diff options
| author | Po Lu | 2022-12-31 18:04:18 +0800 |
|---|---|---|
| committer | Po Lu | 2022-12-31 18:04:18 +0800 |
| commit | cfbc8a5dbcd362b69b37b4e6832ae4a31834364c (patch) | |
| tree | ce003d03c4ae98f4e1d02186d78e5ae6e0d36e55 | |
| parent | 785095c416f9bae43d2947849282b814e2c7942e (diff) | |
| download | emacs-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.
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 | |||
| 52 | src/epaths.h | 52 | src/epaths.h |
| 53 | src/emacs-module.h | 53 | src/emacs-module.h |
| 54 | 54 | ||
| 55 | # Built by recursive call to `configure'. | ||
| 56 | *.android | ||
| 57 | |||
| 58 | # Built by `java'. | ||
| 59 | java/install_temp/* | ||
| 60 | java/*.apk* | ||
| 61 | java/*.dex | ||
| 62 | java/org/gnu/emacs/*.class | ||
| 63 | |||
| 55 | # C-level sources built by 'make'. | 64 | # C-level sources built by 'make'. |
| 56 | lib/alloca.h | 65 | lib/alloca.h |
| 57 | lib/assert.h | 66 | lib/assert.h |
| @@ -81,6 +90,14 @@ src/globals.h | |||
| 81 | src/lisp.mk | 90 | src/lisp.mk |
| 82 | src/verbose.mk | 91 | src/verbose.mk |
| 83 | 92 | ||
| 93 | # Stuff built during cross compilation | ||
| 94 | xcompile/lib/* | ||
| 95 | xcompile/src/* | ||
| 96 | xcompile/lib-src/* | ||
| 97 | xcompile/sys/* | ||
| 98 | xcompile/config.status | ||
| 99 | xcompile/*.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 | ||
| 107 | FIND_DELETE = @FIND_DELETE@ | 107 | FIND_DELETE = @FIND_DELETE@ |
| 108 | 108 | ||
| 109 | HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ | ||
| 110 | |||
| 111 | USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@ | 109 | USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@ |
| 112 | 110 | ||
| 111 | HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ | ||
| 113 | HAVE_BE_APP = @HAVE_BE_APP@ | 112 | HAVE_BE_APP = @HAVE_BE_APP@ |
| 114 | |||
| 115 | HAVE_PGTK = @HAVE_PGTK@ | 113 | HAVE_PGTK = @HAVE_PGTK@ |
| 116 | HAVE_GSETTINGS = @HAVE_GSETTINGS@ | 114 | HAVE_GSETTINGS = @HAVE_GSETTINGS@ |
| 117 | 115 | ||
| 116 | ANDROID = @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. |
| 340 | SUBDIR = $(NTDIR) lib lib-src src lisp | 340 | SUBDIR = $(NTDIR) lib lib-src src lisp |
| 341 | 341 | ||
| 342 | ifeq ($(ANDROID),yes) | ||
| 343 | SUBDIR := $(SUBDIR) java | ||
| 344 | endif | ||
| 345 | |||
| 342 | # The subdir makefiles created by config.status. | 346 | # The subdir makefiles created by config.status. |
| 343 | SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@ | 347 | SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@ |
| 344 | SUBDIR_MAKEFILES = $(patsubst ${srcdir}/%,%,${SUBDIR_MAKEFILES_IN:.in=}) | 348 | SUBDIR_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 | |||
| 532 | lib lib-src lisp nt: Makefile | 536 | lib lib-src lisp nt: Makefile |
| 533 | $(MAKE) -C $@ all | 537 | $(MAKE) -C $@ all |
| 534 | 538 | ||
| 539 | java: lisp | ||
| 540 | $(MAKE) -C $@ all | ||
| 541 | |||
| 542 | xcompile: src | ||
| 543 | $(MAKE) -C $@ all | ||
| 544 | |||
| 535 | trampolines: src lisp | 545 | trampolines: src lisp |
| 536 | ifeq ($(HAVE_NATIVE_COMP),yes) | 546 | ifeq ($(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. |
| 563 | MAKEFILE_NAME = Makefile | 573 | MAKEFILE_NAME = Makefile |
| 574 | ifeq ($(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 |
| 579 | else | ||
| 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); | ||
| 587 | endif | ||
| 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 | |||
| 595 | ifneq ($(ANDROID),) | ||
| 572 | config.status: ${srcdir}/configure | 596 | config.status: ${srcdir}/configure |
| 573 | if [ -x ./config.status ]; then \ | 597 | $(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS) |
| 598 | else | ||
| 599 | config.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 |
| 605 | endif | ||
| 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. |
| 1002 | clean_dirs = $(mostlyclean_dirs) nextstep admin/charsets admin/unidata | 1030 | clean_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 | |||
| 138 | echo "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. | |||
| 26 | AC_INIT([GNU Emacs], [30.0.50], [bug-gnu-emacs@gnu.org], [], | 26 | AC_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 | ||
| 29 | if 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 \ | ||
| 33 | for Android.]) | ||
| 34 | # Set CC to ANDROID_CC, and CXX to ANDROID_CXX. | ||
| 35 | CC=$ANDROID_CC | ||
| 36 | CXX=$ANDROID_CXX | ||
| 37 | fi | ||
| 38 | |||
| 29 | dnl Set emacs_config_options to the options of 'configure', quoted for the shell, | 39 | dnl Set emacs_config_options to the options of 'configure', quoted for the shell, |
| 30 | dnl and then quoted again for a C string. Separate options with spaces. | 40 | dnl and then quoted again for a C string. Separate options with spaces. |
| 31 | dnl Add some environment variables, if they were passed via the environment | 41 | dnl Add some environment variables, if they were passed via the environment |
| @@ -126,7 +136,25 @@ MAKE=$ac_cv_path_MAKE | |||
| 126 | export MAKE | 136 | export MAKE |
| 127 | 137 | ||
| 128 | dnl Canonicalize the configuration name. | 138 | dnl Canonicalize the configuration name. |
| 139 | if 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. | ||
| 149 | Please verify that you specified the correct compiler in the ANDROID_CC | ||
| 150 | and ANDROID_CXX variables when you ran configure.]) | ||
| 151 | ;; | ||
| 152 | esac | ||
| 153 | AC_MSG_RESULT([$host_alias]) | ||
| 154 | fi | ||
| 155 | |||
| 129 | AC_CANONICAL_HOST | 156 | AC_CANONICAL_HOST |
| 157 | AC_CANONICAL_BUILD | ||
| 130 | 158 | ||
| 131 | case $host in | 159 | case $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 | ||
| 238 | dnl ARCH_INDEPENDENT_CONFIG_FILES(FILE...) | ||
| 239 | dnl Like AC_CONFIG_FILES(FILE). However, do not generate this | ||
| 240 | dnl if configure is being called recursively in preparation | ||
| 241 | dnl for cross-compilation. | ||
| 242 | AC_DEFUN([ARCH_INDEPENDENT_CONFIG_FILES], [ | ||
| 243 | AS_IF([test "$XCONFIGURE" != "android"], [AC_CONFIG_FILES([$1])])]) | ||
| 244 | |||
| 210 | dnl OPTION_DEFAULT_OFF(NAME, HELP-STRING) | 245 | dnl OPTION_DEFAULT_OFF(NAME, HELP-STRING) |
| 211 | dnl Create a new --with option that defaults to being disabled. | 246 | dnl Create a new --with option that defaults to being disabled. |
| 212 | dnl NAME is the base name of the option. The shell variable with_NAME | 247 | dnl 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]) | |||
| 498 | OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin]) | 533 | OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin]) |
| 499 | OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input]) | 534 | OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input]) |
| 500 | OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary]) | 535 | OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary]) |
| 536 | OPTION_DEFAULT_OFF([android],[cross-compile Android application package]) | ||
| 501 | 537 | ||
| 502 | AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB], | 538 | AC_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]) |
| 683 | AC_SUBST([BUILD_DETAILS]) | 719 | AC_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 | |||
| 733 | ANDROID= | ||
| 734 | JAVAC= | ||
| 735 | AAPT= | ||
| 736 | JARSIGNER= | ||
| 737 | ZIPALIGN= | ||
| 738 | DX= | ||
| 739 | ANDROID_JAR= | ||
| 740 | ANDROID_ABI= | ||
| 741 | |||
| 742 | # This is a list of Makefiles that have alternative versions for | ||
| 743 | # Android. | ||
| 744 | android_makefiles="lib/Makefile lib/gnulib.mk lib-src/Makefile src/Makefile" | ||
| 745 | |||
| 746 | AC_ARG_VAR([JAVAC], [Java compiler path. Used for Android.]) | ||
| 747 | AC_ARG_VAR([JARSIGNER], [Java package signer path. Used for Android.]) | ||
| 748 | AC_ARG_VAR([SDK_BULD_TOOLS], [Path to the Android SDK build tools.]) | ||
| 749 | |||
| 750 | if 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 | |||
| 755 | along with the path to the SDK build-tools (this is the directory with | ||
| 756 | tools such as aapt, dx, and aidl): | ||
| 757 | |||
| 758 | SDK_BUILD_TOOLS=/path/to/sdk-build-tools | ||
| 759 | |||
| 760 | The 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++]) | ||
| 764 | elif test "$with_android" = "no" || test "$with_android" = ""; then | ||
| 765 | ANDROID=no | ||
| 766 | else | ||
| 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. | ||
| 770 | Please make sure `javac' can be found on your path, or alternatively specify | ||
| 771 | the 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. | ||
| 778 | Please make sure `jarsigner' can be found on your path, or alternatively | ||
| 779 | specify 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 | ||
| 787 | cat << EOF > conftest.java | ||
| 788 | |||
| 789 | import android.app.Activity; | ||
| 790 | import android.os.Bundle; | ||
| 791 | |||
| 792 | class conftest extends Activity | ||
| 793 | { | ||
| 794 | @Override | ||
| 795 | public void | ||
| 796 | onCreate (Bundle savedInstanceState) | ||
| 797 | { | ||
| 798 | super.onCreate (savedInstanceState); | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | EOF | ||
| 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 | ||
| 810 | a 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. | ||
| 818 | Please 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. | ||
| 824 | Please 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. | ||
| 830 | Please 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 | ||
| 838 | for 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 \ | ||
| 864 | binary Emacs is being configured for. Please port this configure script \ | ||
| 865 | to your Android system, or verify that you specified the correct compiler \ | ||
| 866 | in 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-\ | ||
| 879 | configure 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 | ||
| 901 | fi | ||
| 902 | |||
| 903 | AC_SUBST([ANDROID]) | ||
| 904 | AC_SUBST([JAVAC]) | ||
| 905 | AC_SUBST([AAPT]) | ||
| 906 | AC_SUBST([DX]) | ||
| 907 | AC_SUBST([ZIPALIGN]) | ||
| 908 | AC_SUBST([ANDROID_JAR]) | ||
| 909 | AC_SUBST([ANDROID_ABI]) | ||
| 910 | |||
| 911 | if test "$XCONFIGURE" = "android"; then | ||
| 912 | ANDROID=yes | ||
| 913 | |||
| 914 | # Enable cross compiling. | ||
| 915 | cross_compiling=yes | ||
| 916 | fi | ||
| 917 | |||
| 918 | AC_SUBST([XCONFIGURE]) | ||
| 919 | |||
| 920 | if 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 | ||
| 950 | fi | ||
| 951 | |||
| 685 | dnl This used to use changequote, but, apart from 'changequote is evil' | 952 | dnl This used to use changequote, but, apart from 'changequote is evil' |
| 686 | dnl per the autoconf manual, we can speed up autoconf somewhat by quoting | 953 | dnl per the autoconf manual, we can speed up autoconf somewhat by quoting |
| 687 | dnl the great gob of text. Thus it's not processed for possible expansion. | 954 | dnl the great gob of text. Thus it's not processed for possible expansion. |
| @@ -705,6 +972,11 @@ dnl quotation begins | |||
| 705 | opsys='' unported=no | 972 | opsys='' unported=no |
| 706 | case "${canonical}" in | 973 | case "${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 | ||
| 872 | dnl Sets GCC=yes if using gcc. | 1144 | dnl Sets GCC=yes if using gcc. |
| 873 | AC_PROG_CC([gcc cc cl clang "$XCRUN gcc" "$XCRUN clang"]) | 1145 | AC_PROG_CC([gcc cc cl clang "$XCRUN gcc" "$XCRUN clang"]) |
| 1146 | |||
| 874 | if test -n "$XCRUN"; then | 1147 | if 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 |
| 1266 | fi | 1547 | fi |
| 1267 | AC_SUBST([AM_DEFAULT_VERBOSITY]) | 1548 | AC_SUBST([AM_DEFAULT_VERBOSITY]) |
| 1268 | AC_CONFIG_FILES([src/verbose.mk]) | 1549 | ARCH_INDEPENDENT_CONFIG_FILES([src/verbose.mk]) |
| 1269 | 1550 | ||
| 1270 | dnl Some other nice autoconf tests. | 1551 | dnl Some other nice autoconf tests. |
| 1271 | AC_PROG_INSTALL | 1552 | AC_PROG_INSTALL |
| @@ -1762,7 +2043,10 @@ AC_SUBST([SYSTEM_TYPE]) | |||
| 1762 | pre_PKG_CONFIG_CFLAGS=$CFLAGS | 2043 | pre_PKG_CONFIG_CFLAGS=$CFLAGS |
| 1763 | pre_PKG_CONFIG_LIBS=$LIBS | 2044 | pre_PKG_CONFIG_LIBS=$LIBS |
| 1764 | 2045 | ||
| 1765 | PKG_PROG_PKG_CONFIG([0.9.0]) | 2046 | dnl pkg-config does not work when cross-compiling for Android. |
| 2047 | if test "${ANDROID}" != "yes"; then | ||
| 2048 | PKG_PROG_PKG_CONFIG([0.9.0]) | ||
| 2049 | fi | ||
| 1766 | 2050 | ||
| 1767 | dnl EMACS_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4]) | 2051 | dnl EMACS_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4]) |
| 1768 | dnl acts like PKG_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4], | 2052 | dnl 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 | ||
| 1946 | window_system=none | 2230 | window_system=none |
| 1947 | 2231 | ||
| 2232 | ANDROID_OBJ= | ||
| 2233 | ANDROID_LIBS= | ||
| 2234 | ANDROID_CFLAGS= | ||
| 2235 | CM_OBJ="cm.o" | ||
| 2236 | |||
| 2237 | if 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 | ||
| 2245 | with Android support]) | ||
| 2246 | |||
| 2247 | if test "${XCONFIGURE}" != "android"; then | ||
| 2248 | AC_DEFINE([ANDROID_STUBIFY], [1], [Define to 1 if Emacs is being built | ||
| 2249 | for 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 | ||
| 2259 | fi | ||
| 2260 | |||
| 2261 | AC_SUBST(ANDROID) | ||
| 2262 | AC_SUBST(ANDROID_OBJ) | ||
| 2263 | AC_SUBST(ANDROID_LIBS) | ||
| 2264 | AC_SUBST(ANDROID_CFLAGS) | ||
| 2265 | |||
| 1948 | if test "${with_pgtk}" = "yes"; then | 2266 | if test "${with_pgtk}" = "yes"; then |
| 1949 | window_system=pgtk | 2267 | window_system=pgtk |
| 1950 | fi | 2268 | fi |
| 1951 | 2269 | ||
| 1952 | 2270 | if test "${ANDROID}" != "yes"; then | |
| 1953 | AC_PATH_X | 2271 | AC_PATH_X |
| 1954 | if 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 | ||
| 1956 | fi | 2275 | fi |
| 1957 | 2276 | ||
| 1958 | LD_SWITCH_X_SITE_RPATH= | 2277 | LD_SWITCH_X_SITE_RPATH= |
| @@ -2276,7 +2595,6 @@ NTDIR= | |||
| 2276 | LIBS_ECLIENT= | 2595 | LIBS_ECLIENT= |
| 2277 | LIB_WSOCK32= | 2596 | LIB_WSOCK32= |
| 2278 | NTLIB= | 2597 | NTLIB= |
| 2279 | CM_OBJ="cm.o" | ||
| 2280 | XARGS_LIMIT= | 2598 | XARGS_LIMIT= |
| 2281 | if test "${HAVE_W32}" = "yes"; then | 2599 | if 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 | ;; | ||
| 2442 | esac | 2763 | esac |
| 2764 | |||
| 2443 | AC_SUBST([HAVE_PGTK]) | 2765 | AC_SUBST([HAVE_PGTK]) |
| 2444 | 2766 | ||
| 2445 | if test "$window_system" = none && test "X$with_x" != "Xno"; then | 2767 | if test "$window_system" = none && test "X$with_x" != "Xno"; then |
| @@ -2773,7 +3095,6 @@ fail; | |||
| 2773 | fi | 3095 | fi |
| 2774 | fi | 3096 | fi |
| 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. |
| 2778 | HAVE_RSVG=no | 3099 | HAVE_RSVG=no |
| 2779 | if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \ | 3100 | if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \ |
| @@ -4202,7 +4523,7 @@ AC_SUBST([HAVE_MODULES]) | |||
| 4202 | AC_SUBST([MODULES_SUFFIX]) | 4523 | AC_SUBST([MODULES_SUFFIX]) |
| 4203 | AC_SUBST([MODULES_SECONDARY_SUFFIX]) | 4524 | AC_SUBST([MODULES_SECONDARY_SUFFIX]) |
| 4204 | 4525 | ||
| 4205 | AC_CONFIG_FILES([src/emacs-module.h]) | 4526 | ARCH_INDEPENDENT_CONFIG_FILES([src/emacs-module.h]) |
| 4206 | AC_SUBST_FILE([module_env_snippet_25]) | 4527 | AC_SUBST_FILE([module_env_snippet_25]) |
| 4207 | AC_SUBST_FILE([module_env_snippet_26]) | 4528 | AC_SUBST_FILE([module_env_snippet_26]) |
| 4208 | AC_SUBST_FILE([module_env_snippet_27]) | 4529 | AC_SUBST_FILE([module_env_snippet_27]) |
| @@ -5003,6 +5324,40 @@ getpwent endpwent getgrent endgrent \ | |||
| 5003 | renameat2 \ | 5324 | renameat2 \ |
| 5004 | cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \ | 5325 | cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \ |
| 5005 | pthread_set_name_np]) | 5326 | pthread_set_name_np]) |
| 5327 | |||
| 5328 | if 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 | ||
| 5344 | fi | ||
| 5345 | |||
| 5346 | if 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 | ||
| 5359 | fi | ||
| 5360 | |||
| 5006 | LIBS=$OLD_LIBS | 5361 | LIBS=$OLD_LIBS |
| 5007 | 5362 | ||
| 5008 | if test "$ac_cv_func_pthread_setname_np" = "yes"; then | 5363 | if 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. |
| 5110 | AC_CACHE_CHECK([for library containing tputs], [emacs_cv_tputs_lib], | 5465 | AC_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' |
| 5113 | else | 5468 | else |
| 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 | ||
| 6658 | AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D} | 7013 | AS_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 | |||
| 6759 | AC_CONFIG_FILES([Makefile lib/gnulib.mk]) | 7115 | AC_CONFIG_FILES([Makefile lib/gnulib.mk]) |
| 6760 | 7116 | ||
| 6761 | dnl config.status treats $srcdir specially, so I think this is ok... | 7117 | dnl config.status treats $srcdir specially, so I think this is ok... |
| 6762 | AC_CONFIG_FILES([$srcdir/doc/man/emacs.1]) | 7118 | ARCH_INDEPENDENT_CONFIG_FILES([$srcdir/doc/man/emacs.1]) |
| 6763 | 7119 | ||
| 6764 | m4_define([subdir_makefiles], | 7120 | AC_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]) |
| 6766 | SUBDIR_MAKEFILES="subdir_makefiles" | 7122 | ARCH_INDEPENDENT_CONFIG_FILES([doc/emacs/Makefile doc/misc/Makefile |
| 6767 | AC_CONFIG_FILES(subdir_makefiles) | 7123 | doc/lispintro/Makefile doc/lispref/Makefile |
| 7124 | lisp/Makefile leim/Makefile]) | ||
| 7125 | |||
| 7126 | SUBDIR_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 | ||
| 6769 | dnl The test/ directory is missing if './make-dist --no-tests' was used. | 7128 | dnl The test/ directory is missing if './make-dist --no-tests' was used. |
| 6770 | opt_makefile=test/Makefile | 7129 | opt_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]) |
| 6777 | fi | 7136 | fi |
| 6778 | opt_makefile=test/infra/Makefile | 7137 | opt_makefile=test/infra/Makefile |
| 6779 | if test -f "$srcdir/$opt_makefile.in"; then | 7138 | if 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]) |
| 7143 | fi | ||
| 7144 | |||
| 7145 | if test "$ANDROID" = "yes"; then | ||
| 7146 | SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES java/Makefile" | ||
| 6784 | fi | 7147 | fi |
| 6785 | 7148 | ||
| 7149 | if test "$XCOMPILE" = "yes"; then | ||
| 7150 | SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES xcompile/Makefile" | ||
| 7151 | fi | ||
| 6786 | 7152 | ||
| 6787 | dnl The admin/ directory used to be excluded from tarfiles. | 7153 | dnl The admin/ directory used to be excluded from tarfiles. |
| 6788 | if test -d $srcdir/admin; then | 7154 | if 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]) |
| 6793 | fi dnl -d admin | 7159 | fi dnl -d admin |
| 6794 | 7160 | ||
| 6795 | 7161 | ||
| @@ -6800,65 +7166,75 @@ AC_SUBST([SUBDIR_MAKEFILES_IN]) | |||
| 6800 | SMALL_JA_DIC=$with_small_ja_dic | 7166 | SMALL_JA_DIC=$with_small_ja_dic |
| 6801 | AC_SUBST([SMALL_JA_DIC]) | 7167 | AC_SUBST([SMALL_JA_DIC]) |
| 6802 | 7168 | ||
| 6803 | dnl You might wonder (I did) why epaths.h is generated by running make, | 7169 | dnl The following commands are run on the host system when building |
| 6804 | dnl rather than just letting configure generate it from epaths.in. | 7170 | dnl Emacs. |
| 6805 | dnl One reason is that the various paths are not fully expanded (see above); | 7171 | |
| 6806 | dnl e.g., gamedir='${localstatedir}/games/emacs'. | 7172 | if test "$XCONFIGURE" != "android"; then |
| 6807 | dnl 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 |
| 6808 | dnl to run 'make prefix=/some/where/else' and override the values set | 7174 | dnl make, rather than just letting configure generate it from |
| 6809 | dnl 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 |
| 6810 | dnl the use of force in the 'epaths-force' rule in Makefile.in. | 7176 | dnl expanded (see above); e.g., |
| 6811 | AC_CONFIG_COMMANDS([src/epaths.h], [ | 7177 | dnl gamedir='${localstatedir}/games/emacs'. Secondly, the GNU |
| 6812 | if 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 |
| 6814 | elif 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. |
| 6816 | else | 7182 | AC_CONFIG_COMMANDS([src/epaths.h], [ |
| 6817 | ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force | 7183 | if test "${opsys}" = "mingw32"; then |
| 6818 | fi || 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 | |
| 6822 | dnl 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 |
| 6823 | dnl is not yet set, sigh. Or we could use ../$srcdir/src/.gdbinit, | 7189 | fi || AC_MSG_ERROR(['src/epaths.h' could not be made.]) |
| 6824 | dnl or a symlink? | 7190 | ], [GCC="$GCC" CPPFLAGS="$CPPFLAGS" opsys="$opsys" HAVE_NS="$HAVE_NS" |
| 6825 | AC_CONFIG_COMMANDS([src/.gdbinit], [ | 7191 | EN_NS_SELF_CONTAINED="$EN_NS_SELF_CONTAINED"]) |
| 6826 | if 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 |
| 6828 | fi | 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 | ||
| 6831 | dnl Perhaps this would be better named doc-emacs-emacsver.texi? | 7202 | dnl Perhaps this would be better named doc-emacs-emacsver.texi? |
| 6832 | dnl See comments for etc-refcards-emacsver.tex. | 7203 | dnl See comments for etc-refcards-emacsver.tex. |
| 6833 | dnl 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, |
| 6834 | dnl 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. |
| 6835 | AC_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 || \ |
| 6837 | AC_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 | ||
| 6840 | dnl 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, |
| 6841 | dnl then a directory etc/refcards is created in the build directory, | 7212 | dnl then a directory etc/refcards is created in the build directory, |
| 6842 | dnl which is probably harmless, but confusing (in out-of-tree builds). | 7213 | dnl which is probably harmless, but confusing (in out-of-tree builds). |
| 6843 | dnl (If we were to generate etc/refcards/Makefile, this might change.) | 7214 | dnl (If we were to generate etc/refcards/Makefile, this might change.) |
| 6844 | dnl It is really $srcdir/etc/refcards/emacsver.tex that we generate. | 7215 | dnl It is really $srcdir/etc/refcards/emacsver.tex that we generate. |
| 6845 | AC_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 || \ |
| 6847 | AC_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 | ||
| 6850 | if test $AUTO_DEPEND = yes; then | ||
| 6851 | for dir in $AUTODEPEND_PARENTS; do | ||
| 6852 | AS_MKDIR_P([$dir/deps]) | ||
| 6853 | done | ||
| 6854 | fi | ||
| 6855 | if $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 |
| 6860 | fi | 7232 | fi |
| 6861 | 7233 | ||
| 7234 | # Make java/Makefile | ||
| 7235 | ARCH_INDEPENDENT_CONFIG_FILES([java/Makefile]) | ||
| 7236 | ARCH_INDEPENDENT_CONFIG_FILES([xcompile/Makefile]) | ||
| 7237 | |||
| 6862 | AC_OUTPUT | 7238 | AC_OUTPUT |
| 6863 | 7239 | ||
| 6864 | if test ! "$with_mailutils"; then | 7240 | if test ! "$with_mailutils"; then |
| @@ -1094,6 +1094,30 @@ Please refer to the LLDB reference on the web for more information | |||
| 1094 | about LLDB. If you already know GDB, you will also find a mapping | 1094 | about LLDB. If you already know GDB, you will also find a mapping |
| 1095 | from GDB commands to corresponding LLDB commands there. | 1095 | from GDB commands to corresponding LLDB commands there. |
| 1096 | 1096 | ||
| 1097 | ** Debugging Emacs on Android. | ||
| 1098 | |||
| 1099 | Attaching GDB to Emacs running inside the Android application setup | ||
| 1100 | requires a special script found in the java/ directory, and a suitable | ||
| 1101 | GDB server binary to be present on the Android device, which is | ||
| 1102 | present on the free versions of Android. Connecting to the device | ||
| 1103 | also requires the `adb' (Android Debug Bridge) utility, and telling | ||
| 1104 | the Android system to resume the Emacs process after startup requires | ||
| 1105 | the Java debugger (jdb). | ||
| 1106 | |||
| 1107 | If all three of those tools are present, simply run (from the Emacs | ||
| 1108 | source directory): | ||
| 1109 | |||
| 1110 | ../java/debug.sh -- [any extra arguments you wish to pass to gdb] | ||
| 1111 | |||
| 1112 | After which, upon waiting a while, the GDB prompt will show up. | ||
| 1113 | |||
| 1114 | If Emacs crashes and "JNI ERROR" shows up in the Android system log, | ||
| 1115 | then placing a breakpoint on: | ||
| 1116 | |||
| 1117 | break art::JavaVMExt::JniAbort | ||
| 1118 | |||
| 1119 | will let you find the source of the crash. | ||
| 1120 | |||
| 1097 | 1121 | ||
| 1098 | This file is part of GNU Emacs. | 1122 | This 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 | |||
| 20 | top_builddir = @top_builddir@ | ||
| 21 | |||
| 22 | -include ${top_builddir}/src/verbose.mk | ||
| 23 | |||
| 24 | SHELL = @SHELL@ | ||
| 25 | JAVAC = @JAVAC@ | ||
| 26 | AAPT = @AAPT@ | ||
| 27 | DX = @DX@ | ||
| 28 | ZIPALIGN = @ZIPALIGN@ | ||
| 29 | JARSIGNER = @JARSIGNER@ | ||
| 30 | ANDROID_JAR = @ANDROID_JAR@ | ||
| 31 | ANDROID_ABI = @ANDROID_ABI@ | ||
| 32 | |||
| 33 | WARN_JAVAFLAGS = -Xlint:deprecation | ||
| 34 | JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \ | ||
| 35 | $(WARN_JAVAFLAGS) | ||
| 36 | |||
| 37 | SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 | ||
| 38 | |||
| 39 | JAVA_FILES = $(shell find . -type f -name *.java) | ||
| 40 | CLASS_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 | ||
| 58 | all: emacs.apk | ||
| 59 | |||
| 60 | # Binaries to cross-compile. | ||
| 61 | CROSS_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. | ||
| 66 | CROSS_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 | |||
| 77 | emacs.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 | |||
| 127 | classes.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 | |||
| 138 | emacs.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 | |||
| 145 | clean: | ||
| 146 | rm -f emacs.apk emacs.apk-in *.dex *.unaligned *.class | ||
| 147 | rm -rf install-temp | ||
| 148 | find . -name '*.class' -delete | ||
| 149 | |||
| 150 | maintainer-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 @@ | |||
| 1 | This directory holds the Java sources of the port of GNU Emacs to | ||
| 2 | Android-like systems. | ||
| 3 | |||
| 4 | Please keep the Java code indented with tabs and formatted according | ||
| 5 | to the rules for C code in the GNU coding standards. Always use | ||
| 6 | C-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 | |||
| 21 | set -m | ||
| 22 | oldpwd=`pwd` | ||
| 23 | cd `dirname $0` | ||
| 24 | |||
| 25 | devices=`adb devices | grep device | awk -- '/device\y/ { print $1 }' -` | ||
| 26 | device= | ||
| 27 | progname=$0 | ||
| 28 | package=org.gnu.emacs | ||
| 29 | activity=org.gnu.emacs.EmacsActivity | ||
| 30 | gdb_port=5039 | ||
| 31 | jdb_port=64013 | ||
| 32 | jdb=no | ||
| 33 | |||
| 34 | while [ $# -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 | ||
| 77 | done | ||
| 78 | |||
| 79 | if [ -z $devices ]; then | ||
| 80 | echo "No devices are available." | ||
| 81 | exit 1 | ||
| 82 | fi | ||
| 83 | |||
| 84 | if [ -z $device ]; then | ||
| 85 | device=$devices | ||
| 86 | fi | ||
| 87 | |||
| 88 | if [ `wc -w <<< "$devices"` -gt 1 ] && [ -z device ]; then | ||
| 89 | echo "Multiple devices are available. Please pick one using" | ||
| 90 | echo "--device and try again." | ||
| 91 | fi | ||
| 92 | |||
| 93 | echo "Looking for $package on device $device" | ||
| 94 | |||
| 95 | # Find the application data directory | ||
| 96 | app_data_dir=`adb -s $device shell run-as $package sh -c 'pwd 2> /dev/null'` | ||
| 97 | |||
| 98 | if [ -z $app_data_dir ]; then | ||
| 99 | echo "The data directory for the package $package was not found." | ||
| 100 | echo "Is it installed?" | ||
| 101 | fi | ||
| 102 | |||
| 103 | echo "Found application data directory at $app_data_dir..." | ||
| 104 | |||
| 105 | # Find which PIDs are associated with org.gnu.emacs | ||
| 106 | package_uid=`adb -s $device shell run-as $package id -u` | ||
| 107 | |||
| 108 | if [ -z $package_uid ]; then | ||
| 109 | echo "Failed to obtain UID of packages named $package" | ||
| 110 | exit 1 | ||
| 111 | fi | ||
| 112 | |||
| 113 | # First, run ps -u $package_uid -o PID,CMD to fetch the list of | ||
| 114 | # process IDs. | ||
| 115 | package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD` | ||
| 116 | |||
| 117 | # Next, remove lines matching "ps" itself. | ||
| 118 | package_pids=`awk -- '{ | ||
| 119 | if (!match ($0, /(PID|ps)/)) | ||
| 120 | print $1 | ||
| 121 | }' <<< $package_pids` | ||
| 122 | |||
| 123 | # Finally, kill each existing process. | ||
| 124 | for pid in $package_pids; do | ||
| 125 | echo "Killing existing process $pid..." | ||
| 126 | adb -s $device shell run-as $package kill -9 $pid &> /dev/null | ||
| 127 | done | ||
| 128 | |||
| 129 | # Now run the main activity. This must be done as the adb user and | ||
| 130 | # not as the package user. | ||
| 131 | echo "Starting activity $activity and attaching debugger" | ||
| 132 | |||
| 133 | # Exit if the activity could not be started. | ||
| 134 | adb -s $device shell am start -D "$package/$activity" | ||
| 135 | if [ ! $? ]; then | ||
| 136 | exit 1; | ||
| 137 | fi | ||
| 138 | |||
| 139 | # Now look for processes matching the package again. | ||
| 140 | package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD` | ||
| 141 | |||
| 142 | # Next, remove lines matching "ps" itself. | ||
| 143 | package_pids=`awk -- '{ | ||
| 144 | if (!match ($0, /(PID|ps)/)) | ||
| 145 | print $1 | ||
| 146 | }' <<< $package_pids` | ||
| 147 | |||
| 148 | pid=$package_pids | ||
| 149 | num_pids=`wc -w <<< "$package_pids"` | ||
| 150 | |||
| 151 | if [ $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 | ||
| 161 | elif [ -z $package_pids ]; then | ||
| 162 | echo "No processes were found to attach to." | ||
| 163 | exit 1 | ||
| 164 | fi | ||
| 165 | |||
| 166 | # Start JDB to make the wait dialog disappear. | ||
| 167 | echo "Attaching JDB to unblock the application." | ||
| 168 | adb -s $device forward --remove-all | ||
| 169 | adb -s $device forward "tcp:$jdb_port" "jdwp:$pid" | ||
| 170 | |||
| 171 | if [ ! $? ]; 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; | ||
| 175 | fi | ||
| 176 | |||
| 177 | jdb_command="jdb -connect \ | ||
| 178 | com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port" | ||
| 179 | |||
| 180 | if [ $jdb = "yes" ]; then | ||
| 181 | # Just start JDB and then exit | ||
| 182 | $jdb_command | ||
| 183 | exit 1 | ||
| 184 | fi | ||
| 185 | |||
| 186 | exec 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 | |||
| 191 | character= | ||
| 192 | # Next, wait until the prompt is found. | ||
| 193 | while read -n1 -u 4 character; do | ||
| 194 | if [ "$character" = ">" ]; then | ||
| 195 | echo "JDB attached successfully" | ||
| 196 | break; | ||
| 197 | fi | ||
| 198 | done | ||
| 199 | |||
| 200 | # Now start gdbserver on the device asynchronously. | ||
| 201 | |||
| 202 | echo "Attaching gdbserver to $pid on $device..." | ||
| 203 | exec 5<> /tmp/file-descriptor-stamp | ||
| 204 | adb -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. | ||
| 208 | line= | ||
| 209 | while 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 | ||
| 221 | done | ||
| 222 | |||
| 223 | # Send EOF to JDB to make it go away. This will also cause Android to | ||
| 224 | # allow Emacs to continue executing. | ||
| 225 | echo "Making JDB go away..." | ||
| 226 | echo "exit" >&4 | ||
| 227 | read -u 4 line | ||
| 228 | echo "JDB has gone away with $line" | ||
| 229 | |||
| 230 | # Forward the gdb server port here. | ||
| 231 | adb -s $device forward "tcp:$gdb_port" \ | ||
| 232 | "localfilesystem:$app_data_dir/debug.$package_uid.socket" | ||
| 233 | if [ ! $? ]; 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; | ||
| 238 | fi | ||
| 239 | |||
| 240 | # Finally, start gdb with any extra arguments needed. | ||
| 241 | cd "$oldpwd" | ||
| 242 | gdb --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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.IllegalStateException; | ||
| 23 | import java.util.List; | ||
| 24 | import java.util.ArrayList; | ||
| 25 | |||
| 26 | import android.app.Activity; | ||
| 27 | import android.content.Context; | ||
| 28 | import android.content.Intent; | ||
| 29 | import android.os.Bundle; | ||
| 30 | import android.util.Log; | ||
| 31 | import android.widget.FrameLayout; | ||
| 32 | import android.widget.FrameLayout.LayoutParams; | ||
| 33 | |||
| 34 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.app.Application; | ||
| 23 | |||
| 24 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Bitmap; | ||
| 23 | import android.graphics.Canvas; | ||
| 24 | import android.graphics.Paint; | ||
| 25 | import android.graphics.PorterDuff.Mode; | ||
| 26 | import android.graphics.PorterDuffXfermode; | ||
| 27 | import android.graphics.Rect; | ||
| 28 | import android.graphics.Xfermode; | ||
| 29 | |||
| 30 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.Math; | ||
| 23 | |||
| 24 | import android.graphics.Bitmap; | ||
| 25 | import android.graphics.Canvas; | ||
| 26 | import android.graphics.Paint; | ||
| 27 | import android.graphics.PorterDuff.Mode; | ||
| 28 | import android.graphics.PorterDuffXfermode; | ||
| 29 | import android.graphics.Rect; | ||
| 30 | import android.graphics.Xfermode; | ||
| 31 | |||
| 32 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Bitmap; | ||
| 23 | import android.graphics.Canvas; | ||
| 24 | import android.graphics.Paint; | ||
| 25 | import android.graphics.PorterDuff.Mode; | ||
| 26 | import android.graphics.PorterDuffXfermode; | ||
| 27 | import android.graphics.Rect; | ||
| 28 | import android.graphics.Xfermode; | ||
| 29 | |||
| 30 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Rect; | ||
| 23 | import android.graphics.Bitmap; | ||
| 24 | import android.graphics.Canvas; | ||
| 25 | |||
| 26 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.Math; | ||
| 23 | |||
| 24 | import android.graphics.Bitmap; | ||
| 25 | import android.graphics.Canvas; | ||
| 26 | import android.graphics.Paint; | ||
| 27 | import android.graphics.Path; | ||
| 28 | import android.graphics.Point; | ||
| 29 | import android.graphics.PorterDuff.Mode; | ||
| 30 | import android.graphics.PorterDuffXfermode; | ||
| 31 | import android.graphics.Rect; | ||
| 32 | import android.graphics.RectF; | ||
| 33 | import android.graphics.Xfermode; | ||
| 34 | |||
| 35 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Bitmap; | ||
| 23 | import android.graphics.Canvas; | ||
| 24 | import android.graphics.Paint; | ||
| 25 | import android.graphics.PorterDuff.Mode; | ||
| 26 | import android.graphics.PorterDuffXfermode; | ||
| 27 | import android.graphics.Rect; | ||
| 28 | import android.graphics.Xfermode; | ||
| 29 | |||
| 30 | import android.util.Log; | ||
| 31 | |||
| 32 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.util.List; | ||
| 23 | |||
| 24 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Rect; | ||
| 23 | |||
| 24 | /* X like graphics context structures. Keep the enums in synch with | ||
| 25 | androidgui.h! */ | ||
| 26 | |||
| 27 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.util.List; | ||
| 23 | import java.util.ArrayList; | ||
| 24 | import java.lang.Object; | ||
| 25 | import 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 | |||
| 34 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.System; | ||
| 23 | |||
| 24 | import android.content.res.AssetManager; | ||
| 25 | |||
| 26 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.util.LinkedList; | ||
| 23 | import java.util.List; | ||
| 24 | |||
| 25 | import android.graphics.Canvas; | ||
| 26 | import android.graphics.Paint; | ||
| 27 | import android.graphics.Rect; | ||
| 28 | |||
| 29 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Canvas; | ||
| 23 | import android.graphics.Paint; | ||
| 24 | import android.graphics.Rect; | ||
| 25 | |||
| 26 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.IllegalArgumentException; | ||
| 23 | |||
| 24 | import android.graphics.Bitmap; | ||
| 25 | import android.graphics.Canvas; | ||
| 26 | import android.graphics.Rect; | ||
| 27 | |||
| 28 | /* Drawable backed by bitmap. */ | ||
| 29 | |||
| 30 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.io.File; | ||
| 23 | import java.io.IOException; | ||
| 24 | |||
| 25 | import java.util.LinkedList; | ||
| 26 | import java.util.List; | ||
| 27 | |||
| 28 | import android.graphics.Paint; | ||
| 29 | import android.graphics.Rect; | ||
| 30 | import android.graphics.Typeface; | ||
| 31 | |||
| 32 | import android.util.Log; | ||
| 33 | |||
| 34 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.Runnable; | ||
| 23 | import java.io.IOException; | ||
| 24 | import java.util.List; | ||
| 25 | import java.util.ArrayList; | ||
| 26 | |||
| 27 | import android.graphics.Canvas; | ||
| 28 | import android.graphics.Bitmap; | ||
| 29 | import android.graphics.Point; | ||
| 30 | |||
| 31 | import android.annotation.TargetApi; | ||
| 32 | import android.app.Service; | ||
| 33 | import android.content.Context; | ||
| 34 | import android.content.Intent; | ||
| 35 | import android.content.res.AssetManager; | ||
| 36 | import android.os.Build; | ||
| 37 | import android.os.Looper; | ||
| 38 | import android.os.IBinder; | ||
| 39 | import android.os.Handler; | ||
| 40 | import android.util.Log; | ||
| 41 | |||
| 42 | class 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 | |||
| 50 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.view.SurfaceView; | ||
| 23 | import android.view.SurfaceHolder; | ||
| 24 | |||
| 25 | import android.graphics.Canvas; | ||
| 26 | import android.graphics.Rect; | ||
| 27 | |||
| 28 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.Thread; | ||
| 23 | |||
| 24 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.view.View; | ||
| 23 | import android.view.KeyEvent; | ||
| 24 | import android.view.ViewGroup; | ||
| 25 | import android.graphics.Bitmap; | ||
| 26 | import android.graphics.Canvas; | ||
| 27 | import android.graphics.Rect; | ||
| 28 | import android.graphics.Region; | ||
| 29 | import android.graphics.Paint; | ||
| 30 | import android.util.Log; | ||
| 31 | |||
| 32 | import 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 | |||
| 42 | public 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.lang.IllegalStateException; | ||
| 23 | import java.util.ArrayList; | ||
| 24 | import java.util.List; | ||
| 25 | |||
| 26 | import android.graphics.Rect; | ||
| 27 | import android.graphics.Canvas; | ||
| 28 | import android.graphics.Bitmap; | ||
| 29 | import android.graphics.Point; | ||
| 30 | |||
| 31 | import android.view.View; | ||
| 32 | import android.view.ViewGroup; | ||
| 33 | import 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 | |||
| 46 | public 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@ | |||
| 96 | srcdir=@srcdir@ | 96 | srcdir=@srcdir@ |
| 97 | VPATH=@srcdir@ | 97 | VPATH=@srcdir@ |
| 98 | 98 | ||
| 99 | # Cross-compilation setup | ||
| 100 | |||
| 101 | XCONFIGURE=@XCONFIGURE@ | ||
| 102 | |||
| 103 | ifneq ($(XCONFIGURE),) | ||
| 104 | vpath $(srcdir) | ||
| 105 | endif | ||
| 106 | |||
| 99 | # The top-level source directory, also set by configure. | 107 | # The top-level source directory, also set by configure. |
| 100 | top_srcdir=@top_srcdir@ | 108 | top_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 @@ | |||
| 20 | srcdir = @srcdir@ | 20 | srcdir = @srcdir@ |
| 21 | VPATH = @srcdir@ | 21 | VPATH = @srcdir@ |
| 22 | 22 | ||
| 23 | # This is not empty if this is a Makefile that will be copied to | ||
| 24 | # xcompile/lib. | ||
| 25 | XCONFIGURE = @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. | ||
| 30 | ANDROID_CFLAGS = @ANDROID_CFLAGS@ | ||
| 31 | |||
| 32 | ifneq ($(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 | |||
| 41 | vpath _Noreturn.h $(srcdir) | ||
| 42 | vpath acl-internal.h $(srcdir) | ||
| 43 | vpath acl.h $(srcdir) | ||
| 44 | vpath af_alg.h $(srcdir) | ||
| 45 | vpath alloca.in.h $(srcdir) | ||
| 46 | vpath allocator.h $(srcdir) | ||
| 47 | vpath arg-nonnull.h $(srcdir) | ||
| 48 | vpath assert.in.h $(srcdir) | ||
| 49 | vpath attribute.h $(srcdir) | ||
| 50 | vpath binary-io.h $(srcdir) | ||
| 51 | vpath byteswap.in.h $(srcdir) | ||
| 52 | vpath c++defs.h $(srcdir) | ||
| 53 | vpath c-ctype.h $(srcdir) | ||
| 54 | vpath c-strcase.h $(srcdir) | ||
| 55 | vpath careadlinkat.h $(srcdir) | ||
| 56 | vpath cdefs.h $(srcdir) | ||
| 57 | vpath cloexec.h $(srcdir) | ||
| 58 | vpath close-stream.h $(srcdir) | ||
| 59 | vpath count-leading-zeros.h $(srcdir) | ||
| 60 | vpath count-one-bits.h $(srcdir) | ||
| 61 | vpath count-trailing-zeros.h $(srcdir) | ||
| 62 | vpath diffseq.h $(srcdir) | ||
| 63 | vpath dirent.h $(srcdir) | ||
| 64 | vpath dirent.in.h $(srcdir) | ||
| 65 | vpath dynarray.h $(srcdir) | ||
| 66 | vpath eloop-threshold.h $(srcdir) | ||
| 67 | vpath errno.in.h $(srcdir) | ||
| 68 | vpath execinfo.in.h $(srcdir) | ||
| 69 | vpath fcntl.in.h $(srcdir) | ||
| 70 | vpath filemode.h $(srcdir) | ||
| 71 | vpath filename.h $(srcdir) | ||
| 72 | vpath filevercmp.h $(srcdir) | ||
| 73 | vpath fingerprint.h $(srcdir) | ||
| 74 | vpath flexmember.h $(srcdir) | ||
| 75 | vpath fpending.h $(srcdir) | ||
| 76 | vpath fsusage.h $(srcdir) | ||
| 77 | vpath ftoastr.h $(srcdir) | ||
| 78 | vpath getopt-cdefs.in.h $(srcdir) | ||
| 79 | vpath getopt-core.h $(srcdir) | ||
| 80 | vpath getopt-ext.h $(srcdir) | ||
| 81 | vpath getopt-pfx-core.h $(srcdir) | ||
| 82 | vpath getopt-pfx-ext.h $(srcdir) | ||
| 83 | vpath getopt.in.h $(srcdir) | ||
| 84 | vpath getopt_int.h $(srcdir) | ||
| 85 | vpath gettext.h $(srcdir) | ||
| 86 | vpath idx.h $(srcdir) | ||
| 87 | vpath ieee754.in.h $(srcdir) | ||
| 88 | vpath ignore-value.h $(srcdir) | ||
| 89 | vpath intprops-internal.h $(srcdir) | ||
| 90 | vpath intprops.h $(srcdir) | ||
| 91 | vpath inttypes.in.h $(srcdir) | ||
| 92 | vpath libc-config.h $(srcdir) | ||
| 93 | vpath limits.in.h $(srcdir) | ||
| 94 | vpath malloc/dynarray.h $(srcdir) | ||
| 95 | vpath malloc/scratch_buffer.h $(srcdir) | ||
| 96 | vpath md5.h $(srcdir) | ||
| 97 | vpath min-max.h $(srcdir) | ||
| 98 | vpath mini-gmp.h $(srcdir) | ||
| 99 | vpath minmax.h $(srcdir) | ||
| 100 | vpath mktime-internal.h $(srcdir) | ||
| 101 | vpath nproc.h $(srcdir) | ||
| 102 | vpath openat-priv.h $(srcdir) | ||
| 103 | vpath openat.h $(srcdir) | ||
| 104 | vpath pathmax.h $(srcdir) | ||
| 105 | vpath regex.h $(srcdir) | ||
| 106 | vpath regex_internal.h $(srcdir) | ||
| 107 | vpath root-uid.h $(srcdir) | ||
| 108 | vpath save-cwd.h $(srcdir) | ||
| 109 | vpath scratch_buffer.h $(srcdir) | ||
| 110 | vpath sha1.h $(srcdir) | ||
| 111 | vpath sha256.h $(srcdir) | ||
| 112 | vpath sha512.h $(srcdir) | ||
| 113 | vpath sig2str.h $(srcdir) | ||
| 114 | vpath signal.in.h $(srcdir) | ||
| 115 | vpath stat-time.h $(srcdir) | ||
| 116 | vpath stdalign.in.h $(srcdir) | ||
| 117 | vpath stdckdint.in.h $(srcdir) | ||
| 118 | vpath stddef.in.h $(srcdir) | ||
| 119 | vpath stdint.in.h $(srcdir) | ||
| 120 | vpath stdio-impl.h $(srcdir) | ||
| 121 | vpath stdio.h $(srcdir) | ||
| 122 | vpath stdio.in.h $(srcdir) | ||
| 123 | vpath stdlib.in.h $(srcdir) | ||
| 124 | vpath str-two-way.h $(srcdir) | ||
| 125 | vpath strftime.h $(srcdir) | ||
| 126 | vpath string.in.h $(srcdir) | ||
| 127 | vpath sys_random.in.h $(srcdir) | ||
| 128 | vpath sys_select.in.h $(srcdir) | ||
| 129 | vpath sys_stat.in.h $(srcdir) | ||
| 130 | vpath sys_time.in.h $(srcdir) | ||
| 131 | vpath sys_types.in.h $(srcdir) | ||
| 132 | vpath tempname.h $(srcdir) | ||
| 133 | vpath time-internal.h $(srcdir) | ||
| 134 | vpath time.in.h $(srcdir) | ||
| 135 | vpath timespec.h $(srcdir) | ||
| 136 | vpath u64.h $(srcdir) | ||
| 137 | vpath unistd.in.h $(srcdir) | ||
| 138 | vpath unlocked-io.h $(srcdir) | ||
| 139 | vpath utimens.h $(srcdir) | ||
| 140 | vpath verify.h $(srcdir) | ||
| 141 | vpath vla.h $(srcdir) | ||
| 142 | vpath warn-on-use.h $(srcdir) | ||
| 143 | vpath xalloc-oversized.h $(srcdir) | ||
| 144 | vpath %.c $(srcdir) | ||
| 145 | endif | ||
| 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. |
| 25 | abs_top_srcdir = @abs_top_srcdir@ | 149 | abs_top_srcdir = @abs_top_srcdir@ |
| @@ -33,11 +157,11 @@ all: | |||
| 33 | 157 | ||
| 34 | HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ | 158 | HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ |
| 35 | 159 | ||
| 36 | ALL_CFLAGS= \ | 160 | ALL_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 | ||
| 42 | ifeq ($(HAVE_NATIVE_COMP),yes) | 166 | ifeq ($(HAVE_NATIVE_COMP),yes) |
| 43 | ALL_CFLAGS += -DGL_COMPILE_CRYPTO_STREAM | 167 | ALL_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 |
| 53 | endif | 177 | endif |
| 54 | 178 | ||
| 179 | ifeq ($(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. | ||
| 182 | ALL_CFLAGS += -I$(top_srcdir)/xcompile -I. | ||
| 183 | endif | ||
| 184 | |||
| 55 | DEPDIR = deps | 185 | DEPDIR = deps |
| 56 | ifeq ($(AUTO_DEPEND),yes) | 186 | ifeq ($(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 = |
| 61 | endif | 191 | endif |
| 62 | 192 | ||
| 193 | # This piece of code interferes with cross compilation | ||
| 194 | ifeq ($(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 $@) |
| 66 | Makefile: ../config.status $(srcdir)/Makefile.in | 198 | Makefile: ../config.status $(srcdir)/Makefile.in |
| 67 | $(MAKE) -C .. lib/$@ | 199 | $(MAKE) -C .. lib/$@ |
| 200 | endif | ||
| 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 @@ | |||
| 33 | size_t | 33 | size_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> |
| 22 | typedef int dummy; | 22 | typedef 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 | |||
| 2137 | that use a window system such as X, and false for text-only terminals. | 2137 | that use a window system such as X, and false for text-only terminals. |
| 2138 | DISPLAY can be a display name, a frame, or nil (meaning the selected | 2138 | DISPLAY can be a display name, a frame, or nil (meaning the selected |
| 2139 | frame's display)." | 2139 | frame'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). | |||
| 2202 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2203 | If 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 | |||
| 2280 | refers to the height in millimeters for all physical monitors | 2281 | refers to the height in millimeters for all physical monitors |
| 2281 | associated with DISPLAY. To get information for each physical | 2282 | associated with DISPLAY. To get information for each physical |
| 2282 | monitor, use `display-monitor-attributes-list'." | 2283 | monitor, 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 | |||
| 2301 | refers to the width in millimeters for all physical monitors | 2302 | refers to the width in millimeters for all physical monitors |
| 2302 | associated with DISPLAY. To get information for each physical | 2303 | associated with DISPLAY. To get information for each physical |
| 2303 | monitor, use `display-monitor-attributes-list'." | 2304 | monitor, 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. | |||
| 2319 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2320 | If 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. | |||
| 2332 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2333 | If 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. | |||
| 2345 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2346 | If 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. | |||
| 2360 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2361 | If 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. | |||
| 2377 | If DISPLAY is omitted or nil, it defaults to the selected frame's display." | 2378 | If 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'. |
| 437 | On a graphical display, try using the same monitor as the current | 439 | On 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. | ||
| 49 | DISPLAY 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. |
| 34 | abs_top_srcdir=@abs_top_srcdir@ | 34 | abs_top_srcdir=@abs_top_srcdir@ |
| 35 | VPATH = $(srcdir) | 35 | VPATH = $(srcdir) |
| 36 | |||
| 37 | # This is not empty if this is a Makefile that will be copied to | ||
| 38 | # xcompile/src. | ||
| 39 | XCONFIGURE = @XCONFIGURE@ | ||
| 40 | |||
| 41 | ifneq ($(XCONFIGURE),) | ||
| 42 | vpath %.c := $(srcdir) | ||
| 43 | vpath %.h := $(srcdir) | ||
| 44 | endif | ||
| 45 | |||
| 36 | CC = @CC@ | 46 | CC = @CC@ |
| 37 | CXX = @CXX@ | 47 | CXX = @CXX@ |
| 38 | CFLAGS = @CFLAGS@ | 48 | CFLAGS = @CFLAGS@ |
| @@ -48,6 +58,7 @@ LIBOBJS = @LIBOBJS@ | |||
| 48 | 58 | ||
| 49 | lispsource = $(top_srcdir)/lisp | 59 | lispsource = $(top_srcdir)/lisp |
| 50 | lib = ../lib | 60 | lib = ../lib |
| 61 | hostlib = $(top_builddir)/lib | ||
| 51 | libsrc = ../lib-src | 62 | libsrc = ../lib-src |
| 52 | etc = ../etc | 63 | etc = ../etc |
| 53 | oldXMenudir = ../oldXMenu | 64 | oldXMenudir = ../oldXMenu |
| @@ -326,7 +337,7 @@ W32_RES_LINK=@W32_RES_LINK@ | |||
| 326 | ## if HAVE_HARFBUZZ, hbfont.o is added regardless of the rest | 337 | ## if HAVE_HARFBUZZ, hbfont.o is added regardless of the rest |
| 327 | FONT_OBJ=@FONT_OBJ@ | 338 | FONT_OBJ=@FONT_OBJ@ |
| 328 | 339 | ||
| 329 | ## Empty for MinGW, cm.o for the rest. | 340 | ## Empty for MinGW and Android, cm.o for the rest. |
| 330 | CM_OBJ=@CM_OBJ@ | 341 | CM_OBJ=@CM_OBJ@ |
| 331 | 342 | ||
| 332 | LIBGPM = @LIBGPM@ | 343 | LIBGPM = @LIBGPM@ |
| @@ -370,6 +381,10 @@ HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@ | |||
| 370 | HAIKU_LIBS = @HAIKU_LIBS@ | 381 | HAIKU_LIBS = @HAIKU_LIBS@ |
| 371 | HAIKU_CFLAGS = @HAIKU_CFLAGS@ | 382 | HAIKU_CFLAGS = @HAIKU_CFLAGS@ |
| 372 | 383 | ||
| 384 | ANDROID_OBJ = @ANDROID_OBJ@ | ||
| 385 | ANDROID_LIBS = @ANDROID_LIBS@ | ||
| 386 | ANDROID_CFLAGS = @ANDROID_CFLAGS@ | ||
| 387 | |||
| 373 | DUMPING=@DUMPING@ | 388 | DUMPING=@DUMPING@ |
| 374 | CHECK_STRUCTS = @CHECK_STRUCTS@ | 389 | CHECK_STRUCTS = @CHECK_STRUCTS@ |
| 375 | HAVE_PDUMPER = @HAVE_PDUMPER@ | 390 | HAVE_PDUMPER = @HAVE_PDUMPER@ |
| @@ -411,7 +426,8 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ | |||
| 411 | $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ | 426 | $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ |
| 412 | $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ | 427 | $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ |
| 413 | $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ | 428 | $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ |
| 414 | $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) | 429 | $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) \ |
| 430 | $(ANDROID_CFLAGS) | ||
| 415 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) | 431 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) |
| 416 | ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ | 432 | ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ |
| 417 | $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ | 433 | $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ |
| @@ -449,7 +465,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ | |||
| 449 | $(if $(HYBRID_MALLOC),sheap.o) \ | 465 | $(if $(HYBRID_MALLOC),sheap.o) \ |
| 450 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ | 466 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ |
| 451 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ | 467 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ |
| 452 | $(HAIKU_OBJ) $(PGTK_OBJ) | 468 | $(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ) |
| 453 | doc_obj = $(base_obj) $(NS_OBJC_OBJ) | 469 | doc_obj = $(base_obj) $(NS_OBJC_OBJ) |
| 454 | obj = $(doc_obj) $(HAIKU_CXX_OBJ) | 470 | obj = $(doc_obj) $(HAIKU_CXX_OBJ) |
| 455 | 471 | ||
| @@ -466,7 +482,8 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \ | |||
| 466 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ | 482 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ |
| 467 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ | 483 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ |
| 468 | xsettings.o xgselect.o termcap.o hbfont.o \ | 484 | xsettings.o xgselect.o termcap.o hbfont.o \ |
| 469 | haikuterm.o haikufns.o haikumenu.o haikufont.o | 485 | haikuterm.o haikufns.o haikumenu.o haikufont.o androidterm.o androidfns.o \ |
| 486 | androidfont.o | ||
| 470 | 487 | ||
| 471 | ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. | 488 | ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. |
| 472 | GMALLOC_OBJ=@GMALLOC_OBJ@ | 489 | GMALLOC_OBJ=@GMALLOC_OBJ@ |
| @@ -569,7 +586,8 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE | |||
| 569 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ | 586 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ |
| 570 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ | 587 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ |
| 571 | $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) $(HAIKU_LIBS) \ | 588 | $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) $(HAIKU_LIBS) \ |
| 572 | $(TREE_SITTER_LIBS) $(SQLITE3_LIBS) $(XCOMPOSITE_LIBS) $(XSHAPE_LIBS) | 589 | $(TREE_SITTER_LIBS) $(SQLITE3_LIBS) $(XCOMPOSITE_LIBS) $(XSHAPE_LIBS) \ |
| 590 | $(ANDROID_LIBS) | ||
| 573 | 591 | ||
| 574 | ## FORCE it so that admin/unidata can decide whether this file is | 592 | ## FORCE it so that admin/unidata can decide whether this file is |
| 575 | ## up-to-date. Although since charprop depends on bootstrap-emacs, | 593 | ## up-to-date. Although since charprop depends on bootstrap-emacs, |
| @@ -658,7 +676,7 @@ $(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) | |||
| 658 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC | 676 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC |
| 659 | 677 | ||
| 660 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ | 678 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ |
| 661 | $(lib)/libgnu.a | 679 | $(hostlib)/libgnu.a |
| 662 | $(MAKE) -C $(dir $@) $(notdir $@) | 680 | $(MAKE) -C $(dir $@) $(notdir $@) |
| 663 | 681 | ||
| 664 | buildobj.h: Makefile | 682 | buildobj.h: Makefile |
| @@ -719,6 +737,27 @@ ifeq ($(DUMPING),unexec) | |||
| 719 | endif | 737 | endif |
| 720 | endif | 738 | endif |
| 721 | 739 | ||
| 740 | ifeq ($(XCONFIGURE),android) | ||
| 741 | ## The Android package internally links to and communicates with a | ||
| 742 | ## shared library named `libemacs.so' at startup. This is built | ||
| 743 | ## almost the same way temacs is. But it is position independent. It | ||
| 744 | ## is not dumped here. Instead, it dumps itself the first time it | ||
| 745 | ## starts on the user's device. | ||
| 746 | |||
| 747 | libemacs.so: $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ | ||
| 748 | $(MAKE_PDUMPER_FINGERPRINT) | ||
| 749 | $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) \ | ||
| 750 | $(LDFLAGS) -shared $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(LIBES) | ||
| 751 | $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@ | ||
| 752 | |||
| 753 | # There is also a binary named `android-emacs' which simply calls | ||
| 754 | # emacs.so. | ||
| 755 | |||
| 756 | android-emacs: libemacs.so android-emacs.o | ||
| 757 | $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \ | ||
| 758 | -L. "-l:libemacs.so" android-emacs.o | ||
| 759 | endif | ||
| 760 | |||
| 722 | ## The following oldxmenu-related rules are only (possibly) used if | 761 | ## The following oldxmenu-related rules are only (possibly) used if |
| 723 | ## HAVE_X11 && !USE_GTK, but there is no harm in always defining them. | 762 | ## HAVE_X11 && !USE_GTK, but there is no harm in always defining them. |
| 724 | $(lwlibdir)/liblw.a: $(config_h) globals.h lisp.h FORCE | 763 | $(lwlibdir)/liblw.a: $(config_h) globals.h lisp.h FORCE |
| @@ -747,6 +786,7 @@ ns-app: emacs$(EXEEXT) $(pdmp) | |||
| 747 | .PHONY: versionclean | 786 | .PHONY: versionclean |
| 748 | 787 | ||
| 749 | mostlyclean: | 788 | mostlyclean: |
| 789 | rm -f aemacs emacs.so | ||
| 750 | rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o | 790 | rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o |
| 751 | rm -f dmpstruct.h | 791 | rm -f dmpstruct.h |
| 752 | rm -f emacs.pdmp | 792 | rm -f emacs.pdmp |
diff --git a/src/alloc.c b/src/alloc.c index e7edc0595b3..b8d326f4407 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3342,6 +3342,14 @@ cleanup_vector (struct Lisp_Vector *vector) | |||
| 3342 | drv->close_font (font); | 3342 | drv->close_font (font); |
| 3343 | } | 3343 | } |
| 3344 | } | 3344 | } |
| 3345 | |||
| 3346 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 3347 | /* The Android font driver needs the ability to associate extra | ||
| 3348 | information with font entities. */ | ||
| 3349 | if ((vector->header.size & PSEUDOVECTOR_SIZE_MASK) | ||
| 3350 | == FONT_ENTITY_MAX) | ||
| 3351 | android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity)); | ||
| 3352 | #endif | ||
| 3345 | } | 3353 | } |
| 3346 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) | 3354 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) |
| 3347 | finalize_one_thread (PSEUDOVEC_STRUCT (vector, thread_state)); | 3355 | finalize_one_thread (PSEUDOVEC_STRUCT (vector, thread_state)); |
| @@ -6467,6 +6475,10 @@ garbage_collect (void) | |||
| 6467 | mark_xselect (); | 6475 | mark_xselect (); |
| 6468 | #endif | 6476 | #endif |
| 6469 | 6477 | ||
| 6478 | #ifdef HAVE_ANDROID | ||
| 6479 | mark_androidterm (); | ||
| 6480 | #endif | ||
| 6481 | |||
| 6470 | #ifdef HAVE_NS | 6482 | #ifdef HAVE_NS |
| 6471 | mark_nsterm (); | 6483 | mark_nsterm (); |
| 6472 | #endif | 6484 | #endif |
diff --git a/src/android-emacs.c b/src/android-emacs.c new file mode 100644 index 00000000000..d4fa14e39fb --- /dev/null +++ b/src/android-emacs.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include "android.h" | ||
| 22 | |||
| 23 | /* android-emacs is a wrapper around libemacs. It simply calls | ||
| 24 | android_emacs_init with the argv and argc given to it. */ | ||
| 25 | |||
| 26 | int | ||
| 27 | main (int argc, char **argv) | ||
| 28 | { | ||
| 29 | return android_emacs_init (argc, argv); | ||
| 30 | } | ||
diff --git a/src/android.c b/src/android.c new file mode 100644 index 00000000000..dd841cf383a --- /dev/null +++ b/src/android.c | |||
| @@ -0,0 +1,2335 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <fcntl.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | #include <pthread.h> | ||
| 24 | #include <limits.h> | ||
| 25 | #include <signal.h> | ||
| 26 | #include <semaphore.h> | ||
| 27 | |||
| 28 | #include <sys/stat.h> | ||
| 29 | #include <sys/mman.h> | ||
| 30 | |||
| 31 | #include <assert.h> | ||
| 32 | |||
| 33 | #include "android.h" | ||
| 34 | #include "androidgui.h" | ||
| 35 | |||
| 36 | #include "lisp.h" | ||
| 37 | #include "blockinput.h" | ||
| 38 | #include "coding.h" | ||
| 39 | #include "epaths.h" | ||
| 40 | |||
| 41 | /* Whether or not Emacs is running inside the application process and | ||
| 42 | Android windowing should be enabled. */ | ||
| 43 | bool android_init_gui; | ||
| 44 | |||
| 45 | #ifndef ANDROID_STUBIFY | ||
| 46 | |||
| 47 | #include <android/asset_manager.h> | ||
| 48 | #include <android/asset_manager_jni.h> | ||
| 49 | #include <android/log.h> | ||
| 50 | |||
| 51 | #include <linux/ashmem.h> | ||
| 52 | |||
| 53 | #define ANDROID_THROW(env, class, msg) \ | ||
| 54 | ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg)) | ||
| 55 | |||
| 56 | #define ANDROID_MAX_ASSET_FD 65535 | ||
| 57 | |||
| 58 | struct android_fd_table_entry | ||
| 59 | { | ||
| 60 | /* Various flags associated with this table. */ | ||
| 61 | short flags; | ||
| 62 | |||
| 63 | /* The stat buffer associated with this entry. */ | ||
| 64 | struct stat statb; | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum android_fd_table_entry_flags | ||
| 68 | { | ||
| 69 | ANDROID_FD_TABLE_ENTRY_IS_VALID = 1, | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct android_emacs_service | ||
| 73 | { | ||
| 74 | jclass class; | ||
| 75 | jmethodID fill_rectangle; | ||
| 76 | jmethodID fill_polygon; | ||
| 77 | jmethodID draw_rectangle; | ||
| 78 | jmethodID draw_line; | ||
| 79 | jmethodID draw_point; | ||
| 80 | jmethodID copy_area; | ||
| 81 | jmethodID clear_window; | ||
| 82 | jmethodID clear_area; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct android_emacs_pixmap | ||
| 86 | { | ||
| 87 | jclass class; | ||
| 88 | jmethodID constructor; | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct android_graphics_point | ||
| 92 | { | ||
| 93 | jclass class; | ||
| 94 | jmethodID constructor; | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* The asset manager being used. */ | ||
| 98 | static AAssetManager *asset_manager; | ||
| 99 | |||
| 100 | /* Whether or not Emacs has been initialized. */ | ||
| 101 | static int emacs_initialized; | ||
| 102 | |||
| 103 | /* The path used to store site-lisp. */ | ||
| 104 | char *android_site_load_path; | ||
| 105 | |||
| 106 | /* The path used to store native libraries. */ | ||
| 107 | char *android_lib_dir; | ||
| 108 | |||
| 109 | /* The Android application data directory. */ | ||
| 110 | static char *android_files_dir; | ||
| 111 | |||
| 112 | /* Array of structures used to hold asset information corresponding to | ||
| 113 | a file descriptor. This assumes Emacs does not do funny things | ||
| 114 | with dup. It currently does not. */ | ||
| 115 | static struct android_fd_table_entry android_table[ANDROID_MAX_ASSET_FD]; | ||
| 116 | |||
| 117 | /* The Java environment being used for the main thread. */ | ||
| 118 | JNIEnv *android_java_env; | ||
| 119 | |||
| 120 | /* The EmacsGC class. */ | ||
| 121 | static jclass emacs_gc_class; | ||
| 122 | |||
| 123 | /* Various fields. */ | ||
| 124 | static jfieldID emacs_gc_foreground, emacs_gc_background; | ||
| 125 | static jfieldID emacs_gc_function, emacs_gc_clip_rects; | ||
| 126 | static jfieldID emacs_gc_clip_x_origin, emacs_gc_clip_y_origin; | ||
| 127 | static jfieldID emacs_gc_stipple, emacs_gc_clip_mask; | ||
| 128 | static jfieldID emacs_gc_fill_style, emacs_gc_ts_origin_x; | ||
| 129 | static jfieldID emacs_gc_ts_origin_y; | ||
| 130 | |||
| 131 | /* The constructor and one function. */ | ||
| 132 | static jmethodID emacs_gc_constructor, emacs_gc_mark_dirty; | ||
| 133 | |||
| 134 | /* The Rect class. */ | ||
| 135 | static jclass android_rect_class; | ||
| 136 | |||
| 137 | /* Its constructor. */ | ||
| 138 | static jmethodID android_rect_constructor; | ||
| 139 | |||
| 140 | /* The EmacsService object. */ | ||
| 141 | static jobject emacs_service; | ||
| 142 | |||
| 143 | /* Various methods associated with the EmacsService. */ | ||
| 144 | static struct android_emacs_service service_class; | ||
| 145 | |||
| 146 | /* Various methods associated with the EmacsPixmap class. */ | ||
| 147 | static struct android_emacs_pixmap pixmap_class; | ||
| 148 | |||
| 149 | /* Various methods associated with the Point class. */ | ||
| 150 | static struct android_graphics_point point_class; | ||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | /* Event handling functions. Events are stored on a (circular) queue | ||
| 155 | that is read synchronously. The Android port replaces pselect with | ||
| 156 | a function android_select, which runs pselect in a separate thread, | ||
| 157 | but more importantly also waits for events to be available on the | ||
| 158 | android event queue. */ | ||
| 159 | |||
| 160 | struct android_event_container | ||
| 161 | { | ||
| 162 | /* The next and last events in this queue. */ | ||
| 163 | struct android_event_container *volatile next, *last; | ||
| 164 | |||
| 165 | /* The event itself. */ | ||
| 166 | union android_event event; | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct android_event_queue | ||
| 170 | { | ||
| 171 | /* Mutex protecting the event queue. */ | ||
| 172 | pthread_mutex_t mutex; | ||
| 173 | |||
| 174 | /* Mutex protecting the select data. */ | ||
| 175 | pthread_mutex_t select_mutex; | ||
| 176 | |||
| 177 | /* The thread used to run select. */ | ||
| 178 | pthread_t select_thread; | ||
| 179 | |||
| 180 | /* Condition variable for the writing side. */ | ||
| 181 | pthread_cond_t write_var; | ||
| 182 | |||
| 183 | /* Condition variables for the reading side. */ | ||
| 184 | pthread_cond_t read_var; | ||
| 185 | |||
| 186 | /* The number of events in the queue. If this is greater than 1024, | ||
| 187 | writing will block. */ | ||
| 188 | volatile int num_events; | ||
| 189 | |||
| 190 | /* Circular queue of events. */ | ||
| 191 | struct android_event_container events; | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* Arguments to pselect used by the select thread. */ | ||
| 195 | static volatile int android_pselect_nfds; | ||
| 196 | static fd_set *volatile android_pselect_readfds; | ||
| 197 | static fd_set *volatile android_pselect_writefds; | ||
| 198 | static fd_set *volatile android_pselect_exceptfds; | ||
| 199 | static struct timespec *volatile android_pselect_timeout; | ||
| 200 | static const sigset_t *volatile android_pselect_sigset; | ||
| 201 | |||
| 202 | /* Value of pselect. */ | ||
| 203 | static int android_pselect_rc; | ||
| 204 | |||
| 205 | /* Whether or not pselect finished. */ | ||
| 206 | static volatile bool android_pselect_completed; | ||
| 207 | |||
| 208 | /* The global event queue. */ | ||
| 209 | static struct android_event_queue event_queue; | ||
| 210 | |||
| 211 | /* Semaphore used to signal select completion. */ | ||
| 212 | static sem_t android_pselect_sem; | ||
| 213 | |||
| 214 | static void * | ||
| 215 | android_run_select_thread (void *data) | ||
| 216 | { | ||
| 217 | sigset_t signals; | ||
| 218 | int sig, rc; | ||
| 219 | |||
| 220 | sigfillset (&signals); | ||
| 221 | |||
| 222 | if (pthread_sigmask (SIG_BLOCK, &signals, NULL)) | ||
| 223 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 224 | "pthread_sigmask: %s", | ||
| 225 | strerror (errno)); | ||
| 226 | |||
| 227 | sigemptyset (&signals); | ||
| 228 | sigaddset (&signals, SIGUSR1); | ||
| 229 | |||
| 230 | if (pthread_sigmask (SIG_UNBLOCK, &signals, NULL)) | ||
| 231 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 232 | "pthread_sigmask: %s", | ||
| 233 | strerror (errno)); | ||
| 234 | |||
| 235 | sigemptyset (&signals); | ||
| 236 | sigaddset (&signals, SIGUSR2); | ||
| 237 | |||
| 238 | while (true) | ||
| 239 | { | ||
| 240 | /* Keep waiting for SIGUSR2, ignoring EINTR in the meantime. */ | ||
| 241 | |||
| 242 | while (sigwait (&signals, &sig)) | ||
| 243 | /* Spin. */; | ||
| 244 | |||
| 245 | /* Get the select lock and call pselect. */ | ||
| 246 | pthread_mutex_lock (&event_queue.select_mutex); | ||
| 247 | rc = pselect (android_pselect_nfds, | ||
| 248 | android_pselect_readfds, | ||
| 249 | android_pselect_writefds, | ||
| 250 | android_pselect_exceptfds, | ||
| 251 | android_pselect_timeout, | ||
| 252 | android_pselect_sigset); | ||
| 253 | android_pselect_rc = rc; | ||
| 254 | pthread_mutex_unlock (&event_queue.select_mutex); | ||
| 255 | |||
| 256 | /* Signal the Emacs thread that pselect is done. If read_var | ||
| 257 | was signaled by android_write_event, event_queue.mutex could | ||
| 258 | still be locked, so this must come before. */ | ||
| 259 | sem_post (&android_pselect_sem); | ||
| 260 | |||
| 261 | pthread_mutex_lock (&event_queue.mutex); | ||
| 262 | android_pselect_completed = true; | ||
| 263 | pthread_cond_signal (&event_queue.read_var); | ||
| 264 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | static void | ||
| 269 | android_handle_sigusr1 (int sig, siginfo_t *siginfo, void *arg) | ||
| 270 | { | ||
| 271 | /* Nothing to do here, this signal handler is only installed to make | ||
| 272 | sure the disposition of SIGUSR1 is enough. */ | ||
| 273 | } | ||
| 274 | |||
| 275 | /* Set up the global event queue by initializing the mutex and two | ||
| 276 | condition variables, and the linked list of events. This must be | ||
| 277 | called before starting the Emacs thread. Also, initialize the | ||
| 278 | thread used to run pselect. | ||
| 279 | |||
| 280 | These functions must also use the C library malloc and free, | ||
| 281 | because xmalloc is not thread safe. */ | ||
| 282 | |||
| 283 | static void | ||
| 284 | android_init_events (void) | ||
| 285 | { | ||
| 286 | struct sigaction sa; | ||
| 287 | |||
| 288 | if (pthread_mutex_init (&event_queue.mutex, NULL)) | ||
| 289 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 290 | "pthread_mutex_init: %s", | ||
| 291 | strerror (errno)); | ||
| 292 | |||
| 293 | if (pthread_mutex_init (&event_queue.select_mutex, NULL)) | ||
| 294 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 295 | "pthread_mutex_init: %s", | ||
| 296 | strerror (errno)); | ||
| 297 | |||
| 298 | if (pthread_cond_init (&event_queue.write_var, NULL)) | ||
| 299 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 300 | "pthread_cond_init: %s", | ||
| 301 | strerror (errno)); | ||
| 302 | |||
| 303 | if (pthread_cond_init (&event_queue.read_var, NULL)) | ||
| 304 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 305 | "pthread_cond_init: %s", | ||
| 306 | strerror (errno)); | ||
| 307 | |||
| 308 | sem_init (&android_pselect_sem, 0, 0); | ||
| 309 | |||
| 310 | event_queue.events.next = &event_queue.events; | ||
| 311 | event_queue.events.last = &event_queue.events; | ||
| 312 | |||
| 313 | /* Before starting the select thread, make sure the disposition for | ||
| 314 | SIGUSR1 is correct. */ | ||
| 315 | sigfillset (&sa.sa_mask); | ||
| 316 | sa.sa_sigaction = android_handle_sigusr1; | ||
| 317 | sa.sa_flags = SA_SIGINFO; | ||
| 318 | |||
| 319 | if (sigaction (SIGUSR1, &sa, NULL)) | ||
| 320 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 321 | "sigaction: %s", | ||
| 322 | strerror (errno)); | ||
| 323 | |||
| 324 | /* Start the select thread. */ | ||
| 325 | if (pthread_create (&event_queue.select_thread, NULL, | ||
| 326 | android_run_select_thread, NULL)) | ||
| 327 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 328 | "pthread_create: %s", | ||
| 329 | strerror (errno)); | ||
| 330 | } | ||
| 331 | |||
| 332 | int | ||
| 333 | android_pending (void) | ||
| 334 | { | ||
| 335 | int i; | ||
| 336 | |||
| 337 | pthread_mutex_lock (&event_queue.mutex); | ||
| 338 | i = event_queue.num_events; | ||
| 339 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 340 | |||
| 341 | return i; | ||
| 342 | } | ||
| 343 | |||
| 344 | void | ||
| 345 | android_next_event (union android_event *event_return) | ||
| 346 | { | ||
| 347 | struct android_event_container *container; | ||
| 348 | |||
| 349 | pthread_mutex_lock (&event_queue.mutex); | ||
| 350 | |||
| 351 | /* Wait for events to appear if there are none available to | ||
| 352 | read. */ | ||
| 353 | if (!event_queue.num_events) | ||
| 354 | pthread_cond_wait (&event_queue.read_var, | ||
| 355 | &event_queue.mutex); | ||
| 356 | |||
| 357 | /* Obtain the event from the end of the queue. */ | ||
| 358 | container = event_queue.events.last; | ||
| 359 | eassert (container != &event_queue.events); | ||
| 360 | |||
| 361 | /* Remove the event from the queue and copy it to the caller | ||
| 362 | supplied buffer. */ | ||
| 363 | container->last->next = container->next; | ||
| 364 | container->next->last = container->last; | ||
| 365 | *event_return = container->event; | ||
| 366 | event_queue.num_events--; | ||
| 367 | |||
| 368 | /* Free the container. */ | ||
| 369 | free (container); | ||
| 370 | |||
| 371 | /* Signal that events can now be written. */ | ||
| 372 | pthread_cond_signal (&event_queue.write_var); | ||
| 373 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 374 | } | ||
| 375 | |||
| 376 | static void | ||
| 377 | android_write_event (union android_event *event) | ||
| 378 | { | ||
| 379 | struct android_event_container *container; | ||
| 380 | |||
| 381 | container = malloc (sizeof *container); | ||
| 382 | |||
| 383 | if (!container) | ||
| 384 | return; | ||
| 385 | |||
| 386 | pthread_mutex_lock (&event_queue.mutex); | ||
| 387 | |||
| 388 | /* The event queue is full, wait for events to be read. */ | ||
| 389 | if (event_queue.num_events >= 1024) | ||
| 390 | pthread_cond_wait (&event_queue.write_var, | ||
| 391 | &event_queue.mutex); | ||
| 392 | |||
| 393 | container->next = event_queue.events.next; | ||
| 394 | container->last = &event_queue.events; | ||
| 395 | container->next->last = container; | ||
| 396 | container->last->next = container; | ||
| 397 | container->event = *event; | ||
| 398 | event_queue.num_events++; | ||
| 399 | pthread_cond_signal (&event_queue.read_var); | ||
| 400 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 401 | } | ||
| 402 | |||
| 403 | int | ||
| 404 | android_select (int nfds, fd_set *readfds, fd_set *writefds, | ||
| 405 | fd_set *exceptfds, struct timespec *timeout, | ||
| 406 | const sigset_t *sigset) | ||
| 407 | { | ||
| 408 | int nfds_return; | ||
| 409 | |||
| 410 | pthread_mutex_lock (&event_queue.mutex); | ||
| 411 | |||
| 412 | if (event_queue.num_events) | ||
| 413 | { | ||
| 414 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 415 | return 1; | ||
| 416 | } | ||
| 417 | |||
| 418 | nfds_return = 0; | ||
| 419 | android_pselect_completed = false; | ||
| 420 | |||
| 421 | pthread_mutex_lock (&event_queue.select_mutex); | ||
| 422 | android_pselect_nfds = nfds; | ||
| 423 | android_pselect_readfds = readfds; | ||
| 424 | android_pselect_writefds = writefds; | ||
| 425 | android_pselect_exceptfds = exceptfds; | ||
| 426 | android_pselect_timeout = timeout; | ||
| 427 | android_pselect_sigset = sigset; | ||
| 428 | pthread_mutex_unlock (&event_queue.select_mutex); | ||
| 429 | |||
| 430 | pthread_kill (event_queue.select_thread, SIGUSR2); | ||
| 431 | pthread_cond_wait (&event_queue.read_var, &event_queue.mutex); | ||
| 432 | |||
| 433 | /* Interrupt the select thread now, in case it's still in | ||
| 434 | pselect. */ | ||
| 435 | pthread_kill (event_queue.select_thread, SIGUSR1); | ||
| 436 | |||
| 437 | /* Wait for pselect to return in any case. */ | ||
| 438 | sem_wait (&android_pselect_sem); | ||
| 439 | |||
| 440 | /* If there are now events in the queue, return 1. */ | ||
| 441 | if (event_queue.num_events) | ||
| 442 | nfds_return = 1; | ||
| 443 | |||
| 444 | /* Add the return value of pselect. */ | ||
| 445 | if (android_pselect_rc >= 0) | ||
| 446 | nfds_return += android_pselect_rc; | ||
| 447 | |||
| 448 | if (!nfds_return && android_pselect_rc < 0) | ||
| 449 | nfds_return = android_pselect_rc; | ||
| 450 | |||
| 451 | /* Unlock the event queue mutex. */ | ||
| 452 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 453 | |||
| 454 | return nfds_return; | ||
| 455 | } | ||
| 456 | |||
| 457 | |||
| 458 | |||
| 459 | static void * | ||
| 460 | android_run_debug_thread (void *data) | ||
| 461 | { | ||
| 462 | FILE *file; | ||
| 463 | int fd; | ||
| 464 | char *line; | ||
| 465 | size_t n; | ||
| 466 | |||
| 467 | fd = (int) data; | ||
| 468 | file = fdopen (fd, "r"); | ||
| 469 | |||
| 470 | if (!file) | ||
| 471 | return NULL; | ||
| 472 | |||
| 473 | line = NULL; | ||
| 474 | |||
| 475 | while (true) | ||
| 476 | { | ||
| 477 | if (getline (&line, &n, file) < 0) | ||
| 478 | { | ||
| 479 | free (line); | ||
| 480 | break; | ||
| 481 | } | ||
| 482 | |||
| 483 | __android_log_print (ANDROID_LOG_INFO, __func__, "%s", line); | ||
| 484 | } | ||
| 485 | |||
| 486 | fclose (file); | ||
| 487 | return NULL; | ||
| 488 | } | ||
| 489 | |||
| 490 | |||
| 491 | |||
| 492 | /* Intercept USER_FULL_NAME and return something that makes sense if | ||
| 493 | pw->pw_gecos is NULL. */ | ||
| 494 | |||
| 495 | char * | ||
| 496 | android_user_full_name (struct passwd *pw) | ||
| 497 | { | ||
| 498 | if (!pw->pw_gecos) | ||
| 499 | return (char *) "Android user"; | ||
| 500 | |||
| 501 | return pw->pw_gecos; | ||
| 502 | } | ||
| 503 | |||
| 504 | /* Given a real file name, return the part that describes its asset | ||
| 505 | path, or NULL if it is not an asset. */ | ||
| 506 | |||
| 507 | static const char * | ||
| 508 | android_get_asset_name (const char *filename) | ||
| 509 | { | ||
| 510 | if (!strcmp (filename, "/assets") || !strcmp (filename, "/assets/")) | ||
| 511 | return "/"; | ||
| 512 | |||
| 513 | if (!strncmp (filename, "/assets/", sizeof "/assets/" - 1)) | ||
| 514 | return filename + (sizeof "/assets/" - 1); | ||
| 515 | |||
| 516 | return NULL; | ||
| 517 | } | ||
| 518 | |||
| 519 | /* Like fstat. However, look up the asset corresponding to the file | ||
| 520 | descriptor. If it exists, return the right information. */ | ||
| 521 | |||
| 522 | int | ||
| 523 | android_fstat (int fd, struct stat *statb) | ||
| 524 | { | ||
| 525 | if (fd < ANDROID_MAX_ASSET_FD | ||
| 526 | && (android_table[fd].flags | ||
| 527 | & ANDROID_FD_TABLE_ENTRY_IS_VALID)) | ||
| 528 | { | ||
| 529 | memcpy (statb, &android_table[fd].statb, | ||
| 530 | sizeof *statb); | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | return fstat (fd, statb); | ||
| 535 | } | ||
| 536 | |||
| 537 | /* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an | ||
| 538 | asset, find the information for the corresponding asset. */ | ||
| 539 | |||
| 540 | int | ||
| 541 | android_fstatat (int dirfd, const char *restrict pathname, | ||
| 542 | struct stat *restrict statbuf, int flags) | ||
| 543 | { | ||
| 544 | AAsset *asset_desc; | ||
| 545 | const char *asset; | ||
| 546 | |||
| 547 | if (dirfd == AT_FDCWD | ||
| 548 | && asset_manager | ||
| 549 | && (asset = android_get_asset_name (pathname))) | ||
| 550 | { | ||
| 551 | /* AASSET_MODE_STREAMING is fastest here. */ | ||
| 552 | asset_desc = AAssetManager_open (asset_manager, asset, | ||
| 553 | AASSET_MODE_STREAMING); | ||
| 554 | |||
| 555 | if (!asset_desc) | ||
| 556 | return ENOENT; | ||
| 557 | |||
| 558 | memset (statbuf, 0, sizeof *statbuf); | ||
| 559 | |||
| 560 | /* Fill in the stat buffer. */ | ||
| 561 | statbuf->st_mode = S_IFREG; | ||
| 562 | statbuf->st_size = AAsset_getLength (asset_desc); | ||
| 563 | |||
| 564 | /* Close the asset. */ | ||
| 565 | AAsset_close (asset_desc); | ||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | return fstatat (dirfd, pathname, statbuf, flags); | ||
| 570 | } | ||
| 571 | |||
| 572 | /* Return if NAME is a file that is actually an asset and is | ||
| 573 | accessible, as long as !(amode & W_OK). */ | ||
| 574 | |||
| 575 | bool | ||
| 576 | android_file_access_p (const char *name, int amode) | ||
| 577 | { | ||
| 578 | AAsset *asset; | ||
| 579 | AAssetDir *directory; | ||
| 580 | |||
| 581 | if (!asset_manager) | ||
| 582 | return false; | ||
| 583 | |||
| 584 | if (!(amode & W_OK) && (name = android_get_asset_name (name))) | ||
| 585 | { | ||
| 586 | /* Check if the asset exists by opening it. Suboptimal! */ | ||
| 587 | asset = AAssetManager_open (asset_manager, name, | ||
| 588 | AASSET_MODE_UNKNOWN); | ||
| 589 | |||
| 590 | if (!asset) | ||
| 591 | { | ||
| 592 | /* See if it's a directory also. */ | ||
| 593 | directory = AAssetManager_openDir (asset_manager, name); | ||
| 594 | |||
| 595 | if (directory) | ||
| 596 | { | ||
| 597 | AAssetDir_close (directory); | ||
| 598 | return true; | ||
| 599 | } | ||
| 600 | |||
| 601 | return false; | ||
| 602 | } | ||
| 603 | |||
| 604 | AAsset_close (asset); | ||
| 605 | return true; | ||
| 606 | } | ||
| 607 | |||
| 608 | return false; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* Get a file descriptor backed by a temporary in-memory file for the | ||
| 612 | given asset. */ | ||
| 613 | |||
| 614 | static int | ||
| 615 | android_hack_asset_fd (AAsset *asset) | ||
| 616 | { | ||
| 617 | int fd, rc; | ||
| 618 | unsigned char *mem; | ||
| 619 | size_t size; | ||
| 620 | |||
| 621 | fd = open ("/dev/ashmem", O_RDWR); | ||
| 622 | |||
| 623 | if (fd < 0) | ||
| 624 | return -1; | ||
| 625 | |||
| 626 | /* Assets must be small enough to fit in size_t, if off_t is | ||
| 627 | larger. */ | ||
| 628 | size = AAsset_getLength (asset); | ||
| 629 | |||
| 630 | /* An empty name means the memory area will exist until the file | ||
| 631 | descriptor is closed, because no other process can attach. */ | ||
| 632 | rc = ioctl (fd, ASHMEM_SET_NAME, ""); | ||
| 633 | |||
| 634 | if (rc < 0) | ||
| 635 | { | ||
| 636 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 637 | "ioctl ASHMEM_SET_NAME: %s", | ||
| 638 | strerror (errno)); | ||
| 639 | close (fd); | ||
| 640 | return -1; | ||
| 641 | } | ||
| 642 | |||
| 643 | rc = ioctl (fd, ASHMEM_SET_SIZE, size); | ||
| 644 | |||
| 645 | if (rc < 0) | ||
| 646 | { | ||
| 647 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 648 | "ioctl ASHMEM_SET_SIZE: %s", | ||
| 649 | strerror (errno)); | ||
| 650 | close (fd); | ||
| 651 | return -1; | ||
| 652 | } | ||
| 653 | |||
| 654 | if (!size) | ||
| 655 | return fd; | ||
| 656 | |||
| 657 | /* Now map the resource. */ | ||
| 658 | mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); | ||
| 659 | if (mem == MAP_FAILED) | ||
| 660 | { | ||
| 661 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 662 | "mmap: %s", strerror (errno)); | ||
| 663 | close (fd); | ||
| 664 | return -1; | ||
| 665 | } | ||
| 666 | |||
| 667 | if (AAsset_read (asset, mem, size) != size) | ||
| 668 | { | ||
| 669 | /* Too little was read. Close the file descriptor and report an | ||
| 670 | error. */ | ||
| 671 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 672 | "AAsset_read: %s", strerror (errno)); | ||
| 673 | close (fd); | ||
| 674 | return -1; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* Return anyway even if munmap fails. */ | ||
| 678 | munmap (mem, size); | ||
| 679 | return fd; | ||
| 680 | } | ||
| 681 | |||
| 682 | /* `open' and such are modified even though they exist on Android, | ||
| 683 | because Emacs treats "/assets/" as a special directory that must | ||
| 684 | contain all assets in the application package. */ | ||
| 685 | |||
| 686 | int | ||
| 687 | android_open (const char *filename, int oflag, int mode) | ||
| 688 | { | ||
| 689 | const char *name; | ||
| 690 | AAsset *asset; | ||
| 691 | int fd; | ||
| 692 | off_t out_start, out_length; | ||
| 693 | bool fd_hacked; | ||
| 694 | |||
| 695 | /* This flag means whether or not fd should not be duplicated. */ | ||
| 696 | fd_hacked = false; | ||
| 697 | |||
| 698 | if (asset_manager && (name = android_get_asset_name (filename))) | ||
| 699 | { | ||
| 700 | /* If Emacs is trying to write to the file, return NULL. */ | ||
| 701 | |||
| 702 | if (oflag & O_WRONLY || oflag & O_RDWR) | ||
| 703 | { | ||
| 704 | errno = EROFS; | ||
| 705 | return -1; | ||
| 706 | } | ||
| 707 | |||
| 708 | if (oflag & O_DIRECTORY) | ||
| 709 | { | ||
| 710 | errno = EINVAL; | ||
| 711 | return -1; | ||
| 712 | } | ||
| 713 | |||
| 714 | asset = AAssetManager_open (asset_manager, name, | ||
| 715 | AASSET_MODE_BUFFER); | ||
| 716 | |||
| 717 | if (!asset) | ||
| 718 | { | ||
| 719 | errno = ENOENT; | ||
| 720 | return -1; | ||
| 721 | } | ||
| 722 | |||
| 723 | /* Try to obtain the file descriptor corresponding to this | ||
| 724 | asset. */ | ||
| 725 | fd = AAsset_openFileDescriptor (asset, &out_start, | ||
| 726 | &out_length); | ||
| 727 | |||
| 728 | if (fd == -1) | ||
| 729 | { | ||
| 730 | /* The asset can't be accessed for some reason. Try to | ||
| 731 | create a shared memory file descriptor. */ | ||
| 732 | fd = android_hack_asset_fd (asset); | ||
| 733 | |||
| 734 | if (fd == -1) | ||
| 735 | { | ||
| 736 | AAsset_close (asset); | ||
| 737 | errno = ENXIO; | ||
| 738 | return -1; | ||
| 739 | } | ||
| 740 | |||
| 741 | fd_hacked = true; | ||
| 742 | } | ||
| 743 | |||
| 744 | /* Duplicate the file descriptor and then close the asset, | ||
| 745 | which will close the original file descriptor. */ | ||
| 746 | |||
| 747 | if (!fd_hacked) | ||
| 748 | fd = fcntl (fd, F_DUPFD_CLOEXEC); | ||
| 749 | |||
| 750 | if (fd >= ANDROID_MAX_ASSET_FD || fd < 0) | ||
| 751 | { | ||
| 752 | /* Too bad. You lose. */ | ||
| 753 | errno = ENOMEM; | ||
| 754 | |||
| 755 | if (fd >= 0) | ||
| 756 | close (fd); | ||
| 757 | |||
| 758 | fd = -1; | ||
| 759 | } | ||
| 760 | else | ||
| 761 | { | ||
| 762 | assert (!(android_table[fd].flags | ||
| 763 | & ANDROID_FD_TABLE_ENTRY_IS_VALID)); | ||
| 764 | android_table[fd].flags = ANDROID_FD_TABLE_ENTRY_IS_VALID; | ||
| 765 | memset (&android_table[fd].statb, 0, | ||
| 766 | sizeof android_table[fd].statb); | ||
| 767 | |||
| 768 | /* Fill in some information that will be reported to | ||
| 769 | callers of android_fstat, among others. */ | ||
| 770 | android_table[fd].statb.st_mode = S_IFREG; | ||
| 771 | |||
| 772 | /* Owned by root. */ | ||
| 773 | android_table[fd].statb.st_uid = 0; | ||
| 774 | android_table[fd].statb.st_gid = 0; | ||
| 775 | |||
| 776 | /* Size of the file. */ | ||
| 777 | android_table[fd].statb.st_size | ||
| 778 | = AAsset_getLength (asset); | ||
| 779 | } | ||
| 780 | |||
| 781 | AAsset_close (asset); | ||
| 782 | return fd; | ||
| 783 | } | ||
| 784 | |||
| 785 | return open (filename, oflag, mode); | ||
| 786 | } | ||
| 787 | |||
| 788 | /* Like close. However, remove the file descriptor from the asset | ||
| 789 | table as well. */ | ||
| 790 | |||
| 791 | int | ||
| 792 | android_close (int fd) | ||
| 793 | { | ||
| 794 | if (fd < ANDROID_MAX_ASSET_FD | ||
| 795 | && (android_table[fd].flags & ANDROID_FD_TABLE_ENTRY_IS_VALID)) | ||
| 796 | { | ||
| 797 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 798 | "closing android file descriptor %d", | ||
| 799 | fd); | ||
| 800 | android_table[fd].flags = 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | return close (fd); | ||
| 804 | } | ||
| 805 | |||
| 806 | |||
| 807 | |||
| 808 | /* JNI functions called by Java. */ | ||
| 809 | |||
| 810 | #pragma clang diagnostic push | ||
| 811 | #pragma clang diagnostic ignored "-Wmissing-prototypes" | ||
| 812 | |||
| 813 | JNIEXPORT void JNICALL | ||
| 814 | NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, | ||
| 815 | jobject local_asset_manager, | ||
| 816 | jobject files_dir, jobject libs_dir, | ||
| 817 | jobject emacs_service_object) | ||
| 818 | { | ||
| 819 | int pipefd[2]; | ||
| 820 | pthread_t thread; | ||
| 821 | const char *java_string; | ||
| 822 | |||
| 823 | /* This may be called from multiple threads. setEmacsParams should | ||
| 824 | only ever be called once. */ | ||
| 825 | if (__atomic_fetch_add (&emacs_initialized, -1, __ATOMIC_RELAXED)) | ||
| 826 | { | ||
| 827 | ANDROID_THROW (env, "java/lang/IllegalArgumentException", | ||
| 828 | "Emacs was already initialized!"); | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | |||
| 832 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 833 | "Initializing "PACKAGE_STRING"...\nPlease report bugs to " | ||
| 834 | PACKAGE_BUGREPORT". Thanks.\n"); | ||
| 835 | |||
| 836 | /* Set the asset manager. */ | ||
| 837 | asset_manager = AAssetManager_fromJava (env, local_asset_manager); | ||
| 838 | |||
| 839 | /* Hold a VM reference to the asset manager to prevent the native | ||
| 840 | object from being deleted. */ | ||
| 841 | (*env)->NewGlobalRef (env, local_asset_manager); | ||
| 842 | |||
| 843 | /* Create a pipe and duplicate it to stdout and stderr. Next, make | ||
| 844 | a thread that prints stderr to the system log. */ | ||
| 845 | |||
| 846 | if (pipe2 (pipefd, O_CLOEXEC) < 0) | ||
| 847 | emacs_abort (); | ||
| 848 | |||
| 849 | if (dup2 (pipefd[1], 2) < 0) | ||
| 850 | emacs_abort (); | ||
| 851 | close (pipefd[1]); | ||
| 852 | |||
| 853 | if (pthread_create (&thread, NULL, android_run_debug_thread, | ||
| 854 | (void *) pipefd[0])) | ||
| 855 | emacs_abort (); | ||
| 856 | |||
| 857 | /* Now set the path to the site load directory. */ | ||
| 858 | |||
| 859 | java_string = (*env)->GetStringUTFChars (env, (jstring) files_dir, | ||
| 860 | NULL); | ||
| 861 | |||
| 862 | if (!java_string) | ||
| 863 | emacs_abort (); | ||
| 864 | |||
| 865 | android_files_dir = strdup ((const char *) java_string); | ||
| 866 | |||
| 867 | if (!android_files_dir) | ||
| 868 | emacs_abort (); | ||
| 869 | |||
| 870 | (*env)->ReleaseStringUTFChars (env, (jstring) files_dir, | ||
| 871 | java_string); | ||
| 872 | |||
| 873 | java_string = (*env)->GetStringUTFChars (env, (jstring) libs_dir, | ||
| 874 | NULL); | ||
| 875 | |||
| 876 | if (!java_string) | ||
| 877 | emacs_abort (); | ||
| 878 | |||
| 879 | android_lib_dir = strdup ((const char *) java_string); | ||
| 880 | |||
| 881 | if (!android_files_dir) | ||
| 882 | emacs_abort (); | ||
| 883 | |||
| 884 | (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir, | ||
| 885 | java_string); | ||
| 886 | |||
| 887 | /* Calculate the site-lisp path. */ | ||
| 888 | |||
| 889 | android_site_load_path = malloc (PATH_MAX + 1); | ||
| 890 | |||
| 891 | if (!android_site_load_path) | ||
| 892 | emacs_abort (); | ||
| 893 | |||
| 894 | snprintf (android_site_load_path, PATH_MAX, "%s/site-lisp", | ||
| 895 | android_files_dir); | ||
| 896 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 897 | "Site-lisp directory: %s\n" | ||
| 898 | "Files directory: %s\n" | ||
| 899 | "Native code directory: %s", | ||
| 900 | android_site_load_path, | ||
| 901 | android_files_dir, | ||
| 902 | android_lib_dir); | ||
| 903 | |||
| 904 | /* Make a reference to the Emacs service. */ | ||
| 905 | emacs_service = (*env)->NewGlobalRef (env, emacs_service_object); | ||
| 906 | |||
| 907 | if (!emacs_service) | ||
| 908 | emacs_abort (); | ||
| 909 | |||
| 910 | /* Set up events. */ | ||
| 911 | android_init_events (); | ||
| 912 | |||
| 913 | /* OK, setup is now complete. The caller may start the Emacs thread | ||
| 914 | now. */ | ||
| 915 | } | ||
| 916 | |||
| 917 | /* Initialize service_class, aborting if something goes wrong. */ | ||
| 918 | |||
| 919 | static void | ||
| 920 | android_init_emacs_service (void) | ||
| 921 | { | ||
| 922 | jclass old; | ||
| 923 | |||
| 924 | service_class.class | ||
| 925 | = (*android_java_env)->FindClass (android_java_env, | ||
| 926 | "org/gnu/emacs/EmacsService"); | ||
| 927 | eassert (service_class.class); | ||
| 928 | |||
| 929 | old = service_class.class; | ||
| 930 | service_class.class | ||
| 931 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 932 | (jobject) old); | ||
| 933 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 934 | |||
| 935 | if (!service_class.class) | ||
| 936 | emacs_abort (); | ||
| 937 | |||
| 938 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 939 | service_class.c_name \ | ||
| 940 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 941 | service_class.class, \ | ||
| 942 | name, signature); \ | ||
| 943 | assert (service_class.c_name); | ||
| 944 | |||
| 945 | FIND_METHOD (fill_rectangle, "fillRectangle", | ||
| 946 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 947 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 948 | FIND_METHOD (fill_polygon, "fillPolygon", | ||
| 949 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 950 | "Lorg/gnu/emacs/EmacsGC;" | ||
| 951 | "[Landroid/graphics/Point;)V"); | ||
| 952 | FIND_METHOD (draw_rectangle, "drawRectangle", | ||
| 953 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 954 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 955 | FIND_METHOD (draw_line, "drawLine", | ||
| 956 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 957 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 958 | FIND_METHOD (draw_point, "drawPoint", | ||
| 959 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 960 | "Lorg/gnu/emacs/EmacsGC;II)V"); | ||
| 961 | FIND_METHOD (copy_area, "copyArea", | ||
| 962 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 963 | "Lorg/gnu/emacs/EmacsDrawable;" | ||
| 964 | "Lorg/gnu/emacs/EmacsGC;IIIIII)V"); | ||
| 965 | FIND_METHOD (clear_window, "clearWindow", | ||
| 966 | "(Lorg/gnu/emacs/EmacsWindow;)V"); | ||
| 967 | FIND_METHOD (clear_area, "clearArea", | ||
| 968 | "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); | ||
| 969 | |||
| 970 | #undef FIND_METHOD | ||
| 971 | } | ||
| 972 | |||
| 973 | static void | ||
| 974 | android_init_emacs_pixmap (void) | ||
| 975 | { | ||
| 976 | jclass old; | ||
| 977 | |||
| 978 | pixmap_class.class | ||
| 979 | = (*android_java_env)->FindClass (android_java_env, | ||
| 980 | "org/gnu/emacs/EmacsPixmap"); | ||
| 981 | eassert (pixmap_class.class); | ||
| 982 | |||
| 983 | old = pixmap_class.class; | ||
| 984 | pixmap_class.class | ||
| 985 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 986 | (jobject) old); | ||
| 987 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 988 | |||
| 989 | if (!pixmap_class.class) | ||
| 990 | emacs_abort (); | ||
| 991 | |||
| 992 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 993 | pixmap_class.c_name \ | ||
| 994 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 995 | pixmap_class.class, \ | ||
| 996 | name, signature); \ | ||
| 997 | assert (pixmap_class.c_name); | ||
| 998 | |||
| 999 | FIND_METHOD (constructor, "<init>", "(S[IIII)V"); | ||
| 1000 | |||
| 1001 | #undef FIND_METHOD | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static void | ||
| 1005 | android_init_graphics_point (void) | ||
| 1006 | { | ||
| 1007 | jclass old; | ||
| 1008 | |||
| 1009 | point_class.class | ||
| 1010 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1011 | "android/graphics/Point"); | ||
| 1012 | eassert (point_class.class); | ||
| 1013 | |||
| 1014 | old = point_class.class; | ||
| 1015 | point_class.class | ||
| 1016 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1017 | (jobject) old); | ||
| 1018 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1019 | |||
| 1020 | if (!point_class.class) | ||
| 1021 | emacs_abort (); | ||
| 1022 | |||
| 1023 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 1024 | point_class.c_name \ | ||
| 1025 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 1026 | point_class.class, \ | ||
| 1027 | name, signature); \ | ||
| 1028 | assert (point_class.c_name); | ||
| 1029 | |||
| 1030 | FIND_METHOD (constructor, "<init>", "(II)V"); | ||
| 1031 | #undef FIND_METHOD | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | extern JNIEXPORT void JNICALL | ||
| 1035 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) | ||
| 1036 | { | ||
| 1037 | char **c_argv; | ||
| 1038 | jsize nelements, i; | ||
| 1039 | jobject argument; | ||
| 1040 | const char *c_argument; | ||
| 1041 | |||
| 1042 | android_java_env = env; | ||
| 1043 | |||
| 1044 | nelements = (*env)->GetArrayLength (env, argv); | ||
| 1045 | c_argv = alloca (sizeof *c_argv * nelements); | ||
| 1046 | |||
| 1047 | for (i = 0; i < nelements; ++i) | ||
| 1048 | { | ||
| 1049 | argument = (*env)->GetObjectArrayElement (env, argv, i); | ||
| 1050 | c_argument = (*env)->GetStringUTFChars (env, (jstring) argument, | ||
| 1051 | NULL); | ||
| 1052 | |||
| 1053 | if (!c_argument) | ||
| 1054 | emacs_abort (); | ||
| 1055 | |||
| 1056 | /* Note that c_argument is in ``modified UTF-8 encoding'', but | ||
| 1057 | we don't care as NUL bytes are not being specified inside. */ | ||
| 1058 | c_argv[i] = alloca (strlen (c_argument) + 1); | ||
| 1059 | strcpy (c_argv[i], c_argument); | ||
| 1060 | (*env)->ReleaseStringUTFChars (env, (jstring) argument, c_argument); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | android_init_emacs_service (); | ||
| 1064 | android_init_emacs_pixmap (); | ||
| 1065 | android_init_graphics_point (); | ||
| 1066 | |||
| 1067 | /* Initialize the Android GUI. */ | ||
| 1068 | android_init_gui = true; | ||
| 1069 | android_emacs_init (nelements, c_argv); | ||
| 1070 | /* android_emacs_init should never return. */ | ||
| 1071 | emacs_abort (); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | extern JNIEXPORT void JNICALL | ||
| 1075 | NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object) | ||
| 1076 | { | ||
| 1077 | emacs_abort (); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | extern JNIEXPORT void JNICALL | ||
| 1081 | NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object, | ||
| 1082 | jshort window, jlong time, | ||
| 1083 | jint x, jint y, jint width, | ||
| 1084 | jint height) | ||
| 1085 | { | ||
| 1086 | union android_event event; | ||
| 1087 | |||
| 1088 | event.xconfigure.type = ANDROID_CONFIGURE_NOTIFY; | ||
| 1089 | event.xconfigure.window = window; | ||
| 1090 | event.xconfigure.time = time; | ||
| 1091 | event.xconfigure.x = x; | ||
| 1092 | event.xconfigure.y = y; | ||
| 1093 | event.xconfigure.width = width; | ||
| 1094 | event.xconfigure.height = height; | ||
| 1095 | |||
| 1096 | android_write_event (&event); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | extern JNIEXPORT void JNICALL | ||
| 1100 | NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, | ||
| 1101 | jshort window, jlong time, | ||
| 1102 | jint state, jint keycode) | ||
| 1103 | { | ||
| 1104 | union android_event event; | ||
| 1105 | |||
| 1106 | event.xkey.type = ANDROID_KEY_PRESS; | ||
| 1107 | event.xkey.window = window; | ||
| 1108 | event.xkey.time = time; | ||
| 1109 | event.xkey.state = state; | ||
| 1110 | event.xkey.keycode = keycode; | ||
| 1111 | |||
| 1112 | android_write_event (&event); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | extern JNIEXPORT void JNICALL | ||
| 1116 | NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, | ||
| 1117 | jshort window, jlong time, | ||
| 1118 | jint state, jint keycode) | ||
| 1119 | { | ||
| 1120 | union android_event event; | ||
| 1121 | |||
| 1122 | event.xkey.type = ANDROID_KEY_RELEASE; | ||
| 1123 | event.xkey.window = window; | ||
| 1124 | event.xkey.time = time; | ||
| 1125 | event.xkey.state = state; | ||
| 1126 | event.xkey.keycode = keycode; | ||
| 1127 | |||
| 1128 | android_write_event (&event); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | #pragma clang diagnostic pop | ||
| 1132 | |||
| 1133 | |||
| 1134 | |||
| 1135 | /* Java functions called by C. | ||
| 1136 | |||
| 1137 | Because all C code runs in the native function initEmacs, ALL LOCAL | ||
| 1138 | REFERENCES WILL PERSIST! | ||
| 1139 | |||
| 1140 | This means that every local reference must be explicitly destroyed | ||
| 1141 | with DeleteLocalRef. A helper macro is provided to do this. */ | ||
| 1142 | |||
| 1143 | #define MAX_HANDLE 65535 | ||
| 1144 | |||
| 1145 | enum android_handle_type | ||
| 1146 | { | ||
| 1147 | ANDROID_HANDLE_WINDOW, | ||
| 1148 | ANDROID_HANDLE_GCONTEXT, | ||
| 1149 | ANDROID_HANDLE_PIXMAP, | ||
| 1150 | }; | ||
| 1151 | |||
| 1152 | struct android_handle_entry | ||
| 1153 | { | ||
| 1154 | /* The type. */ | ||
| 1155 | enum android_handle_type type; | ||
| 1156 | |||
| 1157 | /* The handle. */ | ||
| 1158 | jobject handle; | ||
| 1159 | }; | ||
| 1160 | |||
| 1161 | /* Table of handles MAX_HANDLE long. */ | ||
| 1162 | struct android_handle_entry android_handles[USHRT_MAX]; | ||
| 1163 | |||
| 1164 | /* The largest handle ID currently known, but subject to | ||
| 1165 | wraparound. */ | ||
| 1166 | static android_handle max_handle; | ||
| 1167 | |||
| 1168 | /* Allocate a new, unused, handle identifier. If Emacs is out of | ||
| 1169 | identifiers, return 0. */ | ||
| 1170 | |||
| 1171 | static android_handle | ||
| 1172 | android_alloc_id (void) | ||
| 1173 | { | ||
| 1174 | android_handle handle; | ||
| 1175 | |||
| 1176 | /* 0 is never a valid handle ID. */ | ||
| 1177 | if (!max_handle) | ||
| 1178 | max_handle++; | ||
| 1179 | |||
| 1180 | if (android_handles[max_handle].handle) | ||
| 1181 | { | ||
| 1182 | handle = max_handle + 1; | ||
| 1183 | |||
| 1184 | while (max_handle < handle) | ||
| 1185 | { | ||
| 1186 | ++max_handle; | ||
| 1187 | |||
| 1188 | if (!max_handle) | ||
| 1189 | ++max_handle; | ||
| 1190 | |||
| 1191 | if (!android_handles[max_handle].handle) | ||
| 1192 | return 0; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | return 0; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | return max_handle++; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | /* Destroy the specified handle and mark it as free on the Java side | ||
| 1202 | as well. */ | ||
| 1203 | |||
| 1204 | static void | ||
| 1205 | android_destroy_handle (android_handle handle) | ||
| 1206 | { | ||
| 1207 | static jclass old, class; | ||
| 1208 | static jmethodID method; | ||
| 1209 | |||
| 1210 | if (!android_handles[handle].handle) | ||
| 1211 | { | ||
| 1212 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1213 | "Trying to destroy free handle!"); | ||
| 1214 | emacs_abort (); | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | if (!class) | ||
| 1218 | { | ||
| 1219 | class | ||
| 1220 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1221 | "org/gnu/emacs/EmacsHandleObject"); | ||
| 1222 | assert (class != NULL); | ||
| 1223 | |||
| 1224 | method | ||
| 1225 | = (*android_java_env)->GetMethodID (android_java_env, class, | ||
| 1226 | "destroyHandle", "()V"); | ||
| 1227 | assert (method != NULL); | ||
| 1228 | |||
| 1229 | old = class; | ||
| 1230 | class | ||
| 1231 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1232 | (jobject) class); | ||
| 1233 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1234 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1235 | |||
| 1236 | if (!class) | ||
| 1237 | memory_full (0); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1241 | android_handles[handle].handle, | ||
| 1242 | method); | ||
| 1243 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 1244 | android_handles[handle].handle); | ||
| 1245 | android_handles[handle].handle = NULL; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | static jobject | ||
| 1249 | android_resolve_handle (android_handle handle, | ||
| 1250 | enum android_handle_type type) | ||
| 1251 | { | ||
| 1252 | if (!handle) | ||
| 1253 | /* ANDROID_NONE. */ | ||
| 1254 | return NULL; | ||
| 1255 | |||
| 1256 | if (!android_handles[handle].handle) | ||
| 1257 | { | ||
| 1258 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1259 | "Trying to resolve free handle!"); | ||
| 1260 | emacs_abort (); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | if (android_handles[handle].type != type) | ||
| 1264 | { | ||
| 1265 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1266 | "Handle has wrong type!"); | ||
| 1267 | emacs_abort (); | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | return android_handles[handle].handle; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | static jobject | ||
| 1274 | android_resolve_handle2 (android_handle handle, | ||
| 1275 | enum android_handle_type type, | ||
| 1276 | enum android_handle_type type2) | ||
| 1277 | { | ||
| 1278 | if (!handle) | ||
| 1279 | return NULL; | ||
| 1280 | |||
| 1281 | if (!android_handles[handle].handle) | ||
| 1282 | { | ||
| 1283 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1284 | "Trying to resolve free handle!"); | ||
| 1285 | emacs_abort (); | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | if (android_handles[handle].type != type | ||
| 1289 | && android_handles[handle].type != type2) | ||
| 1290 | { | ||
| 1291 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1292 | "Handle has wrong type!"); | ||
| 1293 | emacs_abort (); | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | return android_handles[handle].handle; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | static jmethodID android_lookup_method (const char *, const char *, | ||
| 1300 | const char *); | ||
| 1301 | |||
| 1302 | void | ||
| 1303 | android_change_window_attributes (android_window handle, | ||
| 1304 | enum android_window_value_mask value_mask, | ||
| 1305 | struct android_set_window_attributes *attrs) | ||
| 1306 | { | ||
| 1307 | jmethodID method; | ||
| 1308 | jobject window; | ||
| 1309 | |||
| 1310 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1311 | |||
| 1312 | if (value_mask & ANDROID_CW_BACK_PIXEL) | ||
| 1313 | { | ||
| 1314 | method = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1315 | "changeWindowBackground", "(I)V"); | ||
| 1316 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1317 | window, method, | ||
| 1318 | (jint) attrs->background_pixel); | ||
| 1319 | } | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | /* Create a new window with the given width, height and | ||
| 1323 | attributes. */ | ||
| 1324 | |||
| 1325 | android_window | ||
| 1326 | android_create_window (android_window parent, int x, int y, | ||
| 1327 | int width, int height, | ||
| 1328 | enum android_window_value_mask value_mask, | ||
| 1329 | struct android_set_window_attributes *attrs) | ||
| 1330 | { | ||
| 1331 | static jclass class; | ||
| 1332 | static jmethodID constructor; | ||
| 1333 | jobject object, parent_object, old; | ||
| 1334 | android_window window; | ||
| 1335 | android_handle prev_max_handle; | ||
| 1336 | |||
| 1337 | parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW); | ||
| 1338 | |||
| 1339 | prev_max_handle = max_handle; | ||
| 1340 | window = android_alloc_id (); | ||
| 1341 | |||
| 1342 | if (!window) | ||
| 1343 | error ("Out of window handles!"); | ||
| 1344 | |||
| 1345 | if (!class) | ||
| 1346 | { | ||
| 1347 | class = (*android_java_env)->FindClass (android_java_env, | ||
| 1348 | "org/gnu/emacs/EmacsWindow"); | ||
| 1349 | assert (class != NULL); | ||
| 1350 | |||
| 1351 | constructor | ||
| 1352 | = (*android_java_env)->GetMethodID (android_java_env, class, "<init>", | ||
| 1353 | "(SLorg/gnu/emacs/EmacsWindow;IIII)V"); | ||
| 1354 | assert (constructor != NULL); | ||
| 1355 | |||
| 1356 | old = class; | ||
| 1357 | class = (*android_java_env)->NewGlobalRef (android_java_env, class); | ||
| 1358 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1359 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1360 | |||
| 1361 | if (!class) | ||
| 1362 | memory_full (0); | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | object = (*android_java_env)->NewObject (android_java_env, class, | ||
| 1366 | constructor, (jshort) window, | ||
| 1367 | parent_object, (jint) x, (jint) y, | ||
| 1368 | (jint) width, (jint) height); | ||
| 1369 | if (!object) | ||
| 1370 | { | ||
| 1371 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1372 | |||
| 1373 | max_handle = prev_max_handle; | ||
| 1374 | memory_full (0); | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | android_handles[window].type = ANDROID_HANDLE_WINDOW; | ||
| 1378 | android_handles[window].handle | ||
| 1379 | = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1380 | object); | ||
| 1381 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1382 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 1383 | |||
| 1384 | if (!android_handles[window].handle) | ||
| 1385 | memory_full (0); | ||
| 1386 | |||
| 1387 | android_change_window_attributes (window, value_mask, attrs); | ||
| 1388 | return window; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | void | ||
| 1392 | android_set_window_background (android_window window, unsigned long pixel) | ||
| 1393 | { | ||
| 1394 | struct android_set_window_attributes attrs; | ||
| 1395 | |||
| 1396 | attrs.background_pixel = pixel; | ||
| 1397 | android_change_window_attributes (window, ANDROID_CW_BACK_PIXEL, | ||
| 1398 | &attrs); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | void | ||
| 1402 | android_destroy_window (android_window window) | ||
| 1403 | { | ||
| 1404 | if (android_handles[window].type != ANDROID_HANDLE_WINDOW) | ||
| 1405 | { | ||
| 1406 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1407 | "Trying to destroy something not a window!"); | ||
| 1408 | emacs_abort (); | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | android_destroy_handle (window); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | static void | ||
| 1415 | android_init_android_rect_class (void) | ||
| 1416 | { | ||
| 1417 | jclass old; | ||
| 1418 | |||
| 1419 | if (android_rect_class) | ||
| 1420 | /* Already initialized. */ | ||
| 1421 | return; | ||
| 1422 | |||
| 1423 | android_rect_class | ||
| 1424 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1425 | "android/graphics/Rect"); | ||
| 1426 | assert (android_rect_class); | ||
| 1427 | |||
| 1428 | android_rect_constructor | ||
| 1429 | = (*android_java_env)->GetMethodID (android_java_env, android_rect_class, | ||
| 1430 | "<init>", "(IIII)V"); | ||
| 1431 | assert (emacs_gc_constructor); | ||
| 1432 | |||
| 1433 | old = android_rect_class; | ||
| 1434 | android_rect_class | ||
| 1435 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1436 | (jobject) android_rect_class); | ||
| 1437 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1438 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1439 | |||
| 1440 | if (!android_rect_class) | ||
| 1441 | memory_full (0); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static void | ||
| 1445 | android_init_emacs_gc_class (void) | ||
| 1446 | { | ||
| 1447 | jclass old; | ||
| 1448 | |||
| 1449 | if (emacs_gc_class) | ||
| 1450 | /* Already initialized. */ | ||
| 1451 | return; | ||
| 1452 | |||
| 1453 | emacs_gc_class | ||
| 1454 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1455 | "org/gnu/emacs/EmacsGC"); | ||
| 1456 | assert (emacs_gc_class); | ||
| 1457 | |||
| 1458 | emacs_gc_constructor | ||
| 1459 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1460 | emacs_gc_class, | ||
| 1461 | "<init>", "(S)V"); | ||
| 1462 | assert (emacs_gc_constructor); | ||
| 1463 | |||
| 1464 | emacs_gc_mark_dirty | ||
| 1465 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1466 | emacs_gc_class, | ||
| 1467 | "markDirty", "()V"); | ||
| 1468 | assert (emacs_gc_mark_dirty); | ||
| 1469 | |||
| 1470 | old = emacs_gc_class; | ||
| 1471 | emacs_gc_class | ||
| 1472 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1473 | (jobject) emacs_gc_class); | ||
| 1474 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1475 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1476 | if (!emacs_gc_class) | ||
| 1477 | memory_full (0); | ||
| 1478 | |||
| 1479 | emacs_gc_foreground | ||
| 1480 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1481 | emacs_gc_class, | ||
| 1482 | "foreground", "I"); | ||
| 1483 | emacs_gc_background | ||
| 1484 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1485 | emacs_gc_class, | ||
| 1486 | "background", "I"); | ||
| 1487 | emacs_gc_function | ||
| 1488 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1489 | emacs_gc_class, | ||
| 1490 | "function", "I"); | ||
| 1491 | emacs_gc_clip_rects | ||
| 1492 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1493 | emacs_gc_class, | ||
| 1494 | "clip_rects", | ||
| 1495 | "[Landroid/graphics/Rect;"); | ||
| 1496 | emacs_gc_clip_x_origin | ||
| 1497 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1498 | emacs_gc_class, | ||
| 1499 | "clip_x_origin", "I"); | ||
| 1500 | emacs_gc_clip_y_origin | ||
| 1501 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1502 | emacs_gc_class, | ||
| 1503 | "clip_y_origin", "I"); | ||
| 1504 | emacs_gc_stipple | ||
| 1505 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1506 | emacs_gc_class, | ||
| 1507 | "stipple", | ||
| 1508 | "Lorg/gnu/emacs/EmacsPixmap;"); | ||
| 1509 | emacs_gc_clip_mask | ||
| 1510 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1511 | emacs_gc_class, | ||
| 1512 | "clip_mask", | ||
| 1513 | "Lorg/gnu/emacs/EmacsPixmap;"); | ||
| 1514 | emacs_gc_fill_style | ||
| 1515 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1516 | emacs_gc_class, | ||
| 1517 | "fill_style", "I"); | ||
| 1518 | emacs_gc_ts_origin_x | ||
| 1519 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1520 | emacs_gc_class, | ||
| 1521 | "ts_origin_x", "I"); | ||
| 1522 | emacs_gc_ts_origin_y | ||
| 1523 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1524 | emacs_gc_class, | ||
| 1525 | "ts_origin_y", "I"); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | struct android_gc * | ||
| 1529 | android_create_gc (enum android_gc_value_mask mask, | ||
| 1530 | struct android_gc_values *values) | ||
| 1531 | { | ||
| 1532 | struct android_gc *gc; | ||
| 1533 | android_handle prev_max_handle; | ||
| 1534 | jobject object; | ||
| 1535 | |||
| 1536 | android_init_emacs_gc_class (); | ||
| 1537 | |||
| 1538 | gc = xmalloc (sizeof *gc); | ||
| 1539 | prev_max_handle = max_handle; | ||
| 1540 | gc->gcontext = android_alloc_id (); | ||
| 1541 | |||
| 1542 | if (!gc->gcontext) | ||
| 1543 | { | ||
| 1544 | xfree (gc); | ||
| 1545 | error ("Out of GContext handles!"); | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 1549 | emacs_gc_class, | ||
| 1550 | emacs_gc_constructor, | ||
| 1551 | (jshort) gc->gcontext); | ||
| 1552 | |||
| 1553 | if (!object) | ||
| 1554 | { | ||
| 1555 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1556 | |||
| 1557 | max_handle = prev_max_handle; | ||
| 1558 | memory_full (0); | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | android_handles[gc->gcontext].type = ANDROID_HANDLE_GCONTEXT; | ||
| 1562 | android_handles[gc->gcontext].handle | ||
| 1563 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 1564 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1565 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 1566 | |||
| 1567 | if (!android_handles[gc->gcontext].handle) | ||
| 1568 | memory_full (0); | ||
| 1569 | |||
| 1570 | android_change_gc (gc, mask, values); | ||
| 1571 | return gc; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | void | ||
| 1575 | android_free_gc (struct android_gc *gc) | ||
| 1576 | { | ||
| 1577 | android_destroy_handle (gc->gcontext); | ||
| 1578 | xfree (gc); | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | void | ||
| 1582 | android_change_gc (struct android_gc *gc, | ||
| 1583 | enum android_gc_value_mask mask, | ||
| 1584 | struct android_gc_values *values) | ||
| 1585 | { | ||
| 1586 | jobject what, gcontext; | ||
| 1587 | |||
| 1588 | android_init_emacs_gc_class (); | ||
| 1589 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1590 | ANDROID_HANDLE_GCONTEXT); | ||
| 1591 | |||
| 1592 | if (mask & ANDROID_GC_FOREGROUND) | ||
| 1593 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1594 | gcontext, | ||
| 1595 | emacs_gc_foreground, | ||
| 1596 | values->foreground); | ||
| 1597 | |||
| 1598 | if (mask & ANDROID_GC_BACKGROUND) | ||
| 1599 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1600 | gcontext, | ||
| 1601 | emacs_gc_background, | ||
| 1602 | values->background); | ||
| 1603 | |||
| 1604 | if (mask & ANDROID_GC_FUNCTION) | ||
| 1605 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1606 | gcontext, | ||
| 1607 | emacs_gc_function, | ||
| 1608 | values->function); | ||
| 1609 | |||
| 1610 | if (mask & ANDROID_GC_CLIP_X_ORIGIN) | ||
| 1611 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1612 | gcontext, | ||
| 1613 | emacs_gc_clip_x_origin, | ||
| 1614 | values->clip_x_origin); | ||
| 1615 | |||
| 1616 | if (mask & ANDROID_GC_CLIP_Y_ORIGIN) | ||
| 1617 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1618 | gcontext, | ||
| 1619 | emacs_gc_clip_y_origin, | ||
| 1620 | values->clip_y_origin); | ||
| 1621 | |||
| 1622 | if (mask & ANDROID_GC_CLIP_MASK) | ||
| 1623 | { | ||
| 1624 | what = android_resolve_handle (values->clip_mask, | ||
| 1625 | ANDROID_HANDLE_PIXMAP); | ||
| 1626 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1627 | gcontext, | ||
| 1628 | emacs_gc_stipple, | ||
| 1629 | what); | ||
| 1630 | |||
| 1631 | /* Clearing GCClipMask also clears the clip rectangles. */ | ||
| 1632 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1633 | gcontext, | ||
| 1634 | emacs_gc_clip_rects, | ||
| 1635 | NULL); | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | if (mask & ANDROID_GC_STIPPLE) | ||
| 1639 | { | ||
| 1640 | what = android_resolve_handle (values->stipple, | ||
| 1641 | ANDROID_HANDLE_PIXMAP); | ||
| 1642 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1643 | gcontext, | ||
| 1644 | emacs_gc_stipple, | ||
| 1645 | what); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | if (mask & ANDROID_GC_FILL_STYLE) | ||
| 1649 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1650 | gcontext, | ||
| 1651 | emacs_gc_fill_style, | ||
| 1652 | values->fill_style); | ||
| 1653 | |||
| 1654 | if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN) | ||
| 1655 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1656 | gcontext, | ||
| 1657 | emacs_gc_ts_origin_x, | ||
| 1658 | values->ts_x_origin); | ||
| 1659 | |||
| 1660 | if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN) | ||
| 1661 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1662 | gcontext, | ||
| 1663 | emacs_gc_ts_origin_y, | ||
| 1664 | values->ts_y_origin); | ||
| 1665 | |||
| 1666 | if (mask) | ||
| 1667 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1668 | gcontext, | ||
| 1669 | emacs_gc_mark_dirty); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | void | ||
| 1673 | android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin, | ||
| 1674 | int clip_y_origin, | ||
| 1675 | struct android_rectangle *clip_rects, | ||
| 1676 | int n_clip_rects) | ||
| 1677 | { | ||
| 1678 | jobjectArray array; | ||
| 1679 | jobject rect, gcontext; | ||
| 1680 | int i; | ||
| 1681 | |||
| 1682 | android_init_android_rect_class (); | ||
| 1683 | android_init_emacs_gc_class (); | ||
| 1684 | |||
| 1685 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1686 | ANDROID_HANDLE_GCONTEXT); | ||
| 1687 | |||
| 1688 | array = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 1689 | n_clip_rects, | ||
| 1690 | android_rect_class, | ||
| 1691 | NULL); | ||
| 1692 | |||
| 1693 | if (!array) | ||
| 1694 | { | ||
| 1695 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1696 | memory_full (0); | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | for (i = 0; i < n_clip_rects; ++i) | ||
| 1700 | { | ||
| 1701 | rect = (*android_java_env)->NewObject (android_java_env, | ||
| 1702 | android_rect_class, | ||
| 1703 | android_rect_constructor, | ||
| 1704 | (jint) clip_rects[i].x, | ||
| 1705 | (jint) clip_rects[i].y, | ||
| 1706 | (jint) (clip_rects[i].x | ||
| 1707 | + clip_rects[i].width), | ||
| 1708 | (jint) (clip_rects[i].y | ||
| 1709 | + clip_rects[i].height)); | ||
| 1710 | |||
| 1711 | if (!rect) | ||
| 1712 | { | ||
| 1713 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1714 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 1715 | memory_full (0); | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 1719 | array, i, rect); | ||
| 1720 | ANDROID_DELETE_LOCAL_REF (rect); | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1724 | gcontext, | ||
| 1725 | emacs_gc_clip_rects, | ||
| 1726 | (jobject) array); | ||
| 1727 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 1728 | |||
| 1729 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1730 | gcontext, | ||
| 1731 | emacs_gc_clip_x_origin, | ||
| 1732 | clip_x_origin); | ||
| 1733 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1734 | gcontext, | ||
| 1735 | emacs_gc_clip_y_origin, | ||
| 1736 | clip_y_origin); | ||
| 1737 | |||
| 1738 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1739 | gcontext, | ||
| 1740 | emacs_gc_mark_dirty); | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | void | ||
| 1744 | android_reparent_window (android_window w, android_window parent, | ||
| 1745 | int x, int y) | ||
| 1746 | { | ||
| 1747 | /* TODO */ | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | /* Look up the method with SIGNATURE by NAME in CLASS. Abort if it | ||
| 1751 | could not be found. This should be used for functions which are | ||
| 1752 | not called very often. | ||
| 1753 | |||
| 1754 | CLASS must never be unloaded, or the behavior is undefined. */ | ||
| 1755 | |||
| 1756 | static jmethodID | ||
| 1757 | android_lookup_method (const char *class, const char *name, | ||
| 1758 | const char *signature) | ||
| 1759 | { | ||
| 1760 | jclass java_class; | ||
| 1761 | jmethodID method; | ||
| 1762 | |||
| 1763 | java_class | ||
| 1764 | = (*android_java_env)->FindClass (android_java_env, class); | ||
| 1765 | |||
| 1766 | if (!java_class) | ||
| 1767 | { | ||
| 1768 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1769 | "Failed to find class %s", class); | ||
| 1770 | emacs_abort (); | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | method | ||
| 1774 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1775 | java_class, name, | ||
| 1776 | signature); | ||
| 1777 | |||
| 1778 | if (!method) | ||
| 1779 | { | ||
| 1780 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1781 | "Failed to find method %s in class %s" | ||
| 1782 | " with signature %s", | ||
| 1783 | name, class, signature); | ||
| 1784 | emacs_abort (); | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | ANDROID_DELETE_LOCAL_REF (java_class); | ||
| 1788 | return method; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | void | ||
| 1792 | android_clear_window (android_window handle) | ||
| 1793 | { | ||
| 1794 | jobject window; | ||
| 1795 | |||
| 1796 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1797 | |||
| 1798 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1799 | emacs_service, | ||
| 1800 | service_class.clear_window, | ||
| 1801 | window); | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | void | ||
| 1805 | android_map_window (android_window handle) | ||
| 1806 | { | ||
| 1807 | jobject window; | ||
| 1808 | jmethodID map_window; | ||
| 1809 | |||
| 1810 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1811 | map_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1812 | "mapWindow", "()V"); | ||
| 1813 | |||
| 1814 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1815 | window, map_window); | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | void | ||
| 1819 | android_unmap_window (android_window handle) | ||
| 1820 | { | ||
| 1821 | jobject window; | ||
| 1822 | jmethodID unmap_window; | ||
| 1823 | |||
| 1824 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1825 | unmap_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1826 | "unmapWindow", "()V"); | ||
| 1827 | |||
| 1828 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1829 | window, unmap_window); | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | void | ||
| 1833 | android_resize_window (android_window handle, unsigned int width, | ||
| 1834 | unsigned int height) | ||
| 1835 | { | ||
| 1836 | jobject window; | ||
| 1837 | jmethodID resize_window; | ||
| 1838 | |||
| 1839 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1840 | resize_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1841 | "resizeWindow", "(II)V"); | ||
| 1842 | |||
| 1843 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1844 | window, resize_window, | ||
| 1845 | (jint) width, (jint) height); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | void | ||
| 1849 | android_move_window (android_window handle, int x, int y) | ||
| 1850 | { | ||
| 1851 | jobject window; | ||
| 1852 | jmethodID move_window; | ||
| 1853 | |||
| 1854 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1855 | move_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1856 | "moveWindow", "(II)V"); | ||
| 1857 | |||
| 1858 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1859 | window, move_window, | ||
| 1860 | (jint) x, (jint) y); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | void | ||
| 1864 | android_swap_buffers (struct android_swap_info *swap_info, | ||
| 1865 | int num_windows) | ||
| 1866 | { | ||
| 1867 | jobject window; | ||
| 1868 | jmethodID swap_buffers; | ||
| 1869 | int i; | ||
| 1870 | |||
| 1871 | swap_buffers = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1872 | "swapBuffers", "()V"); | ||
| 1873 | |||
| 1874 | for (i = 0; i < num_windows; ++i) | ||
| 1875 | { | ||
| 1876 | window = android_resolve_handle (swap_info[i].swap_window, | ||
| 1877 | ANDROID_HANDLE_WINDOW); | ||
| 1878 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1879 | window, swap_buffers); | ||
| 1880 | } | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | void | ||
| 1884 | android_get_gc_values (struct android_gc *gc, | ||
| 1885 | enum android_gc_value_mask mask, | ||
| 1886 | struct android_gc_values *values) | ||
| 1887 | { | ||
| 1888 | jobject gcontext; | ||
| 1889 | |||
| 1890 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1891 | ANDROID_HANDLE_GCONTEXT); | ||
| 1892 | |||
| 1893 | if (mask & ANDROID_GC_FOREGROUND) | ||
| 1894 | /* GCs never have 32 bit colors, so we don't have to worry about | ||
| 1895 | sign extension here. */ | ||
| 1896 | values->foreground | ||
| 1897 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1898 | gcontext, | ||
| 1899 | emacs_gc_foreground); | ||
| 1900 | |||
| 1901 | if (mask & ANDROID_GC_BACKGROUND) | ||
| 1902 | values->background | ||
| 1903 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1904 | gcontext, | ||
| 1905 | emacs_gc_background); | ||
| 1906 | |||
| 1907 | if (mask & ANDROID_GC_FUNCTION) | ||
| 1908 | values->function | ||
| 1909 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1910 | gcontext, | ||
| 1911 | emacs_gc_function); | ||
| 1912 | |||
| 1913 | if (mask & ANDROID_GC_CLIP_X_ORIGIN) | ||
| 1914 | values->clip_x_origin | ||
| 1915 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1916 | gcontext, | ||
| 1917 | emacs_gc_clip_x_origin); | ||
| 1918 | |||
| 1919 | if (mask & ANDROID_GC_CLIP_Y_ORIGIN) | ||
| 1920 | values->clip_y_origin | ||
| 1921 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1922 | gcontext, | ||
| 1923 | emacs_gc_clip_y_origin); | ||
| 1924 | |||
| 1925 | if (mask & ANDROID_GC_FILL_STYLE) | ||
| 1926 | values->fill_style | ||
| 1927 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1928 | gcontext, | ||
| 1929 | emacs_gc_fill_style); | ||
| 1930 | |||
| 1931 | if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN) | ||
| 1932 | values->ts_x_origin | ||
| 1933 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1934 | gcontext, | ||
| 1935 | emacs_gc_ts_origin_x); | ||
| 1936 | |||
| 1937 | if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN) | ||
| 1938 | values->ts_y_origin | ||
| 1939 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1940 | gcontext, | ||
| 1941 | emacs_gc_ts_origin_y); | ||
| 1942 | |||
| 1943 | /* Fields involving handles are not used by Emacs, and thus not | ||
| 1944 | implemented */ | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | void | ||
| 1948 | android_set_foreground (struct android_gc *gc, unsigned long foreground) | ||
| 1949 | { | ||
| 1950 | struct android_gc_values gcv; | ||
| 1951 | |||
| 1952 | gcv.foreground = foreground; | ||
| 1953 | android_change_gc (gc, ANDROID_GC_FOREGROUND, &gcv); | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | void | ||
| 1957 | android_fill_rectangle (android_drawable handle, struct android_gc *gc, | ||
| 1958 | int x, int y, unsigned int width, | ||
| 1959 | unsigned int height) | ||
| 1960 | { | ||
| 1961 | jobject drawable, gcontext; | ||
| 1962 | |||
| 1963 | drawable = android_resolve_handle2 (handle, | ||
| 1964 | ANDROID_HANDLE_WINDOW, | ||
| 1965 | ANDROID_HANDLE_PIXMAP); | ||
| 1966 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1967 | ANDROID_HANDLE_GCONTEXT); | ||
| 1968 | |||
| 1969 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1970 | emacs_service, | ||
| 1971 | service_class.fill_rectangle, | ||
| 1972 | drawable, | ||
| 1973 | gcontext, | ||
| 1974 | (jint) x, (jint) y, | ||
| 1975 | (jint) width, | ||
| 1976 | (jint) height); | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | android_pixmap | ||
| 1980 | android_create_pixmap_from_bitmap_data (char *data, unsigned int width, | ||
| 1981 | unsigned int height, | ||
| 1982 | unsigned long foreground, | ||
| 1983 | unsigned long background, | ||
| 1984 | unsigned int depth) | ||
| 1985 | { | ||
| 1986 | android_handle prev_max_handle; | ||
| 1987 | jobject object; | ||
| 1988 | jintArray colors; | ||
| 1989 | android_pixmap pixmap; | ||
| 1990 | unsigned int x, y; | ||
| 1991 | jint *region; | ||
| 1992 | |||
| 1993 | USE_SAFE_ALLOCA; | ||
| 1994 | |||
| 1995 | /* Create the color array holding the data. */ | ||
| 1996 | colors = (*android_java_env)->NewIntArray (android_java_env, | ||
| 1997 | width * height); | ||
| 1998 | |||
| 1999 | if (!colors) | ||
| 2000 | { | ||
| 2001 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2002 | memory_full (0); | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | SAFE_NALLOCA (region, sizeof *region, width); | ||
| 2006 | |||
| 2007 | for (y = 0; y < height; ++y) | ||
| 2008 | { | ||
| 2009 | for (x = 0; x < width; ++x) | ||
| 2010 | { | ||
| 2011 | if (data[y / 8] & (1 << (x % 8))) | ||
| 2012 | region[x] = foreground; | ||
| 2013 | else | ||
| 2014 | region[x] = background; | ||
| 2015 | } | ||
| 2016 | |||
| 2017 | (*android_java_env)->SetIntArrayRegion (android_java_env, | ||
| 2018 | colors, | ||
| 2019 | width * y, width, | ||
| 2020 | region); | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | /* First, allocate the pixmap handle. */ | ||
| 2024 | prev_max_handle = max_handle; | ||
| 2025 | pixmap = android_alloc_id (); | ||
| 2026 | |||
| 2027 | if (!pixmap) | ||
| 2028 | { | ||
| 2029 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2030 | error ("Out of pixmap handles!"); | ||
| 2031 | } | ||
| 2032 | |||
| 2033 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 2034 | pixmap_class.class, | ||
| 2035 | pixmap_class.constructor, | ||
| 2036 | (jshort) pixmap, colors, | ||
| 2037 | (jint) width, (jint) height, | ||
| 2038 | (jint) depth); | ||
| 2039 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2040 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2041 | |||
| 2042 | if (!object) | ||
| 2043 | { | ||
| 2044 | max_handle = prev_max_handle; | ||
| 2045 | memory_full (0); | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP; | ||
| 2049 | android_handles[pixmap].handle | ||
| 2050 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 2051 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 2052 | |||
| 2053 | if (!android_handles[pixmap].handle) | ||
| 2054 | memory_full (0); | ||
| 2055 | |||
| 2056 | SAFE_FREE (); | ||
| 2057 | return pixmap; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | void | ||
| 2061 | android_set_clip_mask (struct android_gc *gc, android_pixmap pixmap) | ||
| 2062 | { | ||
| 2063 | struct android_gc_values gcv; | ||
| 2064 | |||
| 2065 | gcv.clip_mask = pixmap; | ||
| 2066 | android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv); | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | void | ||
| 2070 | android_set_fill_style (struct android_gc *gc, | ||
| 2071 | enum android_fill_style fill_style) | ||
| 2072 | { | ||
| 2073 | struct android_gc_values gcv; | ||
| 2074 | |||
| 2075 | gcv.fill_style = fill_style; | ||
| 2076 | android_change_gc (gc, ANDROID_GC_FILL_STYLE, &gcv); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | void | ||
| 2080 | android_copy_area (android_drawable src, android_drawable dest, | ||
| 2081 | struct android_gc *gc, int src_x, int src_y, | ||
| 2082 | unsigned int width, unsigned int height, | ||
| 2083 | int dest_x, int dest_y) | ||
| 2084 | { | ||
| 2085 | jobject src_object, dest_object, gcontext; | ||
| 2086 | |||
| 2087 | src_object = android_resolve_handle2 (src, ANDROID_HANDLE_WINDOW, | ||
| 2088 | ANDROID_HANDLE_PIXMAP); | ||
| 2089 | dest_object = android_resolve_handle2 (dest, ANDROID_HANDLE_WINDOW, | ||
| 2090 | ANDROID_HANDLE_PIXMAP); | ||
| 2091 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2092 | ANDROID_HANDLE_GCONTEXT); | ||
| 2093 | |||
| 2094 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2095 | emacs_service, | ||
| 2096 | service_class.copy_area, | ||
| 2097 | src_object, | ||
| 2098 | dest_object, | ||
| 2099 | gcontext, | ||
| 2100 | (jint) src_x, (jint) src_y, | ||
| 2101 | (jint) width, (jint) height, | ||
| 2102 | (jint) dest_x, (jint) dest_y); | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | void | ||
| 2106 | android_free_pixmap (android_pixmap pixmap) | ||
| 2107 | { | ||
| 2108 | android_destroy_handle (pixmap); | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | void | ||
| 2112 | android_set_background (struct android_gc *gc, unsigned long background) | ||
| 2113 | { | ||
| 2114 | struct android_gc_values gcv; | ||
| 2115 | |||
| 2116 | gcv.background = background; | ||
| 2117 | android_change_gc (gc, ANDROID_GC_BACKGROUND, &gcv); | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | void | ||
| 2121 | android_fill_polygon (android_drawable drawable, struct android_gc *gc, | ||
| 2122 | struct android_point *points, int npoints, | ||
| 2123 | enum android_shape shape, enum android_coord_mode mode) | ||
| 2124 | { | ||
| 2125 | jobjectArray array; | ||
| 2126 | jobject point, drawable_object, gcontext; | ||
| 2127 | int i; | ||
| 2128 | |||
| 2129 | drawable_object = android_resolve_handle2 (drawable, | ||
| 2130 | ANDROID_HANDLE_WINDOW, | ||
| 2131 | ANDROID_HANDLE_PIXMAP); | ||
| 2132 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2133 | ANDROID_HANDLE_GCONTEXT); | ||
| 2134 | |||
| 2135 | array = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 2136 | npoints, | ||
| 2137 | point_class.class, | ||
| 2138 | NULL); | ||
| 2139 | |||
| 2140 | if (!array) | ||
| 2141 | { | ||
| 2142 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2143 | memory_full (0); | ||
| 2144 | } | ||
| 2145 | |||
| 2146 | for (i = 0; i < npoints; ++i) | ||
| 2147 | { | ||
| 2148 | point = (*android_java_env)->NewObject (android_java_env, | ||
| 2149 | point_class.class, | ||
| 2150 | point_class.constructor, | ||
| 2151 | (jint) points[i].x, | ||
| 2152 | (jint) points[i].y); | ||
| 2153 | |||
| 2154 | if (!point) | ||
| 2155 | { | ||
| 2156 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2157 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 2158 | memory_full (0); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 2162 | array, i, point); | ||
| 2163 | ANDROID_DELETE_LOCAL_REF (point); | ||
| 2164 | } | ||
| 2165 | |||
| 2166 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2167 | emacs_service, | ||
| 2168 | service_class.fill_polygon, | ||
| 2169 | drawable_object, | ||
| 2170 | gcontext, array); | ||
| 2171 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | void | ||
| 2175 | android_draw_rectangle (android_drawable handle, struct android_gc *gc, | ||
| 2176 | int x, int y, unsigned int width, unsigned int height) | ||
| 2177 | { | ||
| 2178 | jobject drawable, gcontext; | ||
| 2179 | |||
| 2180 | drawable = android_resolve_handle2 (handle, | ||
| 2181 | ANDROID_HANDLE_WINDOW, | ||
| 2182 | ANDROID_HANDLE_PIXMAP); | ||
| 2183 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2184 | ANDROID_HANDLE_GCONTEXT); | ||
| 2185 | |||
| 2186 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2187 | emacs_service, | ||
| 2188 | service_class.draw_rectangle, | ||
| 2189 | drawable, gcontext, | ||
| 2190 | (jint) x, (jint) y, | ||
| 2191 | (jint) width, (jint) height); | ||
| 2192 | } | ||
| 2193 | |||
| 2194 | void | ||
| 2195 | android_draw_point (android_drawable handle, struct android_gc *gc, | ||
| 2196 | int x, int y) | ||
| 2197 | { | ||
| 2198 | jobject drawable, gcontext; | ||
| 2199 | |||
| 2200 | drawable = android_resolve_handle2 (handle, | ||
| 2201 | ANDROID_HANDLE_WINDOW, | ||
| 2202 | ANDROID_HANDLE_PIXMAP); | ||
| 2203 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2204 | ANDROID_HANDLE_GCONTEXT); | ||
| 2205 | |||
| 2206 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2207 | emacs_service, | ||
| 2208 | service_class.draw_point, | ||
| 2209 | drawable, gcontext, | ||
| 2210 | (jint) x, (jint) y); | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | void | ||
| 2214 | android_draw_line (android_drawable handle, struct android_gc *gc, | ||
| 2215 | int x, int y, int x2, int y2) | ||
| 2216 | { | ||
| 2217 | jobject drawable, gcontext; | ||
| 2218 | |||
| 2219 | drawable = android_resolve_handle2 (handle, | ||
| 2220 | ANDROID_HANDLE_WINDOW, | ||
| 2221 | ANDROID_HANDLE_PIXMAP); | ||
| 2222 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2223 | ANDROID_HANDLE_GCONTEXT); | ||
| 2224 | |||
| 2225 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2226 | emacs_service, | ||
| 2227 | service_class.draw_line, | ||
| 2228 | drawable, gcontext, | ||
| 2229 | (jint) x, (jint) y, | ||
| 2230 | (jint) x2, (jint) y2); | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | android_pixmap | ||
| 2234 | android_create_pixmap (unsigned int width, unsigned int height, | ||
| 2235 | int depth) | ||
| 2236 | { | ||
| 2237 | android_handle prev_max_handle; | ||
| 2238 | jobject object; | ||
| 2239 | jintArray colors; | ||
| 2240 | android_pixmap pixmap; | ||
| 2241 | |||
| 2242 | /* Create the color array holding the data. */ | ||
| 2243 | colors = (*android_java_env)->NewIntArray (android_java_env, | ||
| 2244 | width * height); | ||
| 2245 | |||
| 2246 | if (!colors) | ||
| 2247 | { | ||
| 2248 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2249 | memory_full (0); | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | /* First, allocate the pixmap handle. */ | ||
| 2253 | prev_max_handle = max_handle; | ||
| 2254 | pixmap = android_alloc_id (); | ||
| 2255 | |||
| 2256 | if (!pixmap) | ||
| 2257 | { | ||
| 2258 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2259 | error ("Out of pixmap handles!"); | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 2263 | pixmap_class.class, | ||
| 2264 | pixmap_class.constructor, | ||
| 2265 | (jshort) pixmap, colors, | ||
| 2266 | (jint) width, (jint) height, | ||
| 2267 | (jint) depth); | ||
| 2268 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2269 | |||
| 2270 | if (!object) | ||
| 2271 | { | ||
| 2272 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2273 | max_handle = prev_max_handle; | ||
| 2274 | memory_full (0); | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP; | ||
| 2278 | android_handles[pixmap].handle | ||
| 2279 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 2280 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2281 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 2282 | |||
| 2283 | if (!android_handles[pixmap].handle) | ||
| 2284 | memory_full (0); | ||
| 2285 | |||
| 2286 | return pixmap; | ||
| 2287 | } | ||
| 2288 | |||
| 2289 | void | ||
| 2290 | android_set_ts_origin (struct android_gc *gc, int x, int y) | ||
| 2291 | { | ||
| 2292 | struct android_gc_values gcv; | ||
| 2293 | |||
| 2294 | gcv.ts_x_origin = x; | ||
| 2295 | gcv.ts_y_origin = y; | ||
| 2296 | android_change_gc (gc, (ANDROID_GC_TILE_STIP_X_ORIGIN | ||
| 2297 | | ANDROID_GC_TILE_STIP_Y_ORIGIN), | ||
| 2298 | &gcv); | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | void | ||
| 2302 | android_clear_area (android_window handle, int x, int y, | ||
| 2303 | unsigned int width, unsigned int height) | ||
| 2304 | { | ||
| 2305 | jobject window; | ||
| 2306 | |||
| 2307 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 2308 | |||
| 2309 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2310 | emacs_service, | ||
| 2311 | service_class.clear_area, | ||
| 2312 | window, (jint) x, (jint) y, | ||
| 2313 | (jint) width, (jint) height); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | #else /* ANDROID_STUBIFY */ | ||
| 2317 | |||
| 2318 | /* X emulation functions for Android. */ | ||
| 2319 | |||
| 2320 | struct android_gc * | ||
| 2321 | android_create_gc (enum android_gc_value_mask mask, | ||
| 2322 | struct android_gc_values *values) | ||
| 2323 | { | ||
| 2324 | /* This function should never be called when building stubs. */ | ||
| 2325 | emacs_abort (); | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | void | ||
| 2329 | android_free_gc (struct android_gc *gc) | ||
| 2330 | { | ||
| 2331 | /* This function should never be called when building stubs. */ | ||
| 2332 | emacs_abort (); | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | #endif | ||
diff --git a/src/android.h b/src/android.h new file mode 100644 index 00000000000..6bdcd38ed68 --- /dev/null +++ b/src/android.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | /* On Android, Emacs is built as a shared library loaded from Java | ||
| 21 | using the Java Native Interface. Emacs's `main' function is | ||
| 22 | renamed `android_emacs_init', and runs with some modifications | ||
| 23 | inside a separate thread, communicating with the Java code through | ||
| 24 | a table of function pointers. */ | ||
| 25 | |||
| 26 | #ifndef _ANDROID_H_ | ||
| 27 | #ifndef ANDROID_STUBIFY | ||
| 28 | #include <jni.h> | ||
| 29 | #include <pwd.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* This must be used in every symbol declaration to export it to the | ||
| 34 | JNI Emacs wrapper. */ | ||
| 35 | #define ANDROID_EXPORT __attribute__ ((visibility ("default"))) | ||
| 36 | |||
| 37 | extern bool ANDROID_EXPORT android_init_gui; | ||
| 38 | extern int ANDROID_EXPORT android_emacs_init (int, char **); | ||
| 39 | |||
| 40 | #ifndef ANDROID_STUBIFY | ||
| 41 | |||
| 42 | extern int android_select (int, fd_set *, fd_set *, fd_set *, | ||
| 43 | struct timespec *, const sigset_t *); | ||
| 44 | |||
| 45 | extern bool android_file_access_p (const char *, int); | ||
| 46 | extern int android_open (const char *, int, int); | ||
| 47 | extern char *android_user_full_name (struct passwd *); | ||
| 48 | extern int android_fstat (int, struct stat *); | ||
| 49 | extern int android_fstatat (int, const char *restrict, | ||
| 50 | struct stat *restrict, int); | ||
| 51 | extern int android_close (int); | ||
| 52 | |||
| 53 | #endif | ||
| 54 | |||
| 55 | /* JNI functions should not be built when Emacs is stubbed out for the | ||
| 56 | build. These should be documented in EmacsNative.java. */ | ||
| 57 | |||
| 58 | #ifndef ANDROID_STUBIFY | ||
| 59 | #include <jni.h> | ||
| 60 | |||
| 61 | extern JNIEnv *android_java_env; | ||
| 62 | |||
| 63 | #define ANDROID_DELETE_LOCAL_REF(ref) \ | ||
| 64 | ((*android_java_env)->DeleteLocalRef (android_java_env, \ | ||
| 65 | (ref))) | ||
| 66 | |||
| 67 | #define NATIVE_NAME(name) Java_org_gnu_emacs_EmacsNative_##name | ||
| 68 | |||
| 69 | #endif | ||
| 70 | #endif /* _ANDROID_H_ */ | ||
diff --git a/src/androidfns.c b/src/androidfns.c new file mode 100644 index 00000000000..e9e1ae3d52e --- /dev/null +++ b/src/androidfns.c | |||
| @@ -0,0 +1,1779 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <math.h> | ||
| 22 | |||
| 23 | #include "lisp.h" | ||
| 24 | #include "androidterm.h" | ||
| 25 | #include "blockinput.h" | ||
| 26 | #include "keyboard.h" | ||
| 27 | |||
| 28 | #ifndef ANDROID_STUBIFY | ||
| 29 | |||
| 30 | /* Some kind of reference count for the image cache. */ | ||
| 31 | static ptrdiff_t image_cache_refcount; | ||
| 32 | |||
| 33 | #endif | ||
| 34 | |||
| 35 | static struct android_display_info * | ||
| 36 | android_display_info_for_name (Lisp_Object name) | ||
| 37 | { | ||
| 38 | struct android_display_info *dpyinfo; | ||
| 39 | |||
| 40 | CHECK_STRING (name); | ||
| 41 | |||
| 42 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | ||
| 43 | { | ||
| 44 | if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), | ||
| 45 | name))) | ||
| 46 | return dpyinfo; | ||
| 47 | } | ||
| 48 | |||
| 49 | error ("Cannot connect to Android if it was not initialized" | ||
| 50 | " at startup"); | ||
| 51 | } | ||
| 52 | |||
| 53 | static struct android_display_info * | ||
| 54 | check_android_display_info (Lisp_Object object) | ||
| 55 | { | ||
| 56 | struct android_display_info *dpyinfo; | ||
| 57 | struct frame *sf, *f; | ||
| 58 | struct terminal *t; | ||
| 59 | |||
| 60 | if (NILP (object)) | ||
| 61 | { | ||
| 62 | sf = XFRAME (selected_frame); | ||
| 63 | |||
| 64 | if (FRAME_ANDROID_P (sf) && FRAME_LIVE_P (sf)) | ||
| 65 | dpyinfo = FRAME_DISPLAY_INFO (sf); | ||
| 66 | else if (x_display_list) | ||
| 67 | dpyinfo = x_display_list; | ||
| 68 | else | ||
| 69 | error ("Android windows are not in use or not initialized"); | ||
| 70 | } | ||
| 71 | else if (TERMINALP (object)) | ||
| 72 | { | ||
| 73 | t = decode_live_terminal (object); | ||
| 74 | |||
| 75 | if (t->type != output_android) | ||
| 76 | error ("Terminal %d is not an Android display", t->id); | ||
| 77 | |||
| 78 | dpyinfo = t->display_info.android; | ||
| 79 | } | ||
| 80 | else if (STRINGP (object)) | ||
| 81 | dpyinfo = android_display_info_for_name (object); | ||
| 82 | else | ||
| 83 | { | ||
| 84 | f = decode_window_system_frame (object); | ||
| 85 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 86 | } | ||
| 87 | |||
| 88 | return dpyinfo; | ||
| 89 | } | ||
| 90 | |||
| 91 | Display_Info * | ||
| 92 | check_x_display_info (Lisp_Object object) | ||
| 93 | { | ||
| 94 | return check_android_display_info (object); | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | |||
| 99 | #ifndef ANDROID_STUBIFY | ||
| 100 | |||
| 101 | void | ||
| 102 | gamma_correct (struct frame *f, Emacs_Color *color) | ||
| 103 | { | ||
| 104 | if (f->gamma) | ||
| 105 | { | ||
| 106 | color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 107 | color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 108 | color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /* Decide if color named COLOR_NAME is valid for use on frame F. If | ||
| 113 | so, return the RGB values in COLOR. If ALLOC_P, allocate the | ||
| 114 | color. Value is false if COLOR_NAME is invalid, or no color could | ||
| 115 | be allocated. MAKE_INDEX is some mysterious argument used on | ||
| 116 | NS. */ | ||
| 117 | |||
| 118 | bool | ||
| 119 | android_defined_color (struct frame *f, const char *color_name, | ||
| 120 | Emacs_Color *color, bool alloc_p, | ||
| 121 | bool make_index) | ||
| 122 | { | ||
| 123 | bool success_p; | ||
| 124 | |||
| 125 | success_p = false; | ||
| 126 | |||
| 127 | block_input (); | ||
| 128 | success_p = android_parse_color (f, color_name, color); | ||
| 129 | if (success_p && alloc_p) | ||
| 130 | success_p = android_alloc_nearest_color (f, color); | ||
| 131 | unblock_input (); | ||
| 132 | |||
| 133 | return success_p; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Return the pixel color value for color COLOR_NAME on frame F. If F | ||
| 137 | is a monochrome frame, return MONO_COLOR regardless of what ARG | ||
| 138 | says. Signal an error if color can't be allocated. */ | ||
| 139 | |||
| 140 | static unsigned long | ||
| 141 | android_decode_color (struct frame *f, Lisp_Object color_name, int mono_color) | ||
| 142 | { | ||
| 143 | Emacs_Color cdef; | ||
| 144 | |||
| 145 | CHECK_STRING (color_name); | ||
| 146 | |||
| 147 | if (android_defined_color (f, SSDATA (color_name), &cdef, | ||
| 148 | true, false)) | ||
| 149 | return cdef.pixel; | ||
| 150 | |||
| 151 | signal_error ("Undefined color", color_name); | ||
| 152 | } | ||
| 153 | |||
| 154 | void | ||
| 155 | android_implicitly_set_name (struct frame *f, Lisp_Object arg, | ||
| 156 | Lisp_Object oldval) | ||
| 157 | { | ||
| 158 | |||
| 159 | } | ||
| 160 | |||
| 161 | void | ||
| 162 | android_explicitly_set_name (struct frame *f, Lisp_Object arg, | ||
| 163 | Lisp_Object oldval) | ||
| 164 | { | ||
| 165 | |||
| 166 | } | ||
| 167 | |||
| 168 | /* Set the number of lines used for the tool bar of frame F to VALUE. | ||
| 169 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 170 | is the old number of tool bar lines. This function changes the | ||
| 171 | height of all windows on frame F to match the new tool bar height. | ||
| 172 | The frame's height doesn't change. */ | ||
| 173 | |||
| 174 | static void | ||
| 175 | android_set_tool_bar_lines (struct frame *f, Lisp_Object value, | ||
| 176 | Lisp_Object oldval) | ||
| 177 | { | ||
| 178 | int nlines; | ||
| 179 | |||
| 180 | /* Treat tool bars like menu bars. */ | ||
| 181 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 182 | return; | ||
| 183 | |||
| 184 | /* Use VALUE only if an int >= 0. */ | ||
| 185 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 186 | nlines = XFIXNAT (value); | ||
| 187 | else | ||
| 188 | nlines = 0; | ||
| 189 | |||
| 190 | android_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 191 | } | ||
| 192 | |||
| 193 | void | ||
| 194 | android_change_tool_bar_height (struct frame *f, int height) | ||
| 195 | { | ||
| 196 | int unit = FRAME_LINE_HEIGHT (f); | ||
| 197 | int old_height = FRAME_TOOL_BAR_HEIGHT (f); | ||
| 198 | int lines = (height + unit - 1) / unit; | ||
| 199 | Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); | ||
| 200 | |||
| 201 | /* Make sure we redisplay all windows in this frame. */ | ||
| 202 | fset_redisplay (f); | ||
| 203 | |||
| 204 | FRAME_TOOL_BAR_HEIGHT (f) = height; | ||
| 205 | FRAME_TOOL_BAR_LINES (f) = lines; | ||
| 206 | store_frame_param (f, Qtool_bar_lines, make_fixnum (lines)); | ||
| 207 | |||
| 208 | if (FRAME_ANDROID_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0) | ||
| 209 | { | ||
| 210 | clear_frame (f); | ||
| 211 | clear_current_matrices (f); | ||
| 212 | } | ||
| 213 | |||
| 214 | if ((height < old_height) && WINDOWP (f->tool_bar_window)) | ||
| 215 | clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); | ||
| 216 | |||
| 217 | if (!f->tool_bar_resized) | ||
| 218 | { | ||
| 219 | /* As long as tool_bar_resized is false, effectively try to change | ||
| 220 | F's native height. */ | ||
| 221 | if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) | ||
| 222 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 223 | 1, false, Qtool_bar_lines); | ||
| 224 | else | ||
| 225 | adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines); | ||
| 226 | |||
| 227 | f->tool_bar_resized = f->tool_bar_redisplayed; | ||
| 228 | } | ||
| 229 | else | ||
| 230 | /* Any other change may leave the native size of F alone. */ | ||
| 231 | adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines); | ||
| 232 | |||
| 233 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 234 | here. */ | ||
| 235 | adjust_frame_glyphs (f); | ||
| 236 | SET_FRAME_GARBAGED (f); | ||
| 237 | } | ||
| 238 | |||
| 239 | /* Set the number of lines used for the tab bar of frame F to VALUE. | ||
| 240 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 241 | is the old number of tab bar lines. This function may change the | ||
| 242 | height of all windows on frame F to match the new tab bar height. | ||
| 243 | The frame's height may change if frame_inhibit_implied_resize was | ||
| 244 | set accordingly. */ | ||
| 245 | |||
| 246 | static void | ||
| 247 | android_set_tab_bar_lines (struct frame *f, Lisp_Object value, | ||
| 248 | Lisp_Object oldval) | ||
| 249 | { | ||
| 250 | int olines; | ||
| 251 | int nlines; | ||
| 252 | |||
| 253 | olines = FRAME_TAB_BAR_LINES (f); | ||
| 254 | |||
| 255 | /* Treat tab bars like menu bars. */ | ||
| 256 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 257 | return; | ||
| 258 | |||
| 259 | /* Use VALUE only if an int >= 0. */ | ||
| 260 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 261 | nlines = XFIXNAT (value); | ||
| 262 | else | ||
| 263 | nlines = 0; | ||
| 264 | |||
| 265 | if (nlines != olines && (olines == 0 || nlines == 0)) | ||
| 266 | android_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 267 | } | ||
| 268 | |||
| 269 | void | ||
| 270 | android_change_tab_bar_height (struct frame *f, int height) | ||
| 271 | { | ||
| 272 | int unit, old_height, lines; | ||
| 273 | Lisp_Object fullscreen; | ||
| 274 | |||
| 275 | unit = FRAME_LINE_HEIGHT (f); | ||
| 276 | old_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 277 | fullscreen = get_frame_param (f, Qfullscreen); | ||
| 278 | |||
| 279 | /* This differs from the tool bar code in that the tab bar height is | ||
| 280 | not rounded up. Otherwise, if redisplay_tab_bar decides to grow | ||
| 281 | the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, | ||
| 282 | leading to the tab bar height being incorrectly set upon the next | ||
| 283 | call to android_set_font. (bug#59285) */ | ||
| 284 | lines = height / unit; | ||
| 285 | |||
| 286 | /* Make sure we redisplay all windows in this frame. */ | ||
| 287 | fset_redisplay (f); | ||
| 288 | |||
| 289 | /* Recalculate tab bar and frame text sizes. */ | ||
| 290 | FRAME_TAB_BAR_HEIGHT (f) = height; | ||
| 291 | FRAME_TAB_BAR_LINES (f) = lines; | ||
| 292 | store_frame_param (f, Qtab_bar_lines, make_fixnum (lines)); | ||
| 293 | |||
| 294 | if (FRAME_ANDROID_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0) | ||
| 295 | { | ||
| 296 | clear_frame (f); | ||
| 297 | clear_current_matrices (f); | ||
| 298 | } | ||
| 299 | |||
| 300 | if ((height < old_height) && WINDOWP (f->tab_bar_window)) | ||
| 301 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); | ||
| 302 | |||
| 303 | if (!f->tab_bar_resized) | ||
| 304 | { | ||
| 305 | /* As long as tab_bar_resized is false, effectively try to change | ||
| 306 | F's native height. */ | ||
| 307 | if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) | ||
| 308 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 309 | 1, false, Qtab_bar_lines); | ||
| 310 | else | ||
| 311 | adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines); | ||
| 312 | |||
| 313 | f->tab_bar_resized = f->tab_bar_redisplayed; | ||
| 314 | } | ||
| 315 | else | ||
| 316 | /* Any other change may leave the native size of F alone. */ | ||
| 317 | adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines); | ||
| 318 | |||
| 319 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 320 | here. */ | ||
| 321 | adjust_frame_glyphs (f); | ||
| 322 | SET_FRAME_GARBAGED (f); | ||
| 323 | } | ||
| 324 | |||
| 325 | void | ||
| 326 | android_set_scroll_bar_default_height (struct frame *f) | ||
| 327 | { | ||
| 328 | int height; | ||
| 329 | |||
| 330 | height = FRAME_LINE_HEIGHT (f); | ||
| 331 | |||
| 332 | /* The height of a non-toolkit scrollbar is 14 pixels. */ | ||
| 333 | FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height; | ||
| 334 | |||
| 335 | /* Use all of that space (aside from required margins) for the | ||
| 336 | scroll bar. */ | ||
| 337 | FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = 14; | ||
| 338 | } | ||
| 339 | |||
| 340 | void | ||
| 341 | android_set_scroll_bar_default_width (struct frame *f) | ||
| 342 | { | ||
| 343 | int unit; | ||
| 344 | |||
| 345 | unit = FRAME_COLUMN_WIDTH (f); | ||
| 346 | |||
| 347 | FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; | ||
| 348 | FRAME_CONFIG_SCROLL_BAR_WIDTH (f) | ||
| 349 | = FRAME_CONFIG_SCROLL_BAR_COLS (f) * unit; | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | /* Verify that the icon position args for this window are valid. */ | ||
| 354 | |||
| 355 | static void | ||
| 356 | android_icon_verify (struct frame *f, Lisp_Object parms) | ||
| 357 | { | ||
| 358 | Lisp_Object icon_x, icon_y; | ||
| 359 | |||
| 360 | /* Set the position of the icon. Note that twm groups all | ||
| 361 | icons in an icon window. */ | ||
| 362 | icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, | ||
| 363 | RES_TYPE_NUMBER); | ||
| 364 | icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, | ||
| 365 | RES_TYPE_NUMBER); | ||
| 366 | |||
| 367 | if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound)) | ||
| 368 | { | ||
| 369 | CHECK_FIXNUM (icon_x); | ||
| 370 | CHECK_FIXNUM (icon_y); | ||
| 371 | } | ||
| 372 | else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound)) | ||
| 373 | error ("Both left and top icon corners of icon must be specified"); | ||
| 374 | } | ||
| 375 | |||
| 376 | /* Handle the icon stuff for this window. Perhaps later we might | ||
| 377 | want an x_set_icon_position which can be called interactively as | ||
| 378 | well. */ | ||
| 379 | |||
| 380 | static void | ||
| 381 | android_icon (struct frame *f, Lisp_Object parms) | ||
| 382 | { | ||
| 383 | /* Set the position of the icon. Note that twm groups all | ||
| 384 | icons in an icon window. */ | ||
| 385 | Lisp_Object icon_x | ||
| 386 | = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, | ||
| 387 | RES_TYPE_NUMBER); | ||
| 388 | Lisp_Object icon_y | ||
| 389 | = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, | ||
| 390 | RES_TYPE_NUMBER); | ||
| 391 | |||
| 392 | bool xgiven = !BASE_EQ (icon_x, Qunbound); | ||
| 393 | bool ygiven = !BASE_EQ (icon_y, Qunbound); | ||
| 394 | |||
| 395 | if (xgiven != ygiven) | ||
| 396 | error ("Both left and top icon corners of icon must be specified"); | ||
| 397 | |||
| 398 | if (xgiven) | ||
| 399 | { | ||
| 400 | check_integer_range (icon_x, INT_MIN, INT_MAX); | ||
| 401 | check_integer_range (icon_y, INT_MIN, INT_MAX); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* Now return as this is not supported on Android. */ | ||
| 405 | } | ||
| 406 | |||
| 407 | /* Make the GCs needed for this window, setting the background | ||
| 408 | color. */ | ||
| 409 | |||
| 410 | static void | ||
| 411 | android_make_gc (struct frame *f) | ||
| 412 | { | ||
| 413 | struct android_gc_values gc_values; | ||
| 414 | |||
| 415 | block_input (); | ||
| 416 | |||
| 417 | /* Create the GCs of this frame. | ||
| 418 | Note that many default values are used. */ | ||
| 419 | |||
| 420 | gc_values.foreground = FRAME_FOREGROUND_PIXEL (f); | ||
| 421 | gc_values.background = FRAME_BACKGROUND_PIXEL (f); | ||
| 422 | f->output_data.android->normal_gc | ||
| 423 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 424 | &gc_values); | ||
| 425 | |||
| 426 | /* Reverse video style. */ | ||
| 427 | gc_values.foreground = FRAME_BACKGROUND_PIXEL (f); | ||
| 428 | gc_values.background = FRAME_FOREGROUND_PIXEL (f); | ||
| 429 | f->output_data.android->reverse_gc | ||
| 430 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 431 | &gc_values); | ||
| 432 | |||
| 433 | /* Cursor has cursor-color background, background-color foreground. */ | ||
| 434 | gc_values.foreground = FRAME_BACKGROUND_PIXEL (f); | ||
| 435 | gc_values.background = f->output_data.android->cursor_pixel; | ||
| 436 | f->output_data.android->cursor_gc | ||
| 437 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 438 | &gc_values); | ||
| 439 | unblock_input (); | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | /* Free what was allocated in android_make_gc. */ | ||
| 444 | |||
| 445 | void | ||
| 446 | android_free_gcs (struct frame *f) | ||
| 447 | { | ||
| 448 | block_input (); | ||
| 449 | |||
| 450 | if (f->output_data.android->normal_gc) | ||
| 451 | { | ||
| 452 | android_free_gc (f->output_data.android->normal_gc); | ||
| 453 | f->output_data.android->normal_gc = 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | if (f->output_data.android->reverse_gc) | ||
| 457 | { | ||
| 458 | android_free_gc (f->output_data.android->reverse_gc); | ||
| 459 | f->output_data.android->reverse_gc = 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (f->output_data.android->cursor_gc) | ||
| 463 | { | ||
| 464 | android_free_gc (f->output_data.android->cursor_gc); | ||
| 465 | f->output_data.android->cursor_gc = 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | unblock_input (); | ||
| 469 | } | ||
| 470 | |||
| 471 | /* Handler for signals raised during x_create_frame and | ||
| 472 | Fx_create_tip_frame. FRAME is the frame which is partially | ||
| 473 | constructed. */ | ||
| 474 | |||
| 475 | static Lisp_Object | ||
| 476 | unwind_create_frame (Lisp_Object frame) | ||
| 477 | { | ||
| 478 | struct frame *f = XFRAME (frame); | ||
| 479 | |||
| 480 | /* If frame is already dead, nothing to do. This can happen if the | ||
| 481 | display is disconnected after the frame has become official, but | ||
| 482 | before Fx_create_frame removes the unwind protect. */ | ||
| 483 | if (!FRAME_LIVE_P (f)) | ||
| 484 | return Qnil; | ||
| 485 | |||
| 486 | /* If frame is ``official'', nothing to do. */ | ||
| 487 | if (NILP (Fmemq (frame, Vframe_list))) | ||
| 488 | { | ||
| 489 | /* If the frame's image cache refcount is still the same as our | ||
| 490 | private shadow variable, it means we are unwinding a frame | ||
| 491 | for which we didn't yet call init_frame_faces, where the | ||
| 492 | refcount is incremented. Therefore, we increment it here, so | ||
| 493 | that free_frame_faces, called in x_free_frame_resources | ||
| 494 | below, will not mistakenly decrement the counter that was not | ||
| 495 | incremented yet to account for this new frame. */ | ||
| 496 | if (FRAME_IMAGE_CACHE (f) != NULL | ||
| 497 | && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount) | ||
| 498 | FRAME_IMAGE_CACHE (f)->refcount++; | ||
| 499 | |||
| 500 | android_free_frame_resources (f); | ||
| 501 | free_glyphs (f); | ||
| 502 | return Qt; | ||
| 503 | } | ||
| 504 | |||
| 505 | return Qnil; | ||
| 506 | } | ||
| 507 | |||
| 508 | static void | ||
| 509 | do_unwind_create_frame (Lisp_Object frame) | ||
| 510 | { | ||
| 511 | unwind_create_frame (frame); | ||
| 512 | } | ||
| 513 | |||
| 514 | void | ||
| 515 | android_default_font_parameter (struct frame *f, Lisp_Object parms) | ||
| 516 | { | ||
| 517 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 518 | Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL, | ||
| 519 | RES_TYPE_STRING); | ||
| 520 | Lisp_Object font = Qnil; | ||
| 521 | if (BASE_EQ (font_param, Qunbound)) | ||
| 522 | font_param = Qnil; | ||
| 523 | |||
| 524 | if (NILP (font)) | ||
| 525 | font = (!NILP (font_param) | ||
| 526 | ? font_param | ||
| 527 | : gui_display_get_arg (dpyinfo, parms, | ||
| 528 | Qfont, "font", "Font", | ||
| 529 | RES_TYPE_STRING)); | ||
| 530 | |||
| 531 | if (! FONTP (font) && ! STRINGP (font)) | ||
| 532 | { | ||
| 533 | const char *names[] = { | ||
| 534 | /* This will find the normal font. */ | ||
| 535 | "DroidSansMono", | ||
| 536 | "monospace", | ||
| 537 | NULL | ||
| 538 | }; | ||
| 539 | int i; | ||
| 540 | |||
| 541 | for (i = 0; names[i]; i++) | ||
| 542 | { | ||
| 543 | font = font_open_by_name (f, build_unibyte_string (names[i])); | ||
| 544 | if (! NILP (font)) | ||
| 545 | break; | ||
| 546 | } | ||
| 547 | |||
| 548 | if (NILP (font)) | ||
| 549 | error ("No suitable font was found"); | ||
| 550 | } | ||
| 551 | |||
| 552 | gui_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING); | ||
| 553 | } | ||
| 554 | |||
| 555 | static void | ||
| 556 | android_create_frame_window (struct frame *f) | ||
| 557 | { | ||
| 558 | struct android_set_window_attributes attributes; | ||
| 559 | enum android_window_value_mask attribute_mask; | ||
| 560 | |||
| 561 | attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 562 | attribute_mask = ANDROID_CW_BACK_PIXEL; | ||
| 563 | |||
| 564 | block_input (); | ||
| 565 | FRAME_ANDROID_WINDOW (f) | ||
| 566 | = android_create_window (FRAME_DISPLAY_INFO (f)->root_window, | ||
| 567 | f->left_pos, | ||
| 568 | f->top_pos, | ||
| 569 | FRAME_PIXEL_WIDTH (f), | ||
| 570 | FRAME_PIXEL_HEIGHT (f), | ||
| 571 | attribute_mask, &attributes); | ||
| 572 | unblock_input (); | ||
| 573 | } | ||
| 574 | |||
| 575 | #endif /* ANDROID_STUBIFY */ | ||
| 576 | |||
| 577 | |||
| 578 | |||
| 579 | DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, | ||
| 580 | 1, 1, 0, | ||
| 581 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 582 | (Lisp_Object parms) | ||
| 583 | { | ||
| 584 | #ifdef ANDROID_STUBIFY | ||
| 585 | error ("Android cross-compilation stub called!"); | ||
| 586 | return Qnil; | ||
| 587 | #else | ||
| 588 | struct frame *f; | ||
| 589 | Lisp_Object frame, tem; | ||
| 590 | Lisp_Object name; | ||
| 591 | bool minibuffer_only; | ||
| 592 | bool undecorated, override_redirect; | ||
| 593 | long window_prompting; | ||
| 594 | specpdl_ref count; | ||
| 595 | Lisp_Object display; | ||
| 596 | struct android_display_info *dpyinfo; | ||
| 597 | Lisp_Object parent, parent_frame; | ||
| 598 | struct kboard *kb; | ||
| 599 | |||
| 600 | minibuffer_only = false; | ||
| 601 | undecorated = false; | ||
| 602 | override_redirect = false; | ||
| 603 | window_prompting = 0; | ||
| 604 | count = SPECPDL_INDEX (); | ||
| 605 | dpyinfo = NULL; | ||
| 606 | |||
| 607 | /* Not actually used, but be consistent with X. */ | ||
| 608 | ((void) window_prompting); | ||
| 609 | |||
| 610 | parms = Fcopy_alist (parms); | ||
| 611 | |||
| 612 | /* Use this general default value to start with | ||
| 613 | until we know if this frame has a specified name. */ | ||
| 614 | Vx_resource_name = Vinvocation_name; | ||
| 615 | |||
| 616 | display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, | ||
| 617 | RES_TYPE_NUMBER); | ||
| 618 | if (BASE_EQ (display, Qunbound)) | ||
| 619 | display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, | ||
| 620 | RES_TYPE_STRING); | ||
| 621 | if (BASE_EQ (display, Qunbound)) | ||
| 622 | display = Qnil; | ||
| 623 | dpyinfo = check_android_display_info (display); | ||
| 624 | kb = dpyinfo->terminal->kboard; | ||
| 625 | |||
| 626 | if (!dpyinfo->terminal->name) | ||
| 627 | error ("Terminal is not live, can't create new frames on it"); | ||
| 628 | |||
| 629 | name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", | ||
| 630 | RES_TYPE_STRING); | ||
| 631 | if (!STRINGP (name) | ||
| 632 | && ! BASE_EQ (name, Qunbound) | ||
| 633 | && ! NILP (name)) | ||
| 634 | error ("Invalid frame name--not a string or nil"); | ||
| 635 | |||
| 636 | if (STRINGP (name)) | ||
| 637 | Vx_resource_name = name; | ||
| 638 | |||
| 639 | /* See if parent window is specified. */ | ||
| 640 | parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, | ||
| 641 | RES_TYPE_NUMBER); | ||
| 642 | if (BASE_EQ (parent, Qunbound)) | ||
| 643 | parent = Qnil; | ||
| 644 | if (! NILP (parent)) | ||
| 645 | CHECK_FIXNUM (parent); | ||
| 646 | |||
| 647 | frame = Qnil; | ||
| 648 | tem = gui_display_get_arg (dpyinfo, | ||
| 649 | parms, Qminibuffer, "minibuffer", "Minibuffer", | ||
| 650 | RES_TYPE_SYMBOL); | ||
| 651 | if (EQ (tem, Qnone) || NILP (tem)) | ||
| 652 | f = make_frame_without_minibuffer (Qnil, kb, display); | ||
| 653 | else if (EQ (tem, Qonly)) | ||
| 654 | { | ||
| 655 | f = make_minibuffer_frame (); | ||
| 656 | minibuffer_only = true; | ||
| 657 | } | ||
| 658 | else if (WINDOWP (tem)) | ||
| 659 | f = make_frame_without_minibuffer (tem, kb, display); | ||
| 660 | else | ||
| 661 | f = make_frame (true); | ||
| 662 | |||
| 663 | parent_frame = gui_display_get_arg (dpyinfo, | ||
| 664 | parms, | ||
| 665 | Qparent_frame, | ||
| 666 | NULL, | ||
| 667 | NULL, | ||
| 668 | RES_TYPE_SYMBOL); | ||
| 669 | /* Accept parent-frame iff parent-id was not specified. */ | ||
| 670 | if (!NILP (parent) | ||
| 671 | || BASE_EQ (parent_frame, Qunbound) | ||
| 672 | || NILP (parent_frame) | ||
| 673 | || !FRAMEP (parent_frame) | ||
| 674 | || !FRAME_LIVE_P (XFRAME (parent_frame)) | ||
| 675 | || !FRAME_ANDROID_P (XFRAME (parent_frame))) | ||
| 676 | parent_frame = Qnil; | ||
| 677 | |||
| 678 | fset_parent_frame (f, parent_frame); | ||
| 679 | store_frame_param (f, Qparent_frame, parent_frame); | ||
| 680 | |||
| 681 | if (!NILP (tem = (gui_display_get_arg (dpyinfo, | ||
| 682 | parms, | ||
| 683 | Qundecorated, | ||
| 684 | NULL, | ||
| 685 | NULL, | ||
| 686 | RES_TYPE_BOOLEAN))) | ||
| 687 | && !(BASE_EQ (tem, Qunbound))) | ||
| 688 | undecorated = true; | ||
| 689 | |||
| 690 | FRAME_UNDECORATED (f) = undecorated; | ||
| 691 | store_frame_param (f, Qundecorated, undecorated ? Qt : Qnil); | ||
| 692 | |||
| 693 | if (!NILP (tem = (gui_display_get_arg (dpyinfo, | ||
| 694 | parms, | ||
| 695 | Qoverride_redirect, | ||
| 696 | NULL, | ||
| 697 | NULL, | ||
| 698 | RES_TYPE_BOOLEAN))) | ||
| 699 | && !(BASE_EQ (tem, Qunbound))) | ||
| 700 | override_redirect = true; | ||
| 701 | |||
| 702 | FRAME_OVERRIDE_REDIRECT (f) = override_redirect; | ||
| 703 | store_frame_param (f, Qoverride_redirect, override_redirect ? Qt : Qnil); | ||
| 704 | |||
| 705 | XSETFRAME (frame, f); | ||
| 706 | |||
| 707 | f->terminal = dpyinfo->terminal; | ||
| 708 | |||
| 709 | f->output_method = output_android; | ||
| 710 | f->output_data.android = xzalloc (sizeof *f->output_data.android); | ||
| 711 | FRAME_FONTSET (f) = -1; | ||
| 712 | f->output_data.android->scroll_bar_foreground_pixel = -1; | ||
| 713 | f->output_data.android->scroll_bar_background_pixel = -1; | ||
| 714 | f->output_data.android->white_relief.pixel = -1; | ||
| 715 | f->output_data.android->black_relief.pixel = -1; | ||
| 716 | |||
| 717 | fset_icon_name (f, gui_display_get_arg (dpyinfo, | ||
| 718 | parms, | ||
| 719 | Qicon_name, | ||
| 720 | "iconName", | ||
| 721 | "Title", | ||
| 722 | RES_TYPE_STRING)); | ||
| 723 | if (! STRINGP (f->icon_name)) | ||
| 724 | fset_icon_name (f, Qnil); | ||
| 725 | |||
| 726 | FRAME_DISPLAY_INFO (f) = dpyinfo; | ||
| 727 | |||
| 728 | /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ | ||
| 729 | record_unwind_protect (do_unwind_create_frame, frame); | ||
| 730 | |||
| 731 | /* These colors will be set anyway later, but it's important | ||
| 732 | to get the color reference counts right, so initialize them! | ||
| 733 | |||
| 734 | (Not really on Android, but it's best to be consistent with | ||
| 735 | X.) */ | ||
| 736 | { | ||
| 737 | Lisp_Object black; | ||
| 738 | |||
| 739 | /* Function x_decode_color can signal an error. Make | ||
| 740 | sure to initialize color slots so that we won't try | ||
| 741 | to free colors we haven't allocated. */ | ||
| 742 | FRAME_FOREGROUND_PIXEL (f) = -1; | ||
| 743 | FRAME_BACKGROUND_PIXEL (f) = -1; | ||
| 744 | f->output_data.android->cursor_pixel = -1; | ||
| 745 | f->output_data.android->cursor_foreground_pixel = -1; | ||
| 746 | |||
| 747 | black = build_string ("black"); | ||
| 748 | FRAME_FOREGROUND_PIXEL (f) | ||
| 749 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 750 | FRAME_BACKGROUND_PIXEL (f) | ||
| 751 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 752 | f->output_data.android->cursor_pixel | ||
| 753 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 754 | f->output_data.android->cursor_foreground_pixel | ||
| 755 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 756 | } | ||
| 757 | |||
| 758 | /* Set the name; the functions to which we pass f expect the name to | ||
| 759 | be set. */ | ||
| 760 | if (BASE_EQ (name, Qunbound) || NILP (name)) | ||
| 761 | { | ||
| 762 | fset_name (f, build_string ("GNU Emacs")); | ||
| 763 | f->explicit_name = false; | ||
| 764 | } | ||
| 765 | else | ||
| 766 | { | ||
| 767 | fset_name (f, name); | ||
| 768 | f->explicit_name = true; | ||
| 769 | /* Use the frame's title when getting resources for this frame. */ | ||
| 770 | specbind (Qx_resource_name, name); | ||
| 771 | } | ||
| 772 | |||
| 773 | register_font_driver (&androidfont_driver, f); | ||
| 774 | |||
| 775 | image_cache_refcount = (FRAME_IMAGE_CACHE (f) | ||
| 776 | ? FRAME_IMAGE_CACHE (f)->refcount | ||
| 777 | : 0); | ||
| 778 | |||
| 779 | gui_default_parameter (f, parms, Qfont_backend, Qnil, | ||
| 780 | "fontBackend", "FontBackend", RES_TYPE_STRING); | ||
| 781 | |||
| 782 | /* Extract the window parameters from the supplied values | ||
| 783 | that are needed to determine window geometry. */ | ||
| 784 | android_default_font_parameter (f, parms); | ||
| 785 | if (!FRAME_FONT (f)) | ||
| 786 | { | ||
| 787 | delete_frame (frame, Qnoelisp); | ||
| 788 | error ("Invalid frame font"); | ||
| 789 | } | ||
| 790 | |||
| 791 | if (NILP (Fassq (Qinternal_border_width, parms))) | ||
| 792 | { | ||
| 793 | Lisp_Object value; | ||
| 794 | |||
| 795 | value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, | ||
| 796 | "internalBorder", "internalBorder", | ||
| 797 | RES_TYPE_NUMBER); | ||
| 798 | if (! BASE_EQ (value, Qunbound)) | ||
| 799 | parms = Fcons (Fcons (Qinternal_border_width, value), | ||
| 800 | parms); | ||
| 801 | } | ||
| 802 | |||
| 803 | gui_default_parameter (f, parms, Qinternal_border_width, | ||
| 804 | make_fixnum (0), | ||
| 805 | "internalBorderWidth", "internalBorderWidth", | ||
| 806 | RES_TYPE_NUMBER); | ||
| 807 | |||
| 808 | /* Same for child frames. */ | ||
| 809 | if (NILP (Fassq (Qchild_frame_border_width, parms))) | ||
| 810 | { | ||
| 811 | Lisp_Object value; | ||
| 812 | |||
| 813 | value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width, | ||
| 814 | "childFrameBorder", "childFrameBorder", | ||
| 815 | RES_TYPE_NUMBER); | ||
| 816 | if (! BASE_EQ (value, Qunbound)) | ||
| 817 | parms = Fcons (Fcons (Qchild_frame_border_width, value), | ||
| 818 | parms); | ||
| 819 | } | ||
| 820 | |||
| 821 | gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil, | ||
| 822 | "childFrameBorderWidth", "childFrameBorderWidth", | ||
| 823 | RES_TYPE_NUMBER); | ||
| 824 | gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0), | ||
| 825 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 826 | gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), | ||
| 827 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 828 | |||
| 829 | /* gui_default_parameter (f, parms, Qvertical_scroll_bars, */ | ||
| 830 | /* Qleft, */ | ||
| 831 | /* "verticalScrollBars", "ScrollBars", */ | ||
| 832 | /* RES_TYPE_SYMBOL); */ | ||
| 833 | /* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */ | ||
| 834 | /* "horizontalScrollBars", "ScrollBars", */ | ||
| 835 | /* RES_TYPE_SYMBOL); TODO */ | ||
| 836 | |||
| 837 | /* Also do the stuff which must be set before the window exists. */ | ||
| 838 | gui_default_parameter (f, parms, Qforeground_color, build_string ("black"), | ||
| 839 | "foreground", "Foreground", RES_TYPE_STRING); | ||
| 840 | gui_default_parameter (f, parms, Qbackground_color, build_string ("white"), | ||
| 841 | "background", "Background", RES_TYPE_STRING); | ||
| 842 | gui_default_parameter (f, parms, Qmouse_color, build_string ("black"), | ||
| 843 | "pointerColor", "Foreground", RES_TYPE_STRING); | ||
| 844 | gui_default_parameter (f, parms, Qborder_color, build_string ("black"), | ||
| 845 | "borderColor", "BorderColor", RES_TYPE_STRING); | ||
| 846 | gui_default_parameter (f, parms, Qscreen_gamma, Qnil, | ||
| 847 | "screenGamma", "ScreenGamma", RES_TYPE_FLOAT); | ||
| 848 | gui_default_parameter (f, parms, Qline_spacing, Qnil, | ||
| 849 | "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); | ||
| 850 | gui_default_parameter (f, parms, Qleft_fringe, Qnil, | ||
| 851 | "leftFringe", "LeftFringe", RES_TYPE_NUMBER); | ||
| 852 | gui_default_parameter (f, parms, Qright_fringe, Qnil, | ||
| 853 | "rightFringe", "RightFringe", RES_TYPE_NUMBER); | ||
| 854 | gui_default_parameter (f, parms, Qno_special_glyphs, Qnil, | ||
| 855 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 856 | |||
| 857 | #if 0 | ||
| 858 | android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, | ||
| 859 | "scrollBarForeground", | ||
| 860 | "ScrollBarForeground", true); | ||
| 861 | android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background, | ||
| 862 | "scrollBarBackground", | ||
| 863 | "ScrollBarBackground", false); | ||
| 864 | #endif /* TODO */ | ||
| 865 | |||
| 866 | /* Init faces before gui_default_parameter is called for the | ||
| 867 | scroll-bar-width parameter because otherwise we end up in | ||
| 868 | init_iterator with a null face cache, which should not | ||
| 869 | happen. */ | ||
| 870 | |||
| 871 | init_frame_faces (f); | ||
| 872 | |||
| 873 | tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, | ||
| 874 | RES_TYPE_NUMBER); | ||
| 875 | if (FIXNUMP (tem)) | ||
| 876 | store_frame_param (f, Qmin_width, tem); | ||
| 877 | tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, | ||
| 878 | RES_TYPE_NUMBER); | ||
| 879 | if (FIXNUMP (tem)) | ||
| 880 | store_frame_param (f, Qmin_height, tem); | ||
| 881 | |||
| 882 | adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), | ||
| 883 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true, | ||
| 884 | Qx_create_frame_1); | ||
| 885 | |||
| 886 | /* Set the menu-bar-lines and tool-bar-lines parameters. We don't | ||
| 887 | look up the X resources controlling the menu-bar and tool-bar | ||
| 888 | here; they are processed specially at startup, and reflected in | ||
| 889 | the values of the mode variables. */ | ||
| 890 | |||
| 891 | gui_default_parameter (f, parms, Qmenu_bar_lines, | ||
| 892 | NILP (Vmenu_bar_mode) | ||
| 893 | ? make_fixnum (0) : make_fixnum (1), | ||
| 894 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 895 | gui_default_parameter (f, parms, Qtab_bar_lines, | ||
| 896 | NILP (Vtab_bar_mode) | ||
| 897 | ? make_fixnum (0) : make_fixnum (1), | ||
| 898 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 899 | gui_default_parameter (f, parms, Qtool_bar_lines, | ||
| 900 | NILP (Vtool_bar_mode) | ||
| 901 | ? make_fixnum (0) : make_fixnum (1), | ||
| 902 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 903 | |||
| 904 | gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, | ||
| 905 | "bufferPredicate", "BufferPredicate", | ||
| 906 | RES_TYPE_SYMBOL); | ||
| 907 | gui_default_parameter (f, parms, Qtitle, Qnil, | ||
| 908 | "title", "Title", RES_TYPE_STRING); | ||
| 909 | gui_default_parameter (f, parms, Qwait_for_wm, Qt, | ||
| 910 | "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); | ||
| 911 | gui_default_parameter (f, parms, Qtool_bar_position, | ||
| 912 | FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL); | ||
| 913 | gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil, | ||
| 914 | "inhibitDoubleBuffering", "InhibitDoubleBuffering", | ||
| 915 | RES_TYPE_BOOLEAN); | ||
| 916 | |||
| 917 | /* Compute the size of the X window. */ | ||
| 918 | window_prompting = gui_figure_window_size (f, parms, true, true); | ||
| 919 | |||
| 920 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, | ||
| 921 | RES_TYPE_BOOLEAN); | ||
| 922 | f->no_split = minibuffer_only || EQ (tem, Qt); | ||
| 923 | |||
| 924 | android_icon_verify (f, parms); | ||
| 925 | android_create_frame_window (f); | ||
| 926 | android_icon (f, parms); | ||
| 927 | android_make_gc (f); | ||
| 928 | |||
| 929 | /* Now consider the frame official. */ | ||
| 930 | f->terminal->reference_count++; | ||
| 931 | Vframe_list = Fcons (frame, Vframe_list); | ||
| 932 | |||
| 933 | /* We need to do this after creating the window, so that the | ||
| 934 | icon-creation functions can say whose icon they're | ||
| 935 | describing. */ | ||
| 936 | gui_default_parameter (f, parms, Qicon_type, Qt, | ||
| 937 | "bitmapIcon", "BitmapIcon", RES_TYPE_BOOLEAN); | ||
| 938 | |||
| 939 | gui_default_parameter (f, parms, Qauto_raise, Qnil, | ||
| 940 | "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); | ||
| 941 | gui_default_parameter (f, parms, Qauto_lower, Qnil, | ||
| 942 | "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); | ||
| 943 | gui_default_parameter (f, parms, Qcursor_type, Qbox, | ||
| 944 | "cursorType", "CursorType", RES_TYPE_SYMBOL); | ||
| 945 | gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, | ||
| 946 | "scrollBarWidth", "ScrollBarWidth", | ||
| 947 | RES_TYPE_NUMBER); | ||
| 948 | gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, | ||
| 949 | "scrollBarHeight", "ScrollBarHeight", | ||
| 950 | RES_TYPE_NUMBER); | ||
| 951 | gui_default_parameter (f, parms, Qalpha, Qnil, | ||
| 952 | "alpha", "Alpha", RES_TYPE_NUMBER); | ||
| 953 | gui_default_parameter (f, parms, Qalpha_background, Qnil, | ||
| 954 | "alphaBackground", "AlphaBackground", RES_TYPE_NUMBER); | ||
| 955 | |||
| 956 | if (!NILP (parent_frame)) | ||
| 957 | { | ||
| 958 | struct frame *p = XFRAME (parent_frame); | ||
| 959 | |||
| 960 | block_input (); | ||
| 961 | android_reparent_window (FRAME_ANDROID_WINDOW (f), | ||
| 962 | FRAME_ANDROID_WINDOW (p), | ||
| 963 | f->left_pos, f->top_pos); | ||
| 964 | unblock_input (); | ||
| 965 | } | ||
| 966 | |||
| 967 | gui_default_parameter (f, parms, Qno_focus_on_map, Qnil, | ||
| 968 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 969 | gui_default_parameter (f, parms, Qno_accept_focus, Qnil, | ||
| 970 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 971 | |||
| 972 | /* Consider frame official, now. */ | ||
| 973 | f->can_set_window_size = true; | ||
| 974 | |||
| 975 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 976 | 0, true, Qx_create_frame_2); | ||
| 977 | |||
| 978 | /* Process fullscreen parameter here in the hope that normalizing a | ||
| 979 | fullheight/fullwidth frame will produce the size set by the last | ||
| 980 | adjust_frame_size call. */ | ||
| 981 | gui_default_parameter (f, parms, Qfullscreen, Qnil, | ||
| 982 | "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); | ||
| 983 | |||
| 984 | /* When called from `x-create-frame-with-faces' visibility is | ||
| 985 | always explicitly nil. */ | ||
| 986 | Lisp_Object visibility | ||
| 987 | = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0, | ||
| 988 | RES_TYPE_SYMBOL); | ||
| 989 | Lisp_Object height | ||
| 990 | = gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); | ||
| 991 | Lisp_Object width | ||
| 992 | = gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); | ||
| 993 | |||
| 994 | if (EQ (visibility, Qicon)) | ||
| 995 | { | ||
| 996 | f->was_invisible = true; | ||
| 997 | android_iconify_frame (f); | ||
| 998 | } | ||
| 999 | else | ||
| 1000 | { | ||
| 1001 | if (BASE_EQ (visibility, Qunbound)) | ||
| 1002 | visibility = Qt; | ||
| 1003 | |||
| 1004 | if (!NILP (visibility)) | ||
| 1005 | android_make_frame_visible (f); | ||
| 1006 | else | ||
| 1007 | f->was_invisible = true; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | /* Leave f->was_invisible true only if height or width were | ||
| 1011 | specified too. This takes effect only when we are not called | ||
| 1012 | from `x-create-frame-with-faces' (see above comment). */ | ||
| 1013 | f->was_invisible | ||
| 1014 | = (f->was_invisible | ||
| 1015 | && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound))); | ||
| 1016 | |||
| 1017 | store_frame_param (f, Qvisibility, visibility); | ||
| 1018 | |||
| 1019 | /* Set whether or not frame synchronization is enabled. */ | ||
| 1020 | gui_default_parameter (f, parms, Quse_frame_synchronization, Qt, | ||
| 1021 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 1022 | |||
| 1023 | /* Works iff frame has been already mapped. */ | ||
| 1024 | gui_default_parameter (f, parms, Qskip_taskbar, Qnil, | ||
| 1025 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 1026 | /* The `z-group' parameter works only for visible frames. */ | ||
| 1027 | gui_default_parameter (f, parms, Qz_group, Qnil, | ||
| 1028 | NULL, NULL, RES_TYPE_SYMBOL); | ||
| 1029 | |||
| 1030 | /* Initialize `default-minibuffer-frame' in case this is the first | ||
| 1031 | frame on this terminal. */ | ||
| 1032 | if (FRAME_HAS_MINIBUF_P (f) | ||
| 1033 | && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) | ||
| 1034 | || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) | ||
| 1035 | kset_default_minibuffer_frame (kb, frame); | ||
| 1036 | |||
| 1037 | /* All remaining specified parameters, which have not been "used" by | ||
| 1038 | gui_display_get_arg and friends, now go in the misc. alist of the | ||
| 1039 | frame. */ | ||
| 1040 | for (tem = parms; CONSP (tem); tem = XCDR (tem)) | ||
| 1041 | if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) | ||
| 1042 | fset_param_alist (f, Fcons (XCAR (tem), f->param_alist)); | ||
| 1043 | |||
| 1044 | /* Make sure windows on this frame appear in calls to next-window | ||
| 1045 | and similar functions. */ | ||
| 1046 | Vwindow_list = Qnil; | ||
| 1047 | |||
| 1048 | return unbind_to (count, frame); | ||
| 1049 | #endif | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, | ||
| 1053 | 1, 2, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1054 | (Lisp_Object color, Lisp_Object frame) | ||
| 1055 | { | ||
| 1056 | #ifdef ANDROID_STUBIFY | ||
| 1057 | error ("Android cross-compilation stub called!"); | ||
| 1058 | return Qnil; | ||
| 1059 | #else | ||
| 1060 | Emacs_Color foo; | ||
| 1061 | struct frame *f; | ||
| 1062 | |||
| 1063 | f = decode_window_system_frame (frame); | ||
| 1064 | |||
| 1065 | CHECK_STRING (color); | ||
| 1066 | |||
| 1067 | if (android_defined_color (f, SSDATA (color), &foo, false, false)) | ||
| 1068 | return Qt; | ||
| 1069 | else | ||
| 1070 | return Qnil; | ||
| 1071 | #endif | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, | ||
| 1075 | 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1076 | (Lisp_Object color, Lisp_Object frame) | ||
| 1077 | { | ||
| 1078 | #ifdef ANDROID_STUBIFY | ||
| 1079 | error ("Android cross-compilation stub called!"); | ||
| 1080 | return Qnil; | ||
| 1081 | #else | ||
| 1082 | Emacs_Color foo; | ||
| 1083 | struct frame *f; | ||
| 1084 | |||
| 1085 | f = decode_window_system_frame (frame); | ||
| 1086 | |||
| 1087 | CHECK_STRING (color); | ||
| 1088 | |||
| 1089 | if (android_defined_color (f, SSDATA (color), &foo, false, false)) | ||
| 1090 | return list3i (foo.red, foo.green, foo.blue); | ||
| 1091 | else | ||
| 1092 | return Qnil; | ||
| 1093 | #endif | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | DEFUN ("xw-display-color-p", Fxw_display_color_p, | ||
| 1097 | Sxw_display_color_p, 0, 1, 0, | ||
| 1098 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1099 | (Lisp_Object terminal) | ||
| 1100 | { | ||
| 1101 | return Qt; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, | ||
| 1105 | Sx_display_grayscale_p, 0, 1, 0, | ||
| 1106 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1107 | (Lisp_Object terminal) | ||
| 1108 | { | ||
| 1109 | return Qnil; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | DEFUN ("x-display-pixel-width", Fx_display_pixel_width, | ||
| 1113 | Sx_display_pixel_width, 0, 1, 0, | ||
| 1114 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1115 | (Lisp_Object terminal) | ||
| 1116 | { | ||
| 1117 | #ifdef ANDROID_STUBIFY | ||
| 1118 | error ("Android cross-compilation stub called!"); | ||
| 1119 | return Qnil; | ||
| 1120 | #else | ||
| 1121 | error ("Not implemented"); | ||
| 1122 | return Qnil; | ||
| 1123 | #endif | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | DEFUN ("x-display-pixel-height", Fx_display_pixel_height, | ||
| 1127 | Sx_display_pixel_height, 0, 1, 0, | ||
| 1128 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1129 | (Lisp_Object terminal) | ||
| 1130 | { | ||
| 1131 | #ifdef ANDROID_STUBIFY | ||
| 1132 | error ("Android cross-compilation stub called!"); | ||
| 1133 | return Qnil; | ||
| 1134 | #else | ||
| 1135 | error ("Not implemented"); | ||
| 1136 | return Qnil; | ||
| 1137 | #endif | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, | ||
| 1141 | 0, 1, 0, | ||
| 1142 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1143 | (Lisp_Object terminal) | ||
| 1144 | { | ||
| 1145 | struct android_display_info *dpyinfo; | ||
| 1146 | |||
| 1147 | dpyinfo = check_android_display_info (terminal); | ||
| 1148 | |||
| 1149 | return make_fixnum (dpyinfo->n_planes); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, | ||
| 1153 | 0, 1, 0, | ||
| 1154 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1155 | (Lisp_Object terminal) | ||
| 1156 | { | ||
| 1157 | struct android_display_info *dpyinfo; | ||
| 1158 | int nr_planes; | ||
| 1159 | |||
| 1160 | dpyinfo = check_android_display_info (terminal); | ||
| 1161 | nr_planes = dpyinfo->n_planes; | ||
| 1162 | |||
| 1163 | /* Truncate nr_planes to 24 to avoid integer overflow. */ | ||
| 1164 | |||
| 1165 | if (nr_planes > 24) | ||
| 1166 | nr_planes = 24; | ||
| 1167 | |||
| 1168 | return make_fixnum (1 << nr_planes); | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, | ||
| 1172 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1173 | (Lisp_Object terminal) | ||
| 1174 | { | ||
| 1175 | check_android_display_info (terminal); | ||
| 1176 | return make_fixnum (1); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, | ||
| 1180 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1181 | (Lisp_Object terminal) | ||
| 1182 | { | ||
| 1183 | #ifdef ANDROID_STUBIFY | ||
| 1184 | error ("Android cross-compilation stub called!"); | ||
| 1185 | return Qnil; | ||
| 1186 | #else | ||
| 1187 | error ("Not implemented"); | ||
| 1188 | return Qnil; | ||
| 1189 | #endif | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, | ||
| 1193 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1194 | (Lisp_Object terminal) | ||
| 1195 | { | ||
| 1196 | #ifdef ANDROID_STUBIFY | ||
| 1197 | error ("Android cross-compilation stub called!"); | ||
| 1198 | return Qnil; | ||
| 1199 | #else | ||
| 1200 | error ("Not implemented"); | ||
| 1201 | return Qnil; | ||
| 1202 | #endif | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | DEFUN ("x-display-backing-store", Fx_display_backing_store, | ||
| 1206 | Sx_display_backing_store, 0, 1, 0, | ||
| 1207 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1208 | (Lisp_Object terminal) | ||
| 1209 | { | ||
| 1210 | check_android_display_info (terminal); | ||
| 1211 | |||
| 1212 | /* The Java part is implemented in a way that it always does the | ||
| 1213 | equivalent of backing store. */ | ||
| 1214 | return Qalways; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | DEFUN ("x-display-visual-class", Fx_display_visual_class, | ||
| 1218 | Sx_display_visual_class, 0, 1, 0, | ||
| 1219 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1220 | (Lisp_Object terminal) | ||
| 1221 | { | ||
| 1222 | check_android_display_info (terminal); | ||
| 1223 | |||
| 1224 | return Qtrue_color; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list, | ||
| 1228 | Sx_display_monitor_attributes_list, | ||
| 1229 | 0, 1, 0, | ||
| 1230 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1231 | (Lisp_Object terminal) | ||
| 1232 | { | ||
| 1233 | #ifdef ANDROID_STUBIFY | ||
| 1234 | error ("Android cross-compilation stub called!"); | ||
| 1235 | return Qnil; | ||
| 1236 | #else | ||
| 1237 | error ("Not implemented"); | ||
| 1238 | return Qnil; | ||
| 1239 | #endif | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | DEFUN ("x-frame-geometry", Fx_frame_geometry, Sx_frame_geometry, | ||
| 1243 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1244 | (Lisp_Object terminal) | ||
| 1245 | { | ||
| 1246 | #ifdef ANDROID_STUBIFY | ||
| 1247 | error ("Android cross-compilation stub called!"); | ||
| 1248 | return Qnil; | ||
| 1249 | #else | ||
| 1250 | error ("Not implemented"); | ||
| 1251 | return Qnil; | ||
| 1252 | #endif | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | DEFUN ("x-frame-list-z-order", Fx_frame_list_z_order, | ||
| 1256 | Sx_frame_list_z_order, 0, 1, 0, | ||
| 1257 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1258 | (Lisp_Object terminal) | ||
| 1259 | { | ||
| 1260 | #ifdef ANDROID_STUBIFY | ||
| 1261 | error ("Android cross-compilation stub called!"); | ||
| 1262 | return Qnil; | ||
| 1263 | #else | ||
| 1264 | error ("Not implemented"); | ||
| 1265 | return Qnil; | ||
| 1266 | #endif | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | DEFUN ("x-frame-restack", Fx_frame_restack, Sx_frame_restack, 2, 3, 0, | ||
| 1270 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1271 | (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object frame3) | ||
| 1272 | { | ||
| 1273 | #ifdef ANDROID_STUBIFY | ||
| 1274 | error ("Android cross-compilation stub called!"); | ||
| 1275 | return Qnil; | ||
| 1276 | #else | ||
| 1277 | error ("Not implemented"); | ||
| 1278 | return Qnil; | ||
| 1279 | #endif | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | DEFUN ("x-mouse-absolute-pixel-position", Fx_mouse_absolute_pixel_position, | ||
| 1283 | Sx_mouse_absolute_pixel_position, 0, 0, 0, | ||
| 1284 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1285 | (void) | ||
| 1286 | { | ||
| 1287 | /* TODO: figure out how to implement this. */ | ||
| 1288 | return Qnil; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | DEFUN ("x-set-mouse-absolute-pixel-position", | ||
| 1292 | Fx_set_mouse_absolute_pixel_position, | ||
| 1293 | Sx_set_mouse_absolute_pixel_position, 2, 2, 0, | ||
| 1294 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1295 | (Lisp_Object x, Lisp_Object y) | ||
| 1296 | { | ||
| 1297 | /* TODO: figure out how to implement this. */ | ||
| 1298 | return Qnil; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | DEFUN ("android-get-connection", Fandroid_get_connection, | ||
| 1302 | Sandroid_get_connection, 0, 0, 0, | ||
| 1303 | doc: /* Get the connection to the display server. | ||
| 1304 | Return the terminal if it exists, else nil. | ||
| 1305 | |||
| 1306 | Emacs cannot open a connection to the display server itself under | ||
| 1307 | Android, so there is no equivalent of `x-open-connection'. */) | ||
| 1308 | (void) | ||
| 1309 | { | ||
| 1310 | #ifdef ANDROID_STUBIFY | ||
| 1311 | error ("Android cross-compilation stub called!"); | ||
| 1312 | return Qnil; | ||
| 1313 | #else | ||
| 1314 | Lisp_Object terminal; | ||
| 1315 | |||
| 1316 | terminal = Qnil; | ||
| 1317 | |||
| 1318 | if (x_display_list) | ||
| 1319 | XSETTERMINAL (terminal, x_display_list->terminal); | ||
| 1320 | |||
| 1321 | return terminal; | ||
| 1322 | #endif | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, | ||
| 1326 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1327 | (void) | ||
| 1328 | { | ||
| 1329 | Lisp_Object result; | ||
| 1330 | |||
| 1331 | result = Qnil; | ||
| 1332 | |||
| 1333 | if (x_display_list) | ||
| 1334 | result = Fcons (XCAR (x_display_list->name_list_element), | ||
| 1335 | result); | ||
| 1336 | |||
| 1337 | return result; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, | ||
| 1341 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1342 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, | ||
| 1343 | Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) | ||
| 1344 | { | ||
| 1345 | #ifdef ANDROID_STUBIFY | ||
| 1346 | error ("Android cross-compilation stub called!"); | ||
| 1347 | return Qnil; | ||
| 1348 | #else | ||
| 1349 | error ("Not implemented"); | ||
| 1350 | return Qnil; | ||
| 1351 | #endif | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, | ||
| 1355 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1356 | (void) | ||
| 1357 | { | ||
| 1358 | #ifdef ANDROID_STUBIFY | ||
| 1359 | error ("Android cross-compilation stub called!"); | ||
| 1360 | return Qnil; | ||
| 1361 | #else | ||
| 1362 | error ("Not implemented"); | ||
| 1363 | return Qnil; | ||
| 1364 | #endif | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | |||
| 1368 | |||
| 1369 | #ifndef ANDROID_STUBIFY | ||
| 1370 | |||
| 1371 | static void | ||
| 1372 | android_set_background_color (struct frame *f, Lisp_Object arg, | ||
| 1373 | Lisp_Object oldval) | ||
| 1374 | { | ||
| 1375 | struct android_output *x; | ||
| 1376 | unsigned long bg; | ||
| 1377 | |||
| 1378 | x = f->output_data.android; | ||
| 1379 | bg = android_decode_color (f, arg, WHITE_PIX_DEFAULT (f)); | ||
| 1380 | FRAME_BACKGROUND_PIXEL (f) = bg; | ||
| 1381 | |||
| 1382 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1383 | { | ||
| 1384 | block_input (); | ||
| 1385 | android_set_background (x->normal_gc, bg); | ||
| 1386 | android_set_foreground (x->reverse_gc, bg); | ||
| 1387 | android_set_window_background (FRAME_ANDROID_WINDOW (f), bg); | ||
| 1388 | android_set_foreground (x->cursor_gc, bg); | ||
| 1389 | unblock_input (); | ||
| 1390 | |||
| 1391 | update_face_from_frame_parameter (f, Qbackground_color, arg); | ||
| 1392 | |||
| 1393 | if (FRAME_VISIBLE_P (f)) | ||
| 1394 | redraw_frame (f); | ||
| 1395 | } | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | static void | ||
| 1399 | android_set_border_color (struct frame *f, Lisp_Object arg, | ||
| 1400 | Lisp_Object oldval) | ||
| 1401 | { | ||
| 1402 | /* Left unimplemented because Android has no window borders. */ | ||
| 1403 | CHECK_STRING (arg); | ||
| 1404 | android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1405 | update_face_from_frame_parameter (f, Qborder_color, arg); | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | static void | ||
| 1409 | android_set_cursor_color (struct frame *f, Lisp_Object arg, | ||
| 1410 | Lisp_Object oldval) | ||
| 1411 | { | ||
| 1412 | unsigned long fore_pixel, pixel; | ||
| 1413 | struct android_output *x; | ||
| 1414 | |||
| 1415 | x = f->output_data.android; | ||
| 1416 | |||
| 1417 | if (!NILP (Vx_cursor_fore_pixel)) | ||
| 1418 | fore_pixel = android_decode_color (f, Vx_cursor_fore_pixel, | ||
| 1419 | WHITE_PIX_DEFAULT (f)); | ||
| 1420 | else | ||
| 1421 | fore_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 1422 | |||
| 1423 | pixel = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1424 | |||
| 1425 | /* Make sure that the cursor color differs from the background color. */ | ||
| 1426 | if (pixel == FRAME_BACKGROUND_PIXEL (f)) | ||
| 1427 | { | ||
| 1428 | pixel = FRAME_FOREGROUND_PIXEL (f); | ||
| 1429 | if (pixel == fore_pixel) | ||
| 1430 | fore_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | x->cursor_foreground_pixel = fore_pixel; | ||
| 1434 | x->cursor_pixel = pixel; | ||
| 1435 | |||
| 1436 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1437 | { | ||
| 1438 | block_input (); | ||
| 1439 | android_set_background (x->cursor_gc, x->cursor_pixel); | ||
| 1440 | android_set_foreground (x->cursor_gc, fore_pixel); | ||
| 1441 | unblock_input (); | ||
| 1442 | |||
| 1443 | if (FRAME_VISIBLE_P (f)) | ||
| 1444 | { | ||
| 1445 | gui_update_cursor (f, false); | ||
| 1446 | gui_update_cursor (f, true); | ||
| 1447 | } | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | update_face_from_frame_parameter (f, Qcursor_color, arg); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static void | ||
| 1454 | android_set_cursor_type (struct frame *f, Lisp_Object arg, | ||
| 1455 | Lisp_Object oldval) | ||
| 1456 | { | ||
| 1457 | set_frame_cursor_types (f, arg); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | static void | ||
| 1461 | android_set_foreground_color (struct frame *f, Lisp_Object arg, | ||
| 1462 | Lisp_Object oldval) | ||
| 1463 | { | ||
| 1464 | struct android_output *x; | ||
| 1465 | unsigned long fg, old_fg; | ||
| 1466 | |||
| 1467 | x = f->output_data.android; | ||
| 1468 | |||
| 1469 | fg = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1470 | old_fg = FRAME_FOREGROUND_PIXEL (f); | ||
| 1471 | FRAME_FOREGROUND_PIXEL (f) = fg; | ||
| 1472 | |||
| 1473 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1474 | { | ||
| 1475 | block_input (); | ||
| 1476 | android_set_foreground (x->normal_gc, fg); | ||
| 1477 | android_set_background (x->reverse_gc, fg); | ||
| 1478 | |||
| 1479 | if (x->cursor_pixel == old_fg) | ||
| 1480 | { | ||
| 1481 | x->cursor_pixel = fg; | ||
| 1482 | android_set_background (x->cursor_gc, x->cursor_pixel); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | unblock_input (); | ||
| 1486 | |||
| 1487 | update_face_from_frame_parameter (f, Qforeground_color, arg); | ||
| 1488 | |||
| 1489 | if (FRAME_VISIBLE_P (f)) | ||
| 1490 | redraw_frame (f); | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | static void | ||
| 1495 | android_set_child_frame_border_width (struct frame *f, Lisp_Object arg, | ||
| 1496 | Lisp_Object oldval) | ||
| 1497 | { | ||
| 1498 | int border; | ||
| 1499 | |||
| 1500 | if (NILP (arg)) | ||
| 1501 | border = -1; | ||
| 1502 | else if (RANGED_FIXNUMP (0, arg, INT_MAX)) | ||
| 1503 | border = XFIXNAT (arg); | ||
| 1504 | else | ||
| 1505 | signal_error ("Invalid child frame border width", arg); | ||
| 1506 | |||
| 1507 | if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f)) | ||
| 1508 | { | ||
| 1509 | f->child_frame_border_width = border; | ||
| 1510 | |||
| 1511 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1512 | { | ||
| 1513 | adjust_frame_size (f, -1, -1, 3, false, Qchild_frame_border_width); | ||
| 1514 | android_clear_under_internal_border (f); | ||
| 1515 | } | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | static void | ||
| 1520 | android_set_internal_border_width (struct frame *f, Lisp_Object arg, | ||
| 1521 | Lisp_Object oldval) | ||
| 1522 | { | ||
| 1523 | int border = check_int_nonnegative (arg); | ||
| 1524 | |||
| 1525 | if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) | ||
| 1526 | { | ||
| 1527 | f->internal_border_width = border; | ||
| 1528 | |||
| 1529 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1530 | { | ||
| 1531 | adjust_frame_size (f, -1, -1, 3, false, Qinternal_border_width); | ||
| 1532 | android_clear_under_internal_border (f); | ||
| 1533 | } | ||
| 1534 | } | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | static void | ||
| 1538 | android_set_menu_bar_lines (struct frame *f, Lisp_Object value, | ||
| 1539 | Lisp_Object oldval) | ||
| 1540 | { | ||
| 1541 | int nlines; | ||
| 1542 | int olines = FRAME_MENU_BAR_LINES (f); | ||
| 1543 | |||
| 1544 | /* Right now, menu bars don't work properly in minibuf-only frames; | ||
| 1545 | most of the commands try to apply themselves to the minibuffer | ||
| 1546 | frame itself, and get an error because you can't switch buffers | ||
| 1547 | in or split the minibuffer window. */ | ||
| 1548 | if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f)) | ||
| 1549 | return; | ||
| 1550 | |||
| 1551 | if (TYPE_RANGED_FIXNUMP (int, value)) | ||
| 1552 | nlines = XFIXNUM (value); | ||
| 1553 | else | ||
| 1554 | nlines = 0; | ||
| 1555 | |||
| 1556 | /* Make sure we redisplay all windows in this frame. */ | ||
| 1557 | fset_redisplay (f); | ||
| 1558 | |||
| 1559 | FRAME_MENU_BAR_LINES (f) = nlines; | ||
| 1560 | FRAME_MENU_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); | ||
| 1561 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1562 | android_clear_under_internal_border (f); | ||
| 1563 | |||
| 1564 | /* If the menu bar height gets changed, the internal border below | ||
| 1565 | the top margin has to be cleared. Also, if the menu bar gets | ||
| 1566 | larger, the area for the added lines has to be cleared except for | ||
| 1567 | the first menu bar line that is to be drawn later. */ | ||
| 1568 | if (nlines != olines) | ||
| 1569 | { | ||
| 1570 | int height = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 1571 | int width = FRAME_PIXEL_WIDTH (f); | ||
| 1572 | int y; | ||
| 1573 | |||
| 1574 | adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines); | ||
| 1575 | |||
| 1576 | /* height can be zero here. */ | ||
| 1577 | if (FRAME_ANDROID_WINDOW (f) && height > 0 && width > 0) | ||
| 1578 | { | ||
| 1579 | y = FRAME_TOP_MARGIN_HEIGHT (f); | ||
| 1580 | |||
| 1581 | block_input (); | ||
| 1582 | android_clear_area (FRAME_ANDROID_WINDOW (f), | ||
| 1583 | 0, y, width, height); | ||
| 1584 | unblock_input (); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | if (nlines > 1 && nlines > olines) | ||
| 1588 | { | ||
| 1589 | y = (olines == 0 ? 1 : olines) * FRAME_LINE_HEIGHT (f); | ||
| 1590 | height = nlines * FRAME_LINE_HEIGHT (f) - y; | ||
| 1591 | |||
| 1592 | block_input (); | ||
| 1593 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, y, | ||
| 1594 | width, height); | ||
| 1595 | unblock_input (); | ||
| 1596 | } | ||
| 1597 | |||
| 1598 | if (nlines == 0 && WINDOWP (f->menu_bar_window)) | ||
| 1599 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix); | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | adjust_frame_glyphs (f); | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | static void | ||
| 1606 | android_set_mouse_color (struct frame *f, Lisp_Object arg, | ||
| 1607 | Lisp_Object oldval) | ||
| 1608 | { | ||
| 1609 | /* Changing the mouse color is unsupported under Android, so this is | ||
| 1610 | left intact. */ | ||
| 1611 | android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | static void | ||
| 1615 | android_set_title (struct frame *f, Lisp_Object name, | ||
| 1616 | Lisp_Object old_name) | ||
| 1617 | { | ||
| 1618 | /* Don't change the title if it's already NAME. */ | ||
| 1619 | if (EQ (name, f->title)) | ||
| 1620 | return; | ||
| 1621 | |||
| 1622 | update_mode_lines = 38; | ||
| 1623 | |||
| 1624 | fset_title (f, name); | ||
| 1625 | |||
| 1626 | if (NILP (name)) | ||
| 1627 | name = f->name; | ||
| 1628 | else | ||
| 1629 | CHECK_STRING (name); | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | static void | ||
| 1633 | android_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | ||
| 1634 | { | ||
| 1635 | double alpha = 1.0; | ||
| 1636 | double newval[2]; | ||
| 1637 | int i; | ||
| 1638 | Lisp_Object item; | ||
| 1639 | |||
| 1640 | /* N.B. that setting the window alpha is actually unsupported under | ||
| 1641 | Android. */ | ||
| 1642 | |||
| 1643 | for (i = 0; i < 2; i++) | ||
| 1644 | { | ||
| 1645 | newval[i] = 1.0; | ||
| 1646 | if (CONSP (arg)) | ||
| 1647 | { | ||
| 1648 | item = CAR (arg); | ||
| 1649 | arg = CDR (arg); | ||
| 1650 | } | ||
| 1651 | else | ||
| 1652 | item = arg; | ||
| 1653 | |||
| 1654 | if (NILP (item)) | ||
| 1655 | alpha = - 1.0; | ||
| 1656 | else if (FLOATP (item)) | ||
| 1657 | { | ||
| 1658 | alpha = XFLOAT_DATA (item); | ||
| 1659 | if (! (0 <= alpha && alpha <= 1.0)) | ||
| 1660 | args_out_of_range (make_float (0.0), make_float (1.0)); | ||
| 1661 | } | ||
| 1662 | else if (FIXNUMP (item)) | ||
| 1663 | { | ||
| 1664 | EMACS_INT ialpha = XFIXNUM (item); | ||
| 1665 | if (! (0 <= ialpha && ialpha <= 100)) | ||
| 1666 | args_out_of_range (make_fixnum (0), make_fixnum (100)); | ||
| 1667 | alpha = ialpha / 100.0; | ||
| 1668 | } | ||
| 1669 | else | ||
| 1670 | wrong_type_argument (Qnumberp, item); | ||
| 1671 | newval[i] = alpha; | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | for (i = 0; i < 2; i++) | ||
| 1675 | f->alpha[i] = newval[i]; | ||
| 1676 | |||
| 1677 | if (FRAME_TERMINAL (f)->set_frame_alpha_hook) | ||
| 1678 | { | ||
| 1679 | block_input (); | ||
| 1680 | FRAME_TERMINAL (f)->set_frame_alpha_hook (f); | ||
| 1681 | unblock_input (); | ||
| 1682 | } | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | frame_parm_handler android_frame_parm_handlers[] = | ||
| 1686 | { | ||
| 1687 | gui_set_autoraise, | ||
| 1688 | gui_set_autolower, | ||
| 1689 | android_set_background_color, | ||
| 1690 | android_set_border_color, | ||
| 1691 | gui_set_border_width, | ||
| 1692 | android_set_cursor_color, | ||
| 1693 | android_set_cursor_type, | ||
| 1694 | gui_set_font, | ||
| 1695 | android_set_foreground_color, | ||
| 1696 | NULL, | ||
| 1697 | NULL, | ||
| 1698 | android_set_child_frame_border_width, | ||
| 1699 | android_set_internal_border_width, | ||
| 1700 | gui_set_right_divider_width, | ||
| 1701 | gui_set_bottom_divider_width, | ||
| 1702 | android_set_menu_bar_lines, | ||
| 1703 | android_set_mouse_color, | ||
| 1704 | android_explicitly_set_name, | ||
| 1705 | gui_set_scroll_bar_width, | ||
| 1706 | gui_set_scroll_bar_height, | ||
| 1707 | android_set_title, | ||
| 1708 | gui_set_unsplittable, | ||
| 1709 | gui_set_vertical_scroll_bars, | ||
| 1710 | gui_set_horizontal_scroll_bars, | ||
| 1711 | gui_set_visibility, | ||
| 1712 | android_set_tab_bar_lines, | ||
| 1713 | android_set_tool_bar_lines, | ||
| 1714 | NULL, | ||
| 1715 | NULL, | ||
| 1716 | gui_set_screen_gamma, | ||
| 1717 | gui_set_line_spacing, | ||
| 1718 | gui_set_left_fringe, | ||
| 1719 | gui_set_right_fringe, | ||
| 1720 | NULL, | ||
| 1721 | gui_set_fullscreen, | ||
| 1722 | gui_set_font_backend, | ||
| 1723 | android_set_alpha, | ||
| 1724 | NULL, | ||
| 1725 | NULL, | ||
| 1726 | NULL, | ||
| 1727 | NULL, /* x_set_undecorated, */ | ||
| 1728 | NULL, /* x_set_parent_frame, */ | ||
| 1729 | NULL, /* x_set_skip_taskbar, */ | ||
| 1730 | NULL, /* x_set_no_focus_on_map, */ | ||
| 1731 | NULL, /* x_set_no_accept_focus, */ | ||
| 1732 | NULL, /* x_set_z_group, */ | ||
| 1733 | NULL, /* x_set_override_redirect, */ | ||
| 1734 | gui_set_no_special_glyphs, | ||
| 1735 | NULL, /* x_set_alpha_background, */ | ||
| 1736 | NULL, /* x_set_use_frame_synchronization, */ | ||
| 1737 | }; | ||
| 1738 | |||
| 1739 | #endif | ||
| 1740 | |||
| 1741 | |||
| 1742 | |||
| 1743 | void | ||
| 1744 | syms_of_androidfns (void) | ||
| 1745 | { | ||
| 1746 | /* Miscellaneous symbols used by some functions here. */ | ||
| 1747 | DEFSYM (Qtrue_color, "true-color"); | ||
| 1748 | DEFSYM (Qalways, "always"); | ||
| 1749 | |||
| 1750 | DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, | ||
| 1751 | doc: /* SKIP: real doc in xfns.c. */); | ||
| 1752 | Vx_cursor_fore_pixel = Qnil; | ||
| 1753 | |||
| 1754 | /* Functions defined. */ | ||
| 1755 | defsubr (&Sx_create_frame); | ||
| 1756 | defsubr (&Sxw_color_defined_p); | ||
| 1757 | defsubr (&Sxw_color_values); | ||
| 1758 | defsubr (&Sxw_display_color_p); | ||
| 1759 | defsubr (&Sx_display_grayscale_p); | ||
| 1760 | defsubr (&Sx_display_pixel_width); | ||
| 1761 | defsubr (&Sx_display_pixel_height); | ||
| 1762 | defsubr (&Sx_display_planes); | ||
| 1763 | defsubr (&Sx_display_color_cells); | ||
| 1764 | defsubr (&Sx_display_screens); | ||
| 1765 | defsubr (&Sx_display_mm_width); | ||
| 1766 | defsubr (&Sx_display_mm_height); | ||
| 1767 | defsubr (&Sx_display_backing_store); | ||
| 1768 | defsubr (&Sx_display_visual_class); | ||
| 1769 | defsubr (&Sx_display_monitor_attributes_list); | ||
| 1770 | defsubr (&Sx_frame_geometry); | ||
| 1771 | defsubr (&Sx_frame_list_z_order); | ||
| 1772 | defsubr (&Sx_frame_restack); | ||
| 1773 | defsubr (&Sx_mouse_absolute_pixel_position); | ||
| 1774 | defsubr (&Sx_set_mouse_absolute_pixel_position); | ||
| 1775 | defsubr (&Sandroid_get_connection); | ||
| 1776 | defsubr (&Sx_display_list); | ||
| 1777 | defsubr (&Sx_show_tip); | ||
| 1778 | defsubr (&Sx_hide_tip); | ||
| 1779 | } | ||
diff --git a/src/androidfont.c b/src/androidfont.c new file mode 100644 index 00000000000..e312e55c54a --- /dev/null +++ b/src/androidfont.c | |||
| @@ -0,0 +1,955 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include "lisp.h" | ||
| 23 | #include "dispextern.h" | ||
| 24 | #include "composite.h" | ||
| 25 | #include "blockinput.h" | ||
| 26 | #include "charset.h" | ||
| 27 | #include "frame.h" | ||
| 28 | #include "window.h" | ||
| 29 | #include "fontset.h" | ||
| 30 | #include "androidterm.h" | ||
| 31 | #include "character.h" | ||
| 32 | #include "coding.h" | ||
| 33 | #include "font.h" | ||
| 34 | #include "termchar.h" | ||
| 35 | #include "pdumper.h" | ||
| 36 | #include "android.h" | ||
| 37 | |||
| 38 | #ifndef ANDROID_STUBIFY | ||
| 39 | |||
| 40 | #include <android/log.h> | ||
| 41 | |||
| 42 | struct android_emacs_font_driver | ||
| 43 | { | ||
| 44 | jclass class; | ||
| 45 | jmethodID list; | ||
| 46 | jmethodID match; | ||
| 47 | jmethodID list_families; | ||
| 48 | jmethodID open_font; | ||
| 49 | jmethodID has_char; | ||
| 50 | jmethodID text_extents; | ||
| 51 | jmethodID encode_char; | ||
| 52 | |||
| 53 | /* Static methods. */ | ||
| 54 | jmethodID create_font_driver; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct android_emacs_font_spec | ||
| 58 | { | ||
| 59 | jclass class; | ||
| 60 | jfieldID foundry; | ||
| 61 | jfieldID family; | ||
| 62 | jfieldID adstyle; | ||
| 63 | jfieldID registry; | ||
| 64 | jfieldID width; | ||
| 65 | jfieldID weight; | ||
| 66 | jfieldID slant; | ||
| 67 | jfieldID size; | ||
| 68 | jfieldID spacing; | ||
| 69 | jfieldID avgwidth; | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct android_emacs_font_metrics | ||
| 73 | { | ||
| 74 | jclass class; | ||
| 75 | jfieldID lbearing; | ||
| 76 | jfieldID rbearing; | ||
| 77 | jfieldID width; | ||
| 78 | jfieldID ascent; | ||
| 79 | jfieldID descent; | ||
| 80 | }; | ||
| 81 | |||
| 82 | struct android_emacs_font_object | ||
| 83 | { | ||
| 84 | jclass class; | ||
| 85 | jfieldID min_width; | ||
| 86 | jfieldID max_width; | ||
| 87 | jfieldID pixel_size; | ||
| 88 | jfieldID height; | ||
| 89 | jfieldID space_width; | ||
| 90 | jfieldID average_width; | ||
| 91 | jfieldID ascent; | ||
| 92 | jfieldID descent; | ||
| 93 | jfieldID underline_thickness; | ||
| 94 | jfieldID underline_position; | ||
| 95 | jfieldID baseline_offset; | ||
| 96 | jfieldID relative_compose; | ||
| 97 | jfieldID default_ascent; | ||
| 98 | jfieldID encoding_charset; | ||
| 99 | jfieldID repertory_charset; | ||
| 100 | }; | ||
| 101 | |||
| 102 | struct android_integer | ||
| 103 | { | ||
| 104 | jclass class; | ||
| 105 | jmethodID constructor; | ||
| 106 | jmethodID int_value; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct androidfont_info | ||
| 110 | { | ||
| 111 | /* The font pseudo-vector object. */ | ||
| 112 | struct font font; | ||
| 113 | |||
| 114 | /* The Java-side font. */ | ||
| 115 | jobject object; | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct androidfont_entity | ||
| 119 | { | ||
| 120 | /* The font entity pvec. */ | ||
| 121 | struct font_entity font; | ||
| 122 | |||
| 123 | /* The Java-side font entity. */ | ||
| 124 | jobject object; | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* Method and class identifiers associated with the EmacsFontDriver | ||
| 128 | class. */ | ||
| 129 | |||
| 130 | struct android_emacs_font_driver font_driver_class; | ||
| 131 | |||
| 132 | /* Field and class identifiers associated with the | ||
| 133 | EmacsFontDriver$FontSpec class. */ | ||
| 134 | |||
| 135 | struct android_emacs_font_spec font_spec_class; | ||
| 136 | |||
| 137 | /* Method and class identifiers associated with the Integer class. */ | ||
| 138 | |||
| 139 | struct android_integer integer_class; | ||
| 140 | |||
| 141 | /* Field and class identifiers associated with the | ||
| 142 | EmacsFontDriver$FontMetrics class. */ | ||
| 143 | |||
| 144 | struct android_emacs_font_metrics font_metrics_class; | ||
| 145 | |||
| 146 | /* Field and class identifiers associated with the | ||
| 147 | EmacsFontDriver$FontObject class. */ | ||
| 148 | |||
| 149 | struct android_emacs_font_object font_object_class; | ||
| 150 | |||
| 151 | /* The font cache. */ | ||
| 152 | |||
| 153 | static Lisp_Object font_cache; | ||
| 154 | |||
| 155 | /* The Java-side font driver. */ | ||
| 156 | |||
| 157 | static jobject font_driver; | ||
| 158 | |||
| 159 | |||
| 160 | |||
| 161 | /* Initialize the class and method identifiers for functions in the | ||
| 162 | EmacsFontDriver class, and place them in `font_driver_class'. */ | ||
| 163 | |||
| 164 | static void | ||
| 165 | android_init_font_driver (void) | ||
| 166 | { | ||
| 167 | jclass old; | ||
| 168 | |||
| 169 | font_driver_class.class | ||
| 170 | = (*android_java_env)->FindClass (android_java_env, | ||
| 171 | "org/gnu/emacs/EmacsFontDriver"); | ||
| 172 | eassert (font_driver_class.class); | ||
| 173 | |||
| 174 | old = font_driver_class.class; | ||
| 175 | font_driver_class.class | ||
| 176 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 177 | (jobject) old); | ||
| 178 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 179 | |||
| 180 | if (!font_driver_class.class) | ||
| 181 | emacs_abort (); | ||
| 182 | |||
| 183 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 184 | font_driver_class.c_name \ | ||
| 185 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 186 | font_driver_class.class, \ | ||
| 187 | name, signature); \ | ||
| 188 | eassert (font_driver_class.c_name); | ||
| 189 | |||
| 190 | FIND_METHOD (list, "list", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)" | ||
| 191 | "[Lorg/gnu/emacs/EmacsFontDriver$FontEntity;"); | ||
| 192 | FIND_METHOD (match, "match", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)" | ||
| 193 | "Lorg/gnu/emacs/EmacsFontDriver$FontEntity;"); | ||
| 194 | FIND_METHOD (list_families, "listFamilies", "()[Ljava/lang/String;"); | ||
| 195 | FIND_METHOD (open_font, "openFont", "(Lorg/gnu/emacs/EmacsFontDriver$Font" | ||
| 196 | "Entity;I)Lorg/gnu/emacs/EmacsFontDriver$FontObject;"); | ||
| 197 | FIND_METHOD (has_char, "hasChar", "(Lorg/gnu/emacs/EmacsFontDriver$Font" | ||
| 198 | "Spec;C)I"); | ||
| 199 | FIND_METHOD (text_extents, "textExtents", "(Lorg/gnu/emacs/EmacsFontDriver" | ||
| 200 | "$FontObject;[I[Lorg/gnu/emacs/EmacsFontDriver$FontMetrics;)V"); | ||
| 201 | FIND_METHOD (encode_char, "encodeChar", "(Lorg/gnu/emacs/EmacsFontDriver" | ||
| 202 | "$FontObject;C)I"); | ||
| 203 | |||
| 204 | font_driver_class.create_font_driver | ||
| 205 | = (*android_java_env)->GetStaticMethodID (android_java_env, | ||
| 206 | font_driver_class.class, | ||
| 207 | "createFontDriver", | ||
| 208 | "()Lorg/gnu/emacs/" | ||
| 209 | "EmacsFontDriver;"); | ||
| 210 | eassert (font_driver_class.create_font_driver); | ||
| 211 | #undef FIND_METHOD | ||
| 212 | } | ||
| 213 | |||
| 214 | /* Initialize the class and field identifiers for functions in the | ||
| 215 | EmacsFontDriver$FontSpec class, and place them in | ||
| 216 | `font_spec_class'. */ | ||
| 217 | |||
| 218 | static void | ||
| 219 | android_init_font_spec (void) | ||
| 220 | { | ||
| 221 | jclass old; | ||
| 222 | |||
| 223 | font_spec_class.class | ||
| 224 | = (*android_java_env)->FindClass (android_java_env, | ||
| 225 | "org/gnu/emacs/EmacsFontDriver" | ||
| 226 | "$FontSpec"); | ||
| 227 | eassert (font_spec_class.class); | ||
| 228 | |||
| 229 | old = font_spec_class.class; | ||
| 230 | font_spec_class.class | ||
| 231 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 232 | (jobject) old); | ||
| 233 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 234 | |||
| 235 | if (!font_spec_class.class) | ||
| 236 | emacs_abort (); | ||
| 237 | |||
| 238 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 239 | font_spec_class.c_name \ | ||
| 240 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 241 | font_spec_class.class, \ | ||
| 242 | name, signature); \ | ||
| 243 | eassert (font_spec_class.c_name); | ||
| 244 | |||
| 245 | FIND_FIELD (foundry, "foundry", "Ljava/lang/String;"); | ||
| 246 | FIND_FIELD (family, "family", "Ljava/lang/String;"); | ||
| 247 | FIND_FIELD (adstyle, "adstyle", "Ljava/lang/String;"); | ||
| 248 | FIND_FIELD (registry, "registry", "Ljava/lang/String;"); | ||
| 249 | FIND_FIELD (width, "width", "Ljava/lang/Integer;"); | ||
| 250 | FIND_FIELD (weight, "weight", "Ljava/lang/Integer;"); | ||
| 251 | FIND_FIELD (slant, "slant", "Ljava/lang/Integer;"); | ||
| 252 | FIND_FIELD (size, "size", "Ljava/lang/Integer;"); | ||
| 253 | FIND_FIELD (spacing, "spacing", "Ljava/lang/Integer;"); | ||
| 254 | FIND_FIELD (avgwidth, "avgwidth", "Ljava/lang/Integer;"); | ||
| 255 | #undef FIND_FIELD | ||
| 256 | } | ||
| 257 | |||
| 258 | static void | ||
| 259 | android_init_font_metrics (void) | ||
| 260 | { | ||
| 261 | jclass old; | ||
| 262 | |||
| 263 | font_metrics_class.class | ||
| 264 | = (*android_java_env)->FindClass (android_java_env, | ||
| 265 | "org/gnu/emacs/EmacsFontDriver" | ||
| 266 | "$FontMetrics"); | ||
| 267 | eassert (font_metrics_class.class); | ||
| 268 | |||
| 269 | old = font_metrics_class.class; | ||
| 270 | font_metrics_class.class | ||
| 271 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 272 | (jobject) old); | ||
| 273 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 274 | |||
| 275 | if (!font_metrics_class.class) | ||
| 276 | emacs_abort (); | ||
| 277 | |||
| 278 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 279 | font_metrics_class.c_name \ | ||
| 280 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 281 | font_metrics_class.class, \ | ||
| 282 | name, signature); \ | ||
| 283 | eassert (font_metrics_class.c_name); | ||
| 284 | |||
| 285 | FIND_FIELD (lbearing, "lbearing", "S"); | ||
| 286 | FIND_FIELD (rbearing, "rbearing", "S"); | ||
| 287 | FIND_FIELD (width, "width", "S"); | ||
| 288 | FIND_FIELD (ascent, "ascent", "S"); | ||
| 289 | FIND_FIELD (descent, "descent", "S"); | ||
| 290 | #undef FIND_FIELD | ||
| 291 | } | ||
| 292 | |||
| 293 | static void | ||
| 294 | android_init_integer (void) | ||
| 295 | { | ||
| 296 | jclass old; | ||
| 297 | |||
| 298 | integer_class.class | ||
| 299 | = (*android_java_env)->FindClass (android_java_env, | ||
| 300 | "java/lang/Integer"); | ||
| 301 | eassert (integer_class.class); | ||
| 302 | |||
| 303 | old = integer_class.class; | ||
| 304 | integer_class.class | ||
| 305 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 306 | (jobject) old); | ||
| 307 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 308 | |||
| 309 | if (!integer_class.class) | ||
| 310 | emacs_abort (); | ||
| 311 | |||
| 312 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 313 | integer_class.c_name \ | ||
| 314 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 315 | integer_class.class, \ | ||
| 316 | name, signature); \ | ||
| 317 | eassert (integer_class.c_name); | ||
| 318 | |||
| 319 | FIND_METHOD (constructor, "<init>", "(I)V"); | ||
| 320 | FIND_METHOD (int_value, "intValue", "()I"); | ||
| 321 | #undef FIND_METHOD | ||
| 322 | } | ||
| 323 | |||
| 324 | static void | ||
| 325 | android_init_font_object (void) | ||
| 326 | { | ||
| 327 | jclass old; | ||
| 328 | |||
| 329 | font_object_class.class | ||
| 330 | = (*android_java_env)->FindClass (android_java_env, | ||
| 331 | "org/gnu/emacs/EmacsFontDriver" | ||
| 332 | "$FontObject"); | ||
| 333 | eassert (font_object_class.class); | ||
| 334 | |||
| 335 | old = font_object_class.class; | ||
| 336 | font_object_class.class | ||
| 337 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 338 | (jobject) old); | ||
| 339 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 340 | |||
| 341 | if (!font_object_class.class) | ||
| 342 | emacs_abort (); | ||
| 343 | |||
| 344 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 345 | font_object_class.c_name \ | ||
| 346 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 347 | font_object_class.class, \ | ||
| 348 | name, signature); \ | ||
| 349 | eassert (font_object_class.c_name); | ||
| 350 | |||
| 351 | FIND_FIELD (min_width, "minWidth", "I"); | ||
| 352 | FIND_FIELD (max_width, "maxWidth", "I"); | ||
| 353 | FIND_FIELD (pixel_size, "pixelSize", "I"); | ||
| 354 | FIND_FIELD (height, "height", "I"); | ||
| 355 | FIND_FIELD (space_width, "spaceWidth", "I"); | ||
| 356 | FIND_FIELD (average_width, "averageWidth", "I"); | ||
| 357 | FIND_FIELD (ascent, "ascent", "I"); | ||
| 358 | FIND_FIELD (descent, "descent", "I"); | ||
| 359 | FIND_FIELD (underline_thickness, "underlineThickness", "I"); | ||
| 360 | FIND_FIELD (underline_position, "underlinePosition", "I"); | ||
| 361 | FIND_FIELD (baseline_offset, "baselineOffset", "I"); | ||
| 362 | FIND_FIELD (relative_compose, "relativeCompose", "I"); | ||
| 363 | FIND_FIELD (default_ascent, "defaultAscent", "I"); | ||
| 364 | FIND_FIELD (encoding_charset, "encodingCharset", "I"); | ||
| 365 | FIND_FIELD (repertory_charset, "repertoryCharset", "I"); | ||
| 366 | #undef FIND_FIELD | ||
| 367 | } | ||
| 368 | |||
| 369 | static Lisp_Object | ||
| 370 | androidfont_get_cache (struct frame *frame) | ||
| 371 | { | ||
| 372 | return font_cache; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Return a local reference to an instance of EmacsFontDriver$FontSpec | ||
| 376 | with the same values as FONT. */ | ||
| 377 | |||
| 378 | static jobject | ||
| 379 | androidfont_from_lisp (Lisp_Object font) | ||
| 380 | { | ||
| 381 | jobject spec, integer; | ||
| 382 | jstring string; | ||
| 383 | Lisp_Object tem; | ||
| 384 | |||
| 385 | spec = (*android_java_env)->AllocObject (android_java_env, | ||
| 386 | font_spec_class.class); | ||
| 387 | |||
| 388 | if (!spec) | ||
| 389 | { | ||
| 390 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 391 | memory_full (0); | ||
| 392 | } | ||
| 393 | |||
| 394 | #define DO_SYMBOL_FIELD(field, index) \ | ||
| 395 | tem = AREF (font, index); \ | ||
| 396 | if (SYMBOLP (tem)) \ | ||
| 397 | { \ | ||
| 398 | /* Java seems to DTRT with the Emacs string encoding, so this does \ | ||
| 399 | not matter at all. */ \ | ||
| 400 | string = (*android_java_env)->NewStringUTF (android_java_env, \ | ||
| 401 | SSDATA (SYMBOL_NAME (tem))); \ | ||
| 402 | if (!string) \ | ||
| 403 | { \ | ||
| 404 | (*android_java_env)->ExceptionClear (android_java_env); \ | ||
| 405 | memory_full (0); \ | ||
| 406 | } \ | ||
| 407 | \ | ||
| 408 | (*android_java_env)->SetObjectField (android_java_env, spec, \ | ||
| 409 | font_spec_class.field, \ | ||
| 410 | string); \ | ||
| 411 | ANDROID_DELETE_LOCAL_REF (string); \ | ||
| 412 | } \ | ||
| 413 | |||
| 414 | DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX); | ||
| 415 | DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX); | ||
| 416 | DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX); | ||
| 417 | DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX); | ||
| 418 | |||
| 419 | #undef DO_SYMBOL_FIELD | ||
| 420 | |||
| 421 | #define DO_CARDINAL_FIELD(field, value) \ | ||
| 422 | if (value != -1) \ | ||
| 423 | { \ | ||
| 424 | integer = (*android_java_env)->NewObject (android_java_env, \ | ||
| 425 | integer_class.class, \ | ||
| 426 | integer_class.constructor, \ | ||
| 427 | (jint) value); \ | ||
| 428 | if (!integer) \ | ||
| 429 | { \ | ||
| 430 | (*android_java_env)->ExceptionClear (android_java_env); \ | ||
| 431 | memory_full (0); \ | ||
| 432 | } \ | ||
| 433 | \ | ||
| 434 | (*android_java_env)->SetObjectField (android_java_env, spec, \ | ||
| 435 | font_spec_class.field, \ | ||
| 436 | integer); \ | ||
| 437 | ANDROID_DELETE_LOCAL_REF (integer); \ | ||
| 438 | } | ||
| 439 | |||
| 440 | DO_CARDINAL_FIELD (width, FONT_WIDTH_NUMERIC (font)); | ||
| 441 | DO_CARDINAL_FIELD (weight, FONT_WEIGHT_NUMERIC (font)); | ||
| 442 | DO_CARDINAL_FIELD (slant, FONT_SLANT_NUMERIC (font)); | ||
| 443 | DO_CARDINAL_FIELD (size, (FIXNUMP (AREF (font, FONT_SIZE_INDEX)) | ||
| 444 | ? XFIXNUM (AREF (font, FONT_SIZE_INDEX)) | ||
| 445 | : -1)); | ||
| 446 | DO_CARDINAL_FIELD (spacing, (FIXNUMP (AREF (font, FONT_SPACING_INDEX)) | ||
| 447 | ? XFIXNUM (AREF (font, FONT_SPACING_INDEX)) | ||
| 448 | : -1)); | ||
| 449 | DO_CARDINAL_FIELD (avgwidth, (FIXNUMP (AREF (font, FONT_AVGWIDTH_INDEX)) | ||
| 450 | ? XFIXNUM (AREF (font, FONT_AVGWIDTH_INDEX)) | ||
| 451 | : -1)); | ||
| 452 | |||
| 453 | #undef DO_CARDINAL_FIELD | ||
| 454 | |||
| 455 | return spec; | ||
| 456 | } | ||
| 457 | |||
| 458 | static void | ||
| 459 | androidfont_from_java (jobject spec, Lisp_Object entity) | ||
| 460 | { | ||
| 461 | jobject tem; | ||
| 462 | jint value; | ||
| 463 | const char *string; | ||
| 464 | |||
| 465 | #define DO_SYMBOL_FIELD(field, index) \ | ||
| 466 | tem = (*android_java_env)->GetObjectField (android_java_env, \ | ||
| 467 | spec, \ | ||
| 468 | font_spec_class.field); \ | ||
| 469 | if (tem) \ | ||
| 470 | { \ | ||
| 471 | string = (*android_java_env)->GetStringUTFChars (android_java_env, \ | ||
| 472 | tem, NULL); \ | ||
| 473 | if (!string) \ | ||
| 474 | memory_full (0); \ | ||
| 475 | ASET (entity, index, intern (string)); \ | ||
| 476 | (*android_java_env)->ReleaseStringUTFChars (android_java_env, \ | ||
| 477 | tem, string); \ | ||
| 478 | ANDROID_DELETE_LOCAL_REF (tem); \ | ||
| 479 | } | ||
| 480 | |||
| 481 | DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX); | ||
| 482 | DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX); | ||
| 483 | DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX); | ||
| 484 | DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX); | ||
| 485 | |||
| 486 | #undef DO_SYMBOL_FIELD | ||
| 487 | #define DO_CARDINAL_FIELD(field, index, is_style) \ | ||
| 488 | tem = (*android_java_env)->GetObjectField (android_java_env, \ | ||
| 489 | spec, \ | ||
| 490 | font_spec_class.field); \ | ||
| 491 | if (tem) \ | ||
| 492 | { \ | ||
| 493 | value \ | ||
| 494 | = (*android_java_env)->CallIntMethod (android_java_env, \ | ||
| 495 | tem, \ | ||
| 496 | integer_class.int_value); \ | ||
| 497 | if (!is_style) \ | ||
| 498 | ASET (entity, index, make_fixnum (value)); \ | ||
| 499 | else \ | ||
| 500 | FONT_SET_STYLE (entity, index, make_fixnum (value)); \ | ||
| 501 | ANDROID_DELETE_LOCAL_REF (tem); \ | ||
| 502 | } | ||
| 503 | |||
| 504 | DO_CARDINAL_FIELD (width, FONT_WIDTH_INDEX, true); | ||
| 505 | DO_CARDINAL_FIELD (weight, FONT_WEIGHT_INDEX, true); | ||
| 506 | DO_CARDINAL_FIELD (slant, FONT_SLANT_INDEX, true); | ||
| 507 | DO_CARDINAL_FIELD (size, FONT_SIZE_INDEX, false); | ||
| 508 | DO_CARDINAL_FIELD (spacing, FONT_SPACING_INDEX, false); | ||
| 509 | DO_CARDINAL_FIELD (avgwidth, FONT_AVGWIDTH_INDEX, false); | ||
| 510 | #undef DO_CARDINAL_FIELD | ||
| 511 | } | ||
| 512 | |||
| 513 | /* Transfer the values from FONT, which must be some kind of font | ||
| 514 | entity, */ | ||
| 515 | |||
| 516 | static Lisp_Object | ||
| 517 | androidfont_list (struct frame *f, Lisp_Object font_spec) | ||
| 518 | { | ||
| 519 | jobject spec, array, tem; | ||
| 520 | jarray entities; | ||
| 521 | jsize i, size; | ||
| 522 | Lisp_Object value, entity; | ||
| 523 | struct androidfont_entity *info; | ||
| 524 | |||
| 525 | spec = androidfont_from_lisp (font_spec); | ||
| 526 | array = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 527 | font_driver, | ||
| 528 | font_driver_class.list, | ||
| 529 | spec); | ||
| 530 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 531 | ANDROID_DELETE_LOCAL_REF (spec); | ||
| 532 | |||
| 533 | if (!array) | ||
| 534 | memory_full (0); | ||
| 535 | |||
| 536 | entities = (jarray) array; | ||
| 537 | size = (*android_java_env)->GetArrayLength (android_java_env, | ||
| 538 | entities); | ||
| 539 | value = Qnil; | ||
| 540 | |||
| 541 | for (i = 0; i < size; ++i) | ||
| 542 | { | ||
| 543 | entity = font_make_entity_android (VECSIZE (struct androidfont_entity)); | ||
| 544 | info = (struct androidfont_entity *) XFONT_ENTITY (entity); | ||
| 545 | |||
| 546 | /* The type must be set correctly, or font_open_entity won't be | ||
| 547 | able to find the right font driver. */ | ||
| 548 | ASET (entity, FONT_TYPE_INDEX, Qandroid); | ||
| 549 | |||
| 550 | /* Clear this now in case GC happens without it set, which can | ||
| 551 | happen if androidfont_from_java runs out of memory. */ | ||
| 552 | info->object = NULL; | ||
| 553 | |||
| 554 | tem = (*android_java_env)->GetObjectArrayElement (android_java_env, | ||
| 555 | entities, i); | ||
| 556 | androidfont_from_java (tem, entity); | ||
| 557 | |||
| 558 | /* Now, make a global reference to the Java font entity. */ | ||
| 559 | info->object = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 560 | (jobject) tem); | ||
| 561 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 562 | ANDROID_DELETE_LOCAL_REF (tem); | ||
| 563 | |||
| 564 | if (!info->object) | ||
| 565 | memory_full (0); | ||
| 566 | |||
| 567 | value = Fcons (entity, value); | ||
| 568 | } | ||
| 569 | |||
| 570 | ANDROID_DELETE_LOCAL_REF (entities); | ||
| 571 | return Fnreverse (value); | ||
| 572 | } | ||
| 573 | |||
| 574 | static Lisp_Object | ||
| 575 | androidfont_match (struct frame *f, Lisp_Object font_spec) | ||
| 576 | { | ||
| 577 | jobject spec, result; | ||
| 578 | Lisp_Object entity; | ||
| 579 | struct androidfont_entity *info; | ||
| 580 | |||
| 581 | spec = androidfont_from_lisp (font_spec); | ||
| 582 | result = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 583 | font_driver, | ||
| 584 | font_driver_class.match, | ||
| 585 | spec); | ||
| 586 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 587 | ANDROID_DELETE_LOCAL_REF (spec); | ||
| 588 | |||
| 589 | if (!result) | ||
| 590 | memory_full (0); | ||
| 591 | |||
| 592 | entity = font_make_entity_android (VECSIZE (struct androidfont_entity)); | ||
| 593 | info = (struct androidfont_entity *) XFONT_ENTITY (entity); | ||
| 594 | |||
| 595 | /* The type must be set correctly, or font_open_entity won't be able | ||
| 596 | to find the right font driver. */ | ||
| 597 | ASET (entity, FONT_TYPE_INDEX, Qandroid); | ||
| 598 | |||
| 599 | info->object = NULL; | ||
| 600 | androidfont_from_java (result, entity); | ||
| 601 | info->object = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 602 | (jobject) result); | ||
| 603 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 604 | ANDROID_DELETE_LOCAL_REF (result); | ||
| 605 | |||
| 606 | if (!info->object) | ||
| 607 | memory_full (0); | ||
| 608 | |||
| 609 | return entity; | ||
| 610 | } | ||
| 611 | |||
| 612 | static int | ||
| 613 | androidfont_draw (struct glyph_string *s, int from, int to, | ||
| 614 | int x, int y, bool with_background) | ||
| 615 | { | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static Lisp_Object | ||
| 620 | androidfont_open_font (struct frame *f, Lisp_Object font_entity, int x) | ||
| 621 | { | ||
| 622 | struct androidfont_info *font_info; | ||
| 623 | struct androidfont_entity *entity; | ||
| 624 | struct font *font; | ||
| 625 | Lisp_Object font_object, tem; | ||
| 626 | jobject old; | ||
| 627 | jint value; | ||
| 628 | |||
| 629 | if (x <= 0) | ||
| 630 | { | ||
| 631 | /* Get pixel size from frame instead. */ | ||
| 632 | tem = get_frame_param (f, Qfontsize); | ||
| 633 | x = NILP (tem) ? 0 : XFIXNAT (tem); | ||
| 634 | } | ||
| 635 | |||
| 636 | __android_log_print (ANDROID_LOG_DEBUG, __func__, | ||
| 637 | "opening font entity %"pI"x:%d", | ||
| 638 | (EMACS_INT) font_entity, x); | ||
| 639 | |||
| 640 | entity = (struct androidfont_entity *) XFONT_ENTITY (font_entity); | ||
| 641 | |||
| 642 | block_input (); | ||
| 643 | font_object = font_make_object (VECSIZE (struct androidfont_info), | ||
| 644 | font_entity, x); | ||
| 645 | ASET (font_object, FONT_TYPE_INDEX, Qandroid); | ||
| 646 | font_info = (struct androidfont_info *) XFONT_OBJECT (font_object); | ||
| 647 | font = &font_info->font; | ||
| 648 | font->driver = &androidfont_driver; | ||
| 649 | |||
| 650 | /* Clear font_info->object early in case GC happens later on! */ | ||
| 651 | font_info->object = NULL; | ||
| 652 | unblock_input (); | ||
| 653 | |||
| 654 | font_info->object | ||
| 655 | = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 656 | font_driver, | ||
| 657 | font_driver_class.open_font, | ||
| 658 | entity->object, (jint) x); | ||
| 659 | if (!font_info->object) | ||
| 660 | { | ||
| 661 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 662 | return Qnil; | ||
| 663 | } | ||
| 664 | |||
| 665 | old = font_info->object; | ||
| 666 | font_info->object | ||
| 667 | = (*android_java_env)->NewGlobalRef (android_java_env, old); | ||
| 668 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 669 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 670 | |||
| 671 | if (!font_info->object) | ||
| 672 | return Qnil; | ||
| 673 | |||
| 674 | /* Copy the font attributes from the Java object. */ | ||
| 675 | androidfont_from_java (font_info->object, font_object); | ||
| 676 | |||
| 677 | /* Copy font attributes inside EmacsFontDriver$FontObject. */ | ||
| 678 | #define DO_CARDINAL_FIELD(field) \ | ||
| 679 | value \ | ||
| 680 | = (*android_java_env)->GetIntField (android_java_env, \ | ||
| 681 | font_info->object, \ | ||
| 682 | font_object_class.field); \ | ||
| 683 | font->field = value; | ||
| 684 | |||
| 685 | DO_CARDINAL_FIELD (min_width); | ||
| 686 | DO_CARDINAL_FIELD (max_width); | ||
| 687 | DO_CARDINAL_FIELD (pixel_size); | ||
| 688 | DO_CARDINAL_FIELD (height); | ||
| 689 | DO_CARDINAL_FIELD (space_width); | ||
| 690 | DO_CARDINAL_FIELD (average_width); | ||
| 691 | DO_CARDINAL_FIELD (ascent); | ||
| 692 | DO_CARDINAL_FIELD (descent); | ||
| 693 | DO_CARDINAL_FIELD (underline_thickness); | ||
| 694 | DO_CARDINAL_FIELD (underline_position); | ||
| 695 | DO_CARDINAL_FIELD (baseline_offset); | ||
| 696 | DO_CARDINAL_FIELD (relative_compose); | ||
| 697 | DO_CARDINAL_FIELD (default_ascent); | ||
| 698 | DO_CARDINAL_FIELD (encoding_charset); | ||
| 699 | DO_CARDINAL_FIELD (repertory_charset); | ||
| 700 | |||
| 701 | #undef DO_CARDINAL_FIELD | ||
| 702 | |||
| 703 | /* This should eventually become unnecessary. */ | ||
| 704 | font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil); | ||
| 705 | |||
| 706 | return font_object; | ||
| 707 | } | ||
| 708 | |||
| 709 | static void | ||
| 710 | androidfont_close_font (struct font *font) | ||
| 711 | { | ||
| 712 | struct androidfont_info *info; | ||
| 713 | |||
| 714 | info = (struct androidfont_info *) font; | ||
| 715 | |||
| 716 | /* If info->object is NULL, then FONT was unsuccessfully created, | ||
| 717 | and there is no global reference that has to be deleted. */ | ||
| 718 | |||
| 719 | if (!info->object) | ||
| 720 | return; | ||
| 721 | |||
| 722 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 723 | info->object); | ||
| 724 | } | ||
| 725 | |||
| 726 | static int | ||
| 727 | androidfont_has_char (Lisp_Object font, int c) | ||
| 728 | { | ||
| 729 | struct androidfont_info *info; | ||
| 730 | struct androidfont_entity *entity; | ||
| 731 | |||
| 732 | if (FONT_ENTITY_P (font)) | ||
| 733 | { | ||
| 734 | entity = (struct androidfont_entity *) XFONT_ENTITY (font); | ||
| 735 | |||
| 736 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 737 | font_driver, | ||
| 738 | font_driver_class.has_char, | ||
| 739 | entity->object, (jint) c); | ||
| 740 | } | ||
| 741 | else | ||
| 742 | { | ||
| 743 | info = (struct androidfont_info *) XFONT_OBJECT (font); | ||
| 744 | |||
| 745 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 746 | font_driver, | ||
| 747 | font_driver_class.has_char, | ||
| 748 | info->object, (jint) c); | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | static unsigned | ||
| 753 | androidfont_encode_char (struct font *font, int c) | ||
| 754 | { | ||
| 755 | struct androidfont_info *info; | ||
| 756 | |||
| 757 | info = (struct androidfont_info *) font; | ||
| 758 | |||
| 759 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 760 | font_driver, | ||
| 761 | font_driver_class.encode_char, | ||
| 762 | info->object, (jchar) c); | ||
| 763 | } | ||
| 764 | |||
| 765 | static void | ||
| 766 | androidfont_text_extents (struct font *font, const unsigned int *code, | ||
| 767 | int nglyphs, struct font_metrics *metrics) | ||
| 768 | { | ||
| 769 | struct androidfont_info *info; | ||
| 770 | jarray codepoint_array, metrics_array; | ||
| 771 | jobject metrics_object; | ||
| 772 | int i; | ||
| 773 | short value; | ||
| 774 | |||
| 775 | info = (struct androidfont_info *) font; | ||
| 776 | |||
| 777 | /* Allocate the arrays of code points and font metrics. */ | ||
| 778 | codepoint_array | ||
| 779 | = (*android_java_env)->NewIntArray (android_java_env, | ||
| 780 | nglyphs); | ||
| 781 | if (!codepoint_array) | ||
| 782 | { | ||
| 783 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 784 | memory_full (0); | ||
| 785 | } | ||
| 786 | |||
| 787 | metrics_array | ||
| 788 | = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 789 | nglyphs, | ||
| 790 | font_metrics_class.class, | ||
| 791 | NULL); | ||
| 792 | if (!metrics_array) | ||
| 793 | { | ||
| 794 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 795 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 796 | memory_full (0); | ||
| 797 | } | ||
| 798 | |||
| 799 | if (sizeof (unsigned int) == sizeof (jint)) | ||
| 800 | /* Always true on every Android device. */ | ||
| 801 | (*android_java_env)->SetIntArrayRegion (android_java_env, | ||
| 802 | codepoint_array, | ||
| 803 | 0, nglyphs, | ||
| 804 | (jint *) code); | ||
| 805 | else | ||
| 806 | emacs_abort (); | ||
| 807 | |||
| 808 | for (i = 0; i < nglyphs; ++i) | ||
| 809 | { | ||
| 810 | metrics_object | ||
| 811 | = (*android_java_env)->AllocObject (android_java_env, | ||
| 812 | font_metrics_class.class); | ||
| 813 | |||
| 814 | if (!metrics_object) | ||
| 815 | { | ||
| 816 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 817 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 818 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 819 | memory_full (0); | ||
| 820 | } | ||
| 821 | |||
| 822 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 823 | metrics_array, i, | ||
| 824 | metrics_object); | ||
| 825 | ANDROID_DELETE_LOCAL_REF (metrics_object); | ||
| 826 | } | ||
| 827 | |||
| 828 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 829 | font_driver, | ||
| 830 | font_driver_class.text_extents, | ||
| 831 | info->object, codepoint_array, | ||
| 832 | metrics_array); | ||
| 833 | |||
| 834 | if ((*android_java_env)->ExceptionCheck (android_java_env)) | ||
| 835 | { | ||
| 836 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 837 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 838 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 839 | memory_full (0); | ||
| 840 | } | ||
| 841 | |||
| 842 | for (i = 0; i < nglyphs; ++i) | ||
| 843 | { | ||
| 844 | metrics_object | ||
| 845 | = (*android_java_env)->GetObjectArrayElement (android_java_env, | ||
| 846 | metrics_array, i); | ||
| 847 | #define DO_CARDINAL_FIELD(field) \ | ||
| 848 | value \ | ||
| 849 | = (*android_java_env)->GetShortField (android_java_env, \ | ||
| 850 | metrics_object, \ | ||
| 851 | font_metrics_class.field); \ | ||
| 852 | metrics[i].field = value; | ||
| 853 | |||
| 854 | DO_CARDINAL_FIELD (lbearing); | ||
| 855 | DO_CARDINAL_FIELD (rbearing); | ||
| 856 | DO_CARDINAL_FIELD (width); | ||
| 857 | DO_CARDINAL_FIELD (ascent); | ||
| 858 | DO_CARDINAL_FIELD (descent); | ||
| 859 | |||
| 860 | #undef DO_CARDINAL_FIELD | ||
| 861 | |||
| 862 | ANDROID_DELETE_LOCAL_REF (metrics_object); | ||
| 863 | } | ||
| 864 | |||
| 865 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 866 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 867 | } | ||
| 868 | |||
| 869 | static Lisp_Object | ||
| 870 | androidfont_list_family (struct frame *f) | ||
| 871 | { | ||
| 872 | return Qnil; | ||
| 873 | } | ||
| 874 | |||
| 875 | struct font_driver androidfont_driver = | ||
| 876 | { | ||
| 877 | .type = LISPSYM_INITIALLY (Qandroid), | ||
| 878 | .case_sensitive = true, | ||
| 879 | .get_cache = androidfont_get_cache, | ||
| 880 | .list = androidfont_list, | ||
| 881 | .match = androidfont_match, | ||
| 882 | .draw = androidfont_draw, | ||
| 883 | .open_font = androidfont_open_font, | ||
| 884 | .close_font = androidfont_close_font, | ||
| 885 | .has_char = androidfont_has_char, | ||
| 886 | .encode_char = androidfont_encode_char, | ||
| 887 | .text_extents = androidfont_text_extents, | ||
| 888 | .list_family = androidfont_list_family, | ||
| 889 | }; | ||
| 890 | |||
| 891 | static void | ||
| 892 | syms_of_androidfont_for_pdumper (void) | ||
| 893 | { | ||
| 894 | register_font_driver (&androidfont_driver, NULL); | ||
| 895 | } | ||
| 896 | |||
| 897 | void | ||
| 898 | syms_of_androidfont (void) | ||
| 899 | { | ||
| 900 | DEFSYM (Qfontsize, "fontsize"); | ||
| 901 | |||
| 902 | pdumper_do_now_and_after_load (syms_of_androidfont_for_pdumper); | ||
| 903 | |||
| 904 | font_cache = list (Qnil); | ||
| 905 | staticpro (&font_cache); | ||
| 906 | } | ||
| 907 | |||
| 908 | void | ||
| 909 | init_androidfont (void) | ||
| 910 | { | ||
| 911 | jmethodID method; | ||
| 912 | jobject old; | ||
| 913 | |||
| 914 | android_init_font_driver (); | ||
| 915 | android_init_font_spec (); | ||
| 916 | android_init_font_metrics (); | ||
| 917 | android_init_font_object (); | ||
| 918 | android_init_integer (); | ||
| 919 | |||
| 920 | method = font_driver_class.create_font_driver; | ||
| 921 | |||
| 922 | /* Initialize the font driver on the Java side. */ | ||
| 923 | font_driver | ||
| 924 | = (*android_java_env)->CallStaticObjectMethod (android_java_env, | ||
| 925 | font_driver_class.class, | ||
| 926 | method); | ||
| 927 | |||
| 928 | if (!font_driver) | ||
| 929 | memory_full (0); | ||
| 930 | |||
| 931 | old = font_driver; | ||
| 932 | font_driver | ||
| 933 | = (*android_java_env)->NewGlobalRef (android_java_env, font_driver); | ||
| 934 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 935 | |||
| 936 | if (!font_driver) | ||
| 937 | memory_full (0); | ||
| 938 | } | ||
| 939 | |||
| 940 | void | ||
| 941 | android_finalize_font_entity (struct font_entity *entity) | ||
| 942 | { | ||
| 943 | struct androidfont_entity *info; | ||
| 944 | |||
| 945 | info = (struct androidfont_entity *) entity; | ||
| 946 | |||
| 947 | if (info->object) | ||
| 948 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 949 | info->object); | ||
| 950 | |||
| 951 | /* Not sure if this can be called twice. */ | ||
| 952 | info->object = NULL; | ||
| 953 | } | ||
| 954 | |||
| 955 | #endif | ||
diff --git a/src/androidgui.h b/src/androidgui.h new file mode 100644 index 00000000000..43ccc86e5c7 --- /dev/null +++ b/src/androidgui.h | |||
| @@ -0,0 +1,315 @@ | |||
| 1 | /* Android window system support. | ||
| 2 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #ifndef _ANDROID_GUI_H_ | ||
| 20 | #define _ANDROID_GUI_H_ | ||
| 21 | |||
| 22 | struct android_char_struct | ||
| 23 | { | ||
| 24 | int rbearing; | ||
| 25 | int lbearing; | ||
| 26 | int width; | ||
| 27 | int ascent; | ||
| 28 | int descent; | ||
| 29 | }; | ||
| 30 | |||
| 31 | typedef struct android_char_struct XCharStruct; | ||
| 32 | |||
| 33 | typedef unsigned short android_handle; | ||
| 34 | |||
| 35 | typedef android_handle android_pixmap, Emacs_Pixmap; | ||
| 36 | typedef android_handle android_window, Emacs_Window; | ||
| 37 | typedef android_handle android_gcontext, GContext; | ||
| 38 | typedef android_handle android_drawable, Drawable; | ||
| 39 | |||
| 40 | typedef unsigned int android_time; | ||
| 41 | |||
| 42 | struct android_rectangle | ||
| 43 | { | ||
| 44 | int x, y; | ||
| 45 | unsigned width, height; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct android_point | ||
| 49 | { | ||
| 50 | int x, y; | ||
| 51 | }; | ||
| 52 | |||
| 53 | /* Keep this in sync with EmacsGC.java! */ | ||
| 54 | |||
| 55 | enum android_gc_function | ||
| 56 | { | ||
| 57 | ANDROID_GC_COPY = 0, | ||
| 58 | ANDROID_GC_XOR = 1, | ||
| 59 | }; | ||
| 60 | |||
| 61 | enum android_gc_value_mask | ||
| 62 | { | ||
| 63 | ANDROID_GC_FOREGROUND = (1 << 0), | ||
| 64 | ANDROID_GC_BACKGROUND = (1 << 1), | ||
| 65 | ANDROID_GC_FUNCTION = (1 << 2), | ||
| 66 | ANDROID_GC_CLIP_X_ORIGIN = (1 << 3), | ||
| 67 | ANDROID_GC_CLIP_Y_ORIGIN = (1 << 4), | ||
| 68 | ANDROID_GC_CLIP_MASK = (1 << 5), | ||
| 69 | ANDROID_GC_STIPPLE = (1 << 6), | ||
| 70 | ANDROID_GC_FILL_STYLE = (1 << 7), | ||
| 71 | ANDROID_GC_TILE_STIP_X_ORIGIN = (1 << 8), | ||
| 72 | ANDROID_GC_TILE_STIP_Y_ORIGIN = (1 << 9), | ||
| 73 | }; | ||
| 74 | |||
| 75 | enum android_fill_style | ||
| 76 | { | ||
| 77 | ANDROID_FILL_SOLID = 0, | ||
| 78 | ANDROID_FILL_OPAQUE_STIPPLED = 1, | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum android_window_value_mask | ||
| 82 | { | ||
| 83 | ANDROID_CW_BACK_PIXEL = (1 << 1), | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct android_set_window_attributes | ||
| 87 | { | ||
| 88 | /* The background pixel. */ | ||
| 89 | unsigned long background_pixel; | ||
| 90 | }; | ||
| 91 | |||
| 92 | struct android_gc_values | ||
| 93 | { | ||
| 94 | /* The foreground and background. */ | ||
| 95 | unsigned long foreground, background; | ||
| 96 | |||
| 97 | /* The function. */ | ||
| 98 | enum android_gc_function function; | ||
| 99 | |||
| 100 | /* The fill style. */ | ||
| 101 | enum android_fill_style fill_style; | ||
| 102 | |||
| 103 | /* The clip X and Y origin. */ | ||
| 104 | int clip_x_origin, clip_y_origin; | ||
| 105 | |||
| 106 | /* The clip mask image and stipple. */ | ||
| 107 | android_pixmap clip_mask, stipple; | ||
| 108 | |||
| 109 | /* The tile-stipple X and Y origins. */ | ||
| 110 | int ts_x_origin, ts_y_origin; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* X-like graphics context structure. This is implemented in | ||
| 114 | EmacsGC.java, but a copy is kept here to avoid sending changes all | ||
| 115 | the time. */ | ||
| 116 | |||
| 117 | struct android_gc | ||
| 118 | { | ||
| 119 | /* The Java-side handle. */ | ||
| 120 | android_gcontext gcontext; | ||
| 121 | }; | ||
| 122 | |||
| 123 | enum android_swap_action | ||
| 124 | { | ||
| 125 | ANDROID_COPIED, | ||
| 126 | }; | ||
| 127 | |||
| 128 | enum android_shape | ||
| 129 | { | ||
| 130 | ANDROID_CONVEX, | ||
| 131 | }; | ||
| 132 | |||
| 133 | enum android_coord_mode | ||
| 134 | { | ||
| 135 | ANDROID_COORD_MODE_ORIGIN, | ||
| 136 | }; | ||
| 137 | |||
| 138 | struct android_swap_info | ||
| 139 | { | ||
| 140 | /* The window to swap. */ | ||
| 141 | android_window swap_window; | ||
| 142 | |||
| 143 | /* Unused field present only for consistency with X. */ | ||
| 144 | enum android_swap_action swap_action; | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* Android doesn't support cursors, so define this to something | ||
| 148 | unused. */ | ||
| 149 | typedef char Emacs_Cursor; | ||
| 150 | |||
| 151 | #define NativeRectangle Emacs_Rectangle | ||
| 152 | #define CONVERT_TO_NATIVE_RECT(xr, nr) ((xr) = (nr)) | ||
| 153 | #define CONVERT_FROM_EMACS_RECT(xr, nr) ((nr) = (xr)) | ||
| 154 | |||
| 155 | #define STORE_NATIVE_RECT(nr, rx, ry, rwidth, rheight) \ | ||
| 156 | ((nr).x = (rx), (nr).y = (ry), \ | ||
| 157 | (nr).width = (rwidth), (nr).height = (rheight)) \ | ||
| 158 | |||
| 159 | #define ForgetGravity 0 | ||
| 160 | #define NorthWestGravity 1 | ||
| 161 | #define NorthGravity 2 | ||
| 162 | #define NorthEastGravity 3 | ||
| 163 | #define WestGravity 4 | ||
| 164 | #define CenterGravity 5 | ||
| 165 | #define EastGravity 6 | ||
| 166 | #define SouthWestGravity 7 | ||
| 167 | #define SouthGravity 8 | ||
| 168 | #define SouthEastGravity 9 | ||
| 169 | #define StaticGravity 10 | ||
| 170 | |||
| 171 | #define NoValue 0x0000 | ||
| 172 | #define XValue 0x0001 | ||
| 173 | #define YValue 0x0002 | ||
| 174 | #define WidthValue 0x0004 | ||
| 175 | #define HeightValue 0x0008 | ||
| 176 | #define AllValues 0x000F | ||
| 177 | #define XNegative 0x0010 | ||
| 178 | #define YNegative 0x0020 | ||
| 179 | |||
| 180 | #define USPosition (1L << 0) /* user specified x, y */ | ||
| 181 | #define USSize (1L << 1) /* user specified width, height */ | ||
| 182 | #define PPosition (1L << 2) /* program specified position */ | ||
| 183 | #define PSize (1L << 3) /* program specified size */ | ||
| 184 | #define PMinSize (1L << 4) /* program specified minimum size */ | ||
| 185 | #define PMaxSize (1L << 5) /* program specified maximum size */ | ||
| 186 | #define PResizeInc (1L << 6) /* program specified resize increments */ | ||
| 187 | #define PAspect (1L << 7) /* program specified min, max aspect ratios */ | ||
| 188 | #define PBaseSize (1L << 8) /* program specified base for incrementing */ | ||
| 189 | #define PWinGravity (1L << 9) /* program specified window gravity */ | ||
| 190 | |||
| 191 | #ifndef ANDROID_STUBIFY | ||
| 192 | |||
| 193 | /* Universal NULL handle. */ | ||
| 194 | static const int ANDROID_NONE; | ||
| 195 | |||
| 196 | /* Keep these as conceptually close to X as possible: that makes | ||
| 197 | synchronizing code between the ports much easier. */ | ||
| 198 | |||
| 199 | enum android_event_type | ||
| 200 | { | ||
| 201 | ANDROID_KEY_PRESS, | ||
| 202 | ANDROID_KEY_RELEASE, | ||
| 203 | ANDROID_CONFIGURE_NOTIFY, | ||
| 204 | }; | ||
| 205 | |||
| 206 | struct android_any_event | ||
| 207 | { | ||
| 208 | enum android_event_type type; | ||
| 209 | android_window window; | ||
| 210 | }; | ||
| 211 | |||
| 212 | struct android_key_event | ||
| 213 | { | ||
| 214 | enum android_event_type type; | ||
| 215 | android_window window; | ||
| 216 | android_time time; | ||
| 217 | unsigned int state; | ||
| 218 | unsigned int keycode; | ||
| 219 | }; | ||
| 220 | |||
| 221 | struct android_configure_event | ||
| 222 | { | ||
| 223 | enum android_event_type type; | ||
| 224 | android_window window; | ||
| 225 | android_time time; | ||
| 226 | int x, y; | ||
| 227 | int width, height; | ||
| 228 | }; | ||
| 229 | |||
| 230 | union android_event | ||
| 231 | { | ||
| 232 | enum android_event_type type; | ||
| 233 | struct android_any_event xany; | ||
| 234 | struct android_key_event xkey; | ||
| 235 | struct android_configure_event xconfigure; | ||
| 236 | }; | ||
| 237 | |||
| 238 | extern int android_pending (void); | ||
| 239 | extern void android_next_event (union android_event *); | ||
| 240 | |||
| 241 | extern android_window android_create_window (android_window, int, | ||
| 242 | int, int, int, | ||
| 243 | enum android_window_value_mask, | ||
| 244 | struct | ||
| 245 | android_set_window_attributes *); | ||
| 246 | extern void android_change_window_attributes (android_window, | ||
| 247 | enum android_window_value_mask, | ||
| 248 | struct | ||
| 249 | android_set_window_attributes *); | ||
| 250 | extern void android_set_window_background (android_window, unsigned long); | ||
| 251 | extern void android_destroy_window (android_window); | ||
| 252 | extern void android_reparent_window (android_window, android_window, | ||
| 253 | int, int); | ||
| 254 | extern void android_set_clip_rectangles (struct android_gc *, | ||
| 255 | int, int, | ||
| 256 | struct android_rectangle *, | ||
| 257 | int); | ||
| 258 | extern void android_change_gc (struct android_gc *, | ||
| 259 | enum android_gc_value_mask, | ||
| 260 | struct android_gc_values *); | ||
| 261 | |||
| 262 | extern void android_clear_window (android_window); | ||
| 263 | extern void android_map_window (android_window); | ||
| 264 | extern void android_unmap_window (android_window); | ||
| 265 | extern void android_resize_window (android_window, unsigned int, | ||
| 266 | unsigned int); | ||
| 267 | extern void android_move_window (android_window, int, int); | ||
| 268 | extern void android_swap_buffers (struct android_swap_info *, int); | ||
| 269 | extern void android_get_gc_values (struct android_gc *, | ||
| 270 | enum android_gc_value_mask, | ||
| 271 | struct android_gc_values *); | ||
| 272 | extern void android_set_foreground (struct android_gc *, | ||
| 273 | unsigned long); | ||
| 274 | extern void android_fill_rectangle (android_drawable, struct android_gc *, | ||
| 275 | int, int, unsigned int, unsigned int); | ||
| 276 | extern android_pixmap android_create_pixmap_from_bitmap_data (char *, | ||
| 277 | unsigned int, | ||
| 278 | unsigned int, | ||
| 279 | unsigned long, | ||
| 280 | unsigned long, | ||
| 281 | unsigned int); | ||
| 282 | extern void android_set_clip_mask (struct android_gc *, android_pixmap); | ||
| 283 | extern void android_set_fill_style (struct android_gc *, | ||
| 284 | enum android_fill_style); | ||
| 285 | extern void android_copy_area (android_drawable, android_drawable, | ||
| 286 | struct android_gc *, int, int, | ||
| 287 | unsigned int, unsigned int, int, int); | ||
| 288 | extern void android_free_pixmap (android_drawable); | ||
| 289 | |||
| 290 | extern void android_set_background (struct android_gc *, unsigned long); | ||
| 291 | extern void android_fill_polygon (android_drawable, struct android_gc *, | ||
| 292 | struct android_point *, int, | ||
| 293 | enum android_shape, | ||
| 294 | enum android_coord_mode); | ||
| 295 | extern void android_draw_rectangle (android_drawable, struct android_gc *, | ||
| 296 | int, int, unsigned int, unsigned int); | ||
| 297 | extern void android_draw_point (android_window, struct android_gc *, | ||
| 298 | int, int); | ||
| 299 | extern void android_draw_line (android_window, struct android_gc *, | ||
| 300 | int, int, int, int); | ||
| 301 | extern android_pixmap android_create_pixmap (unsigned int, unsigned int, | ||
| 302 | int); | ||
| 303 | extern void android_set_ts_origin (struct android_gc *, int, int); | ||
| 304 | extern void android_clear_area (android_window, int, int, unsigned int, | ||
| 305 | unsigned int); | ||
| 306 | |||
| 307 | #endif | ||
| 308 | |||
| 309 | /* X emulation stuff also needed while building stubs. */ | ||
| 310 | |||
| 311 | extern struct android_gc *android_create_gc (enum android_gc_value_mask, | ||
| 312 | struct android_gc_values *); | ||
| 313 | extern void android_free_gc (struct android_gc *); | ||
| 314 | |||
| 315 | #endif /* _ANDROID_GUI_H_ */ | ||
diff --git a/src/androidterm.c b/src/androidterm.c new file mode 100644 index 00000000000..bb3c2a29737 --- /dev/null +++ b/src/androidterm.c | |||
| @@ -0,0 +1,3161 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <stdio.h> | ||
| 22 | |||
| 23 | #include "lisp.h" | ||
| 24 | #include "androidterm.h" | ||
| 25 | #include "keyboard.h" | ||
| 26 | #include "blockinput.h" | ||
| 27 | #include "android.h" | ||
| 28 | #include "buffer.h" | ||
| 29 | #include "window.h" | ||
| 30 | |||
| 31 | /* This is a chain of structures for all the X displays currently in | ||
| 32 | use. */ | ||
| 33 | |||
| 34 | struct android_display_info *x_display_list; | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* Android terminal interface functions. */ | ||
| 39 | |||
| 40 | #ifndef ANDROID_STUBIFY | ||
| 41 | |||
| 42 | enum | ||
| 43 | { | ||
| 44 | ANDROID_EVENT_NORMAL, | ||
| 45 | ANDROID_EVENT_GOTO_OUT, | ||
| 46 | ANDROID_EVENT_DROP, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct frame * | ||
| 50 | android_window_to_frame (struct android_display_info *dpyinfo, | ||
| 51 | android_window wdesc) | ||
| 52 | { | ||
| 53 | Lisp_Object tail, frame; | ||
| 54 | struct frame *f; | ||
| 55 | |||
| 56 | if (wdesc == ANDROID_NONE) | ||
| 57 | return NULL; | ||
| 58 | |||
| 59 | FOR_EACH_FRAME (tail, frame) | ||
| 60 | { | ||
| 61 | f = XFRAME (frame); | ||
| 62 | |||
| 63 | if (!FRAME_ANDROID_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo) | ||
| 64 | continue; | ||
| 65 | |||
| 66 | if (FRAME_ANDROID_WINDOW (f) == wdesc) | ||
| 67 | return f; | ||
| 68 | } | ||
| 69 | |||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void | ||
| 74 | android_clear_frame (struct frame *f) | ||
| 75 | { | ||
| 76 | /* Clearing the frame will erase any cursor, so mark them all as no | ||
| 77 | longer visible. */ | ||
| 78 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | ||
| 79 | android_clear_window (FRAME_ANDROID_WINDOW (f)); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void | ||
| 83 | android_ring_bell (struct frame *f) | ||
| 84 | { | ||
| 85 | /* TODO */ | ||
| 86 | } | ||
| 87 | |||
| 88 | static void | ||
| 89 | android_toggle_invisible_pointer (struct frame *f, bool invisible) | ||
| 90 | { | ||
| 91 | /* TODO */ | ||
| 92 | } | ||
| 93 | |||
| 94 | /* Start an update of frame F. This function is installed as a hook | ||
| 95 | for update_begin, i.e. it is called when update_begin is called. | ||
| 96 | This function is called prior to calls to gui_update_window_begin | ||
| 97 | for each window being updated. Currently, there is nothing to do | ||
| 98 | here because all interesting stuff is done on a window basis. */ | ||
| 99 | |||
| 100 | static void | ||
| 101 | android_update_begin (struct frame *f) | ||
| 102 | { | ||
| 103 | /* The frame is no longer complete, as it is in the midst of an | ||
| 104 | update. */ | ||
| 105 | FRAME_ANDROID_COMPLETE_P (f) = false; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* End update of frame F. This function is installed as a hook in | ||
| 109 | update_end. */ | ||
| 110 | |||
| 111 | static void | ||
| 112 | android_update_end (struct frame *f) | ||
| 113 | { | ||
| 114 | /* Mouse highlight may be displayed again. */ | ||
| 115 | MOUSE_HL_INFO (f)->mouse_face_defer = false; | ||
| 116 | } | ||
| 117 | |||
| 118 | static void | ||
| 119 | show_back_buffer (struct frame *f) | ||
| 120 | { | ||
| 121 | struct android_swap_info swap_info; | ||
| 122 | |||
| 123 | memset (&swap_info, 0, sizeof (swap_info)); | ||
| 124 | swap_info.swap_window = FRAME_ANDROID_WINDOW (f); | ||
| 125 | swap_info.swap_action = ANDROID_COPIED; | ||
| 126 | android_swap_buffers (&swap_info, 1); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Flip back buffers on F if it has undrawn content. */ | ||
| 130 | |||
| 131 | static void | ||
| 132 | android_flush_dirty_back_buffer_on (struct frame *f) | ||
| 133 | { | ||
| 134 | if (FRAME_GARBAGED_P (f) | ||
| 135 | || buffer_flipping_blocked_p () | ||
| 136 | /* If the frame is not already up to date, do not flush buffers | ||
| 137 | on input, as that will result in flicker. */ | ||
| 138 | || !FRAME_ANDROID_COMPLETE_P (f)) | ||
| 139 | return; | ||
| 140 | |||
| 141 | show_back_buffer (f); | ||
| 142 | } | ||
| 143 | |||
| 144 | static int | ||
| 145 | handle_one_android_event (struct android_display_info *dpyinfo, | ||
| 146 | union android_event *event, int *finish, | ||
| 147 | struct input_event *hold_quit) | ||
| 148 | { | ||
| 149 | union android_event configureEvent; | ||
| 150 | struct frame *f, *any, *mouse_frame; | ||
| 151 | Mouse_HLInfo *hlinfo; | ||
| 152 | |||
| 153 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 154 | *finish = ANDROID_EVENT_NORMAL; | ||
| 155 | any = android_window_to_frame (dpyinfo, event->xany.window); | ||
| 156 | |||
| 157 | switch (event->type) | ||
| 158 | { | ||
| 159 | case ANDROID_CONFIGURE_NOTIFY: | ||
| 160 | configureEvent = *event; | ||
| 161 | |||
| 162 | f = android_window_to_frame (dpyinfo, | ||
| 163 | configureEvent.xconfigure.window); | ||
| 164 | |||
| 165 | int width = configureEvent.xconfigure.width; | ||
| 166 | int height = configureEvent.xconfigure.height; | ||
| 167 | |||
| 168 | if (CONSP (frame_size_history)) | ||
| 169 | frame_size_history_extra (f, build_string ("ConfigureNotify"), | ||
| 170 | FRAME_PIXEL_WIDTH (f), | ||
| 171 | FRAME_PIXEL_HEIGHT (f), | ||
| 172 | width, height, f->new_width, | ||
| 173 | f->new_height); | ||
| 174 | |||
| 175 | /* Even if the number of character rows and columns has | ||
| 176 | not changed, the font size may have changed, so we need | ||
| 177 | to check the pixel dimensions as well. */ | ||
| 178 | |||
| 179 | if (width != FRAME_PIXEL_WIDTH (f) | ||
| 180 | || height != FRAME_PIXEL_HEIGHT (f) | ||
| 181 | || (f->new_size_p | ||
| 182 | && ((f->new_width >= 0 && width != f->new_width) | ||
| 183 | || (f->new_height >= 0 && height != f->new_height)))) | ||
| 184 | { | ||
| 185 | change_frame_size (f, width, height, false, true, false); | ||
| 186 | android_clear_under_internal_border (f); | ||
| 187 | SET_FRAME_GARBAGED (f); | ||
| 188 | cancel_mouse_face (f); | ||
| 189 | } | ||
| 190 | |||
| 191 | goto OTHER; | ||
| 192 | |||
| 193 | case ANDROID_KEY_PRESS: | ||
| 194 | |||
| 195 | /* If mouse-highlight is an integer, input clears out | ||
| 196 | mouse highlighting. */ | ||
| 197 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | ||
| 198 | && (any == 0 | ||
| 199 | || !EQ (f->tool_bar_window, hlinfo->mouse_face_window) | ||
| 200 | || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))) | ||
| 201 | { | ||
| 202 | mouse_frame = hlinfo->mouse_face_mouse_frame; | ||
| 203 | |||
| 204 | clear_mouse_face (hlinfo); | ||
| 205 | hlinfo->mouse_face_hidden = true; | ||
| 206 | |||
| 207 | if (mouse_frame) | ||
| 208 | android_flush_dirty_back_buffer_on (mouse_frame); | ||
| 209 | } | ||
| 210 | |||
| 211 | default: | ||
| 212 | goto OTHER; | ||
| 213 | } | ||
| 214 | |||
| 215 | OTHER: | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int | ||
| 221 | android_read_socket (struct terminal *terminal, | ||
| 222 | struct input_event *hold_quit) | ||
| 223 | { | ||
| 224 | int count = 0; | ||
| 225 | struct android_display_info *dpyinfo; | ||
| 226 | |||
| 227 | dpyinfo = terminal->display_info.android; | ||
| 228 | |||
| 229 | block_input (); | ||
| 230 | while (android_pending ()) | ||
| 231 | { | ||
| 232 | int finish; | ||
| 233 | union android_event event; | ||
| 234 | |||
| 235 | android_next_event (&event); | ||
| 236 | count += handle_one_android_event (dpyinfo, &event, &finish, | ||
| 237 | hold_quit); | ||
| 238 | |||
| 239 | if (finish == ANDROID_EVENT_GOTO_OUT) | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | unblock_input (); | ||
| 243 | |||
| 244 | /* If the focus was just given to an auto-raising frame, raise it | ||
| 245 | now. */ | ||
| 246 | if (dpyinfo->pending_autoraise_frame) | ||
| 247 | { | ||
| 248 | /* android_raise_frame (dpyinfo->pending_autoraise_frame); | ||
| 249 | TODO */ | ||
| 250 | dpyinfo->pending_autoraise_frame = NULL; | ||
| 251 | } | ||
| 252 | |||
| 253 | return count; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void | ||
| 257 | android_frame_up_to_date (struct frame *f) | ||
| 258 | { | ||
| 259 | eassert (FRAME_ANDROID_P (f)); | ||
| 260 | block_input (); | ||
| 261 | FRAME_MOUSE_UPDATE (f); | ||
| 262 | |||
| 263 | if (!buffer_flipping_blocked_p ()) | ||
| 264 | show_back_buffer (f); | ||
| 265 | |||
| 266 | /* The frame is now complete, as its contents have been drawn. */ | ||
| 267 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 268 | unblock_input (); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void | ||
| 272 | android_buffer_flipping_unblocked_hook (struct frame *f) | ||
| 273 | { | ||
| 274 | block_input (); | ||
| 275 | show_back_buffer (f); | ||
| 276 | unblock_input (); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void | ||
| 280 | android_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) | ||
| 281 | { | ||
| 282 | unsigned long background; | ||
| 283 | |||
| 284 | background = FRAME_BACKGROUND_PIXEL (f); | ||
| 285 | bgcolor->pixel = background; | ||
| 286 | |||
| 287 | android_query_colors (f, bgcolor, 1); | ||
| 288 | } | ||
| 289 | |||
| 290 | int | ||
| 291 | android_parse_color (struct frame *f, const char *color_name, | ||
| 292 | Emacs_Color *color) | ||
| 293 | { | ||
| 294 | unsigned short r, g, b; | ||
| 295 | Lisp_Object tem, tem1; | ||
| 296 | unsigned long lisp_color; | ||
| 297 | |||
| 298 | if (parse_color_spec (color_name, &r, &g, &b)) | ||
| 299 | { | ||
| 300 | color->red = r; | ||
| 301 | color->green = g; | ||
| 302 | color->blue = b; | ||
| 303 | |||
| 304 | return 1; | ||
| 305 | } | ||
| 306 | |||
| 307 | tem = x_display_list->color_map; | ||
| 308 | for (; CONSP (tem); tem = XCDR (tem)) | ||
| 309 | { | ||
| 310 | tem1 = XCAR (tem); | ||
| 311 | |||
| 312 | if (CONSP (tem1) | ||
| 313 | && !xstrcasecmp (SSDATA (XCAR (tem1)), color_name)) | ||
| 314 | { | ||
| 315 | lisp_color = XFIXNUM (XCDR (tem1)); | ||
| 316 | color->red = RED_FROM_ULONG (lisp_color) * 257; | ||
| 317 | color->green = GREEN_FROM_ULONG (lisp_color) * 257; | ||
| 318 | color->blue = BLUE_FROM_ULONG (lisp_color) * 257; | ||
| 319 | return 1; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | bool | ||
| 327 | android_alloc_nearest_color (struct frame *f, Emacs_Color *color) | ||
| 328 | { | ||
| 329 | gamma_correct (f, color); | ||
| 330 | color->pixel = RGB_TO_ULONG (color->red / 256, | ||
| 331 | color->green / 256, | ||
| 332 | color->blue / 256); | ||
| 333 | |||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | void | ||
| 338 | android_query_colors (struct frame *f, Emacs_Color *colors, int ncolors) | ||
| 339 | { | ||
| 340 | int i; | ||
| 341 | |||
| 342 | for (i = 0; i < ncolors; ++i) | ||
| 343 | { | ||
| 344 | colors[i].red = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 345 | colors[i].green = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 346 | colors[i].blue = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | static void | ||
| 351 | android_mouse_position (struct frame **fp, int insist, | ||
| 352 | Lisp_Object *bar_window, | ||
| 353 | enum scroll_bar_part *part, Lisp_Object *x, | ||
| 354 | Lisp_Object *y, Time *timestamp) | ||
| 355 | { | ||
| 356 | /* TODO */ | ||
| 357 | } | ||
| 358 | |||
| 359 | static Lisp_Object | ||
| 360 | android_get_focus_frame (struct frame *f) | ||
| 361 | { | ||
| 362 | Lisp_Object lisp_focus; | ||
| 363 | struct frame *focus; | ||
| 364 | |||
| 365 | focus = FRAME_DISPLAY_INFO (f)->focus_frame; | ||
| 366 | |||
| 367 | if (!focus) | ||
| 368 | return Qnil; | ||
| 369 | |||
| 370 | XSETFRAME (lisp_focus, focus); | ||
| 371 | return lisp_focus; | ||
| 372 | } | ||
| 373 | |||
| 374 | static void | ||
| 375 | android_focus_frame (struct frame *f, bool noactivate) | ||
| 376 | { | ||
| 377 | /* TODO */ | ||
| 378 | } | ||
| 379 | |||
| 380 | static void | ||
| 381 | android_frame_rehighlight (struct frame *f) | ||
| 382 | { | ||
| 383 | /* TODO */ | ||
| 384 | } | ||
| 385 | |||
| 386 | static void | ||
| 387 | android_frame_raise_lower (struct frame *f, bool raise_flag) | ||
| 388 | { | ||
| 389 | /* TODO */ | ||
| 390 | } | ||
| 391 | |||
| 392 | void | ||
| 393 | android_make_frame_visible (struct frame *f) | ||
| 394 | { | ||
| 395 | android_map_window (FRAME_ANDROID_WINDOW (f)); | ||
| 396 | |||
| 397 | SET_FRAME_VISIBLE (f, true); | ||
| 398 | SET_FRAME_ICONIFIED (f, false); | ||
| 399 | } | ||
| 400 | |||
| 401 | void | ||
| 402 | android_make_frame_invisible (struct frame *f) | ||
| 403 | { | ||
| 404 | android_unmap_window (FRAME_ANDROID_WINDOW (f)); | ||
| 405 | |||
| 406 | SET_FRAME_VISIBLE (f, false); | ||
| 407 | SET_FRAME_ICONIFIED (f, false); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void | ||
| 411 | android_make_frame_visible_invisible (struct frame *f, bool visible) | ||
| 412 | { | ||
| 413 | if (visible) | ||
| 414 | android_make_frame_visible (f); | ||
| 415 | else | ||
| 416 | android_make_frame_invisible (f); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void | ||
| 420 | android_fullscreen_hook (struct frame *f) | ||
| 421 | { | ||
| 422 | /* TODO */ | ||
| 423 | } | ||
| 424 | |||
| 425 | void | ||
| 426 | android_iconify_frame (struct frame *f) | ||
| 427 | { | ||
| 428 | /* TODO */ | ||
| 429 | } | ||
| 430 | |||
| 431 | static void | ||
| 432 | android_set_window_size_1 (struct frame *f, bool change_gravity, | ||
| 433 | int width, int height) | ||
| 434 | { | ||
| 435 | if (change_gravity) | ||
| 436 | f->win_gravity = NorthWestGravity; | ||
| 437 | |||
| 438 | android_resize_window (FRAME_ANDROID_WINDOW (f), width, | ||
| 439 | height); | ||
| 440 | |||
| 441 | /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to | ||
| 442 | receive in the ConfigureNotify event; if we get what we asked | ||
| 443 | for, then the event won't cause the screen to become garbaged, so | ||
| 444 | we have to make sure to do it here. */ | ||
| 445 | SET_FRAME_GARBAGED (f); | ||
| 446 | } | ||
| 447 | |||
| 448 | void | ||
| 449 | android_set_window_size (struct frame *f, bool change_gravity, | ||
| 450 | int width, int height) | ||
| 451 | { | ||
| 452 | block_input (); | ||
| 453 | |||
| 454 | android_set_window_size_1 (f, change_gravity, width, height); | ||
| 455 | android_clear_under_internal_border (f); | ||
| 456 | |||
| 457 | /* If cursor was outside the new size, mark it as off. */ | ||
| 458 | mark_window_cursors_off (XWINDOW (f->root_window)); | ||
| 459 | |||
| 460 | /* Clear out any recollection of where the mouse highlighting was, | ||
| 461 | since it might be in a place that's outside the new frame size. | ||
| 462 | Actually checking whether it is outside is a pain in the neck, | ||
| 463 | so don't try--just let the highlighting be done afresh with new size. */ | ||
| 464 | cancel_mouse_face (f); | ||
| 465 | |||
| 466 | unblock_input (); | ||
| 467 | |||
| 468 | do_pending_window_change (false); | ||
| 469 | } | ||
| 470 | |||
| 471 | static void | ||
| 472 | android_set_offset (struct frame *f, int xoff, int yoff, | ||
| 473 | int change_gravity) | ||
| 474 | { | ||
| 475 | if (change_gravity > 0) | ||
| 476 | { | ||
| 477 | f->top_pos = yoff; | ||
| 478 | f->left_pos = xoff; | ||
| 479 | f->size_hint_flags &= ~ (XNegative | YNegative); | ||
| 480 | if (xoff < 0) | ||
| 481 | f->size_hint_flags |= XNegative; | ||
| 482 | if (yoff < 0) | ||
| 483 | f->size_hint_flags |= YNegative; | ||
| 484 | f->win_gravity = NorthWestGravity; | ||
| 485 | } | ||
| 486 | |||
| 487 | android_move_window (FRAME_ANDROID_WINDOW (f), xoff, yoff); | ||
| 488 | } | ||
| 489 | |||
| 490 | static void | ||
| 491 | android_set_alpha (struct frame *f) | ||
| 492 | { | ||
| 493 | /* TODO */ | ||
| 494 | } | ||
| 495 | |||
| 496 | static Lisp_Object | ||
| 497 | android_new_font (struct frame *f, Lisp_Object font_object, int fontset) | ||
| 498 | { | ||
| 499 | struct font *font = XFONT_OBJECT (font_object); | ||
| 500 | int unit, font_ascent, font_descent; | ||
| 501 | |||
| 502 | if (fontset < 0) | ||
| 503 | fontset = fontset_from_font (font_object); | ||
| 504 | FRAME_FONTSET (f) = fontset; | ||
| 505 | if (FRAME_FONT (f) == font) | ||
| 506 | /* This font is already set in frame F. There's nothing more to | ||
| 507 | do. */ | ||
| 508 | return font_object; | ||
| 509 | |||
| 510 | FRAME_FONT (f) = font; | ||
| 511 | FRAME_BASELINE_OFFSET (f) = font->baseline_offset; | ||
| 512 | FRAME_COLUMN_WIDTH (f) = font->average_width; | ||
| 513 | get_font_ascent_descent (font, &font_ascent, &font_descent); | ||
| 514 | FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; | ||
| 515 | |||
| 516 | /* We could use a more elaborate calculation here. */ | ||
| 517 | FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | ||
| 518 | |||
| 519 | /* Compute character columns occupied by scrollbar. | ||
| 520 | |||
| 521 | Don't do things differently for non-toolkit scrollbars | ||
| 522 | (Bug#17163). */ | ||
| 523 | unit = FRAME_COLUMN_WIDTH (f); | ||
| 524 | if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) | ||
| 525 | FRAME_CONFIG_SCROLL_BAR_COLS (f) | ||
| 526 | = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; | ||
| 527 | else | ||
| 528 | FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; | ||
| 529 | |||
| 530 | |||
| 531 | /* Don't change the size of a tip frame; there's no point in doing it | ||
| 532 | because it's done in Fx_show_tip, and it leads to problems because | ||
| 533 | the tip frame has no widget. */ | ||
| 534 | if (FRAME_ANDROID_WINDOW (f) != 0 && !FRAME_TOOLTIP_P (f)) | ||
| 535 | adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), | ||
| 536 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, | ||
| 537 | false, Qfont); | ||
| 538 | |||
| 539 | return font_object; | ||
| 540 | } | ||
| 541 | |||
| 542 | static bool | ||
| 543 | android_bitmap_icon (struct frame *f, Lisp_Object file) | ||
| 544 | { | ||
| 545 | /* TODO */ | ||
| 546 | return false; | ||
| 547 | } | ||
| 548 | |||
| 549 | static void | ||
| 550 | android_free_pixmap_hook (struct frame *f, Emacs_Pixmap pixmap) | ||
| 551 | { | ||
| 552 | android_free_pixmap (pixmap); | ||
| 553 | } | ||
| 554 | |||
| 555 | void | ||
| 556 | android_free_frame_resources (struct frame *f) | ||
| 557 | { | ||
| 558 | struct android_display_info *dpyinfo; | ||
| 559 | Mouse_HLInfo *hlinfo; | ||
| 560 | |||
| 561 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 562 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 563 | |||
| 564 | block_input (); | ||
| 565 | free_frame_faces (f); | ||
| 566 | |||
| 567 | /* FRAME_ANDROID_WINDOW can be 0 if frame creation failed. */ | ||
| 568 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 569 | android_destroy_window (FRAME_ANDROID_WINDOW (f)); | ||
| 570 | |||
| 571 | android_free_gcs (f); | ||
| 572 | |||
| 573 | /* Free extra GCs allocated by android_setup_relief_colors. */ | ||
| 574 | if (f->output_data.android->white_relief.gc) | ||
| 575 | { | ||
| 576 | android_free_gc (f->output_data.android->white_relief.gc); | ||
| 577 | f->output_data.android->white_relief.gc = 0; | ||
| 578 | } | ||
| 579 | if (f->output_data.android->black_relief.gc) | ||
| 580 | { | ||
| 581 | android_free_gc (f->output_data.android->black_relief.gc); | ||
| 582 | f->output_data.android->black_relief.gc = 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | if (f == dpyinfo->focus_frame) | ||
| 586 | dpyinfo->focus_frame = 0; | ||
| 587 | if (f == dpyinfo->highlight_frame) | ||
| 588 | dpyinfo->highlight_frame = 0; | ||
| 589 | if (f == hlinfo->mouse_face_mouse_frame) | ||
| 590 | reset_mouse_highlight (hlinfo); | ||
| 591 | |||
| 592 | unblock_input (); | ||
| 593 | } | ||
| 594 | |||
| 595 | static void | ||
| 596 | android_delete_frame (struct frame *f) | ||
| 597 | { | ||
| 598 | android_free_frame_resources (f); | ||
| 599 | xfree (f->output_data.android); | ||
| 600 | f->output_data.android = NULL; | ||
| 601 | } | ||
| 602 | |||
| 603 | static void | ||
| 604 | android_delete_terminal (struct terminal *terminal) | ||
| 605 | { | ||
| 606 | error ("Cannot terminate connection to Android display server"); | ||
| 607 | } | ||
| 608 | |||
| 609 | |||
| 610 | |||
| 611 | /* RIF functions. */ | ||
| 612 | |||
| 613 | static void | ||
| 614 | android_scroll_run (struct window *w, struct run *run) | ||
| 615 | { | ||
| 616 | struct frame *f = XFRAME (w->frame); | ||
| 617 | int x, y, width, height, from_y, to_y, bottom_y; | ||
| 618 | |||
| 619 | /* Get frame-relative bounding box of the text display area of W, | ||
| 620 | without mode lines. Include in this box the left and right | ||
| 621 | fringe of W. */ | ||
| 622 | window_box (w, ANY_AREA, &x, &y, &width, &height); | ||
| 623 | |||
| 624 | from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); | ||
| 625 | to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); | ||
| 626 | bottom_y = y + height; | ||
| 627 | |||
| 628 | if (to_y < from_y) | ||
| 629 | { | ||
| 630 | /* Scrolling up. Make sure we don't copy part of the mode | ||
| 631 | line at the bottom. */ | ||
| 632 | if (from_y + run->height > bottom_y) | ||
| 633 | height = bottom_y - from_y; | ||
| 634 | else | ||
| 635 | height = run->height; | ||
| 636 | } | ||
| 637 | else | ||
| 638 | { | ||
| 639 | /* Scrolling down. Make sure we don't copy over the mode line. | ||
| 640 | at the bottom. */ | ||
| 641 | if (to_y + run->height > bottom_y) | ||
| 642 | height = bottom_y - to_y; | ||
| 643 | else | ||
| 644 | height = run->height; | ||
| 645 | } | ||
| 646 | |||
| 647 | block_input (); | ||
| 648 | |||
| 649 | /* Cursor off. Will be switched on again in gui_update_window_end. */ | ||
| 650 | gui_clear_cursor (w); | ||
| 651 | |||
| 652 | android_copy_area (FRAME_ANDROID_WINDOW (f), | ||
| 653 | FRAME_ANDROID_WINDOW (f), | ||
| 654 | f->output_data.android->normal_gc, | ||
| 655 | x, from_y, width, height, x, to_y); | ||
| 656 | |||
| 657 | unblock_input (); | ||
| 658 | } | ||
| 659 | |||
| 660 | static void | ||
| 661 | android_after_update_window_line (struct window *w, struct glyph_row *desired_row) | ||
| 662 | { | ||
| 663 | eassert (w); | ||
| 664 | |||
| 665 | if (!desired_row->mode_line_p && !w->pseudo_window_p) | ||
| 666 | desired_row->redraw_fringe_bitmaps_p = true; | ||
| 667 | } | ||
| 668 | |||
| 669 | static void | ||
| 670 | android_flip_and_flush (struct frame *f) | ||
| 671 | { | ||
| 672 | block_input (); | ||
| 673 | show_back_buffer (f); | ||
| 674 | |||
| 675 | /* The frame is complete again as its contents were just | ||
| 676 | flushed. */ | ||
| 677 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 678 | unblock_input (); | ||
| 679 | } | ||
| 680 | |||
| 681 | static void | ||
| 682 | android_clear_rectangle (struct frame *f, struct android_gc *gc, int x, | ||
| 683 | int y, int width, int height) | ||
| 684 | { | ||
| 685 | struct android_gc_values xgcv; | ||
| 686 | |||
| 687 | android_get_gc_values (gc, (ANDROID_GC_BACKGROUND | ||
| 688 | | ANDROID_GC_FOREGROUND), | ||
| 689 | &xgcv); | ||
| 690 | android_set_foreground (gc, xgcv.background); | ||
| 691 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 692 | x, y, width, height); | ||
| 693 | android_set_foreground (gc, xgcv.foreground); | ||
| 694 | } | ||
| 695 | |||
| 696 | static void | ||
| 697 | android_reset_clip_rectangles (struct frame *f, struct android_gc *gc) | ||
| 698 | { | ||
| 699 | android_set_clip_mask (gc, ANDROID_NONE); | ||
| 700 | } | ||
| 701 | |||
| 702 | static void | ||
| 703 | android_clip_to_row (struct window *w, struct glyph_row *row, | ||
| 704 | enum glyph_row_area area, struct android_gc *gc) | ||
| 705 | { | ||
| 706 | struct android_rectangle clip_rect; | ||
| 707 | int window_x, window_y, window_width; | ||
| 708 | |||
| 709 | window_box (w, area, &window_x, &window_y, &window_width, 0); | ||
| 710 | |||
| 711 | clip_rect.x = window_x; | ||
| 712 | clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); | ||
| 713 | clip_rect.y = max (clip_rect.y, window_y); | ||
| 714 | clip_rect.width = window_width; | ||
| 715 | clip_rect.height = row->visible_height; | ||
| 716 | |||
| 717 | android_set_clip_rectangles (gc, 0, 0, &clip_rect, 1); | ||
| 718 | } | ||
| 719 | |||
| 720 | static void | ||
| 721 | android_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | ||
| 722 | struct draw_fringe_bitmap_params *p) | ||
| 723 | { | ||
| 724 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 725 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 726 | struct face *face = p->face; | ||
| 727 | |||
| 728 | /* Must clip because of partially visible lines. */ | ||
| 729 | android_clip_to_row (w, row, ANY_AREA, gc); | ||
| 730 | |||
| 731 | if (p->bx >= 0 && !p->overlay_p) | ||
| 732 | { | ||
| 733 | /* In case the same realized face is used for fringes and for | ||
| 734 | something displayed in the text (e.g. face `region' on | ||
| 735 | mono-displays, the fill style may have been changed to | ||
| 736 | ANDROID_FILL_SOLID in | ||
| 737 | android_draw_glyph_string_background. */ | ||
| 738 | if (face->stipple) | ||
| 739 | { | ||
| 740 | android_set_fill_style (face->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 741 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), face->gc, | ||
| 742 | p->bx, p->by, p->nx, p->ny); | ||
| 743 | android_set_fill_style (face->gc, ANDROID_FILL_SOLID); | ||
| 744 | |||
| 745 | row->stipple_p = true; | ||
| 746 | } | ||
| 747 | else | ||
| 748 | { | ||
| 749 | android_set_background (face->gc, face->background); | ||
| 750 | android_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny); | ||
| 751 | android_set_foreground (face->gc, face->foreground); | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | if (p->which) | ||
| 756 | { | ||
| 757 | android_drawable drawable; | ||
| 758 | char *bits; | ||
| 759 | android_pixmap pixmap, clipmask; | ||
| 760 | struct android_gc_values gcv; | ||
| 761 | unsigned long background, cursor_pixel; | ||
| 762 | int depth; | ||
| 763 | |||
| 764 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 765 | clipmask = ANDROID_NONE; | ||
| 766 | background = face->background; | ||
| 767 | cursor_pixel = f->output_data.android->cursor_pixel; | ||
| 768 | depth = FRAME_DISPLAY_INFO (f)->n_planes; | ||
| 769 | |||
| 770 | if (p->wd > 8) | ||
| 771 | bits = (char *) (p->bits + p->dh); | ||
| 772 | else | ||
| 773 | bits = (char *) p->bits + p->dh; | ||
| 774 | |||
| 775 | pixmap = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 776 | (p->cursor_p | ||
| 777 | ? (p->overlay_p | ||
| 778 | ? face->background | ||
| 779 | : cursor_pixel) | ||
| 780 | : face->foreground), | ||
| 781 | background, depth); | ||
| 782 | |||
| 783 | if (p->overlay_p) | ||
| 784 | { | ||
| 785 | clipmask = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 786 | 1, 0, 0); | ||
| 787 | |||
| 788 | gcv.clip_mask = clipmask; | ||
| 789 | gcv.clip_x_origin = p->x; | ||
| 790 | gcv.clip_y_origin = p->y; | ||
| 791 | android_change_gc (gc, (ANDROID_GC_CLIP_MASK | ||
| 792 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 793 | | ANDROID_GC_CLIP_Y_ORIGIN), | ||
| 794 | &gcv); | ||
| 795 | } | ||
| 796 | |||
| 797 | android_copy_area (pixmap, drawable, gc, 0, 0, p->wd, p->h, | ||
| 798 | p->x, p->y); | ||
| 799 | android_free_pixmap (pixmap); | ||
| 800 | |||
| 801 | if (p->overlay_p) | ||
| 802 | { | ||
| 803 | gcv.clip_mask = ANDROID_NONE; | ||
| 804 | android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv); | ||
| 805 | android_free_pixmap (clipmask); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | android_reset_clip_rectangles (f, gc); | ||
| 810 | } | ||
| 811 | |||
| 812 | /* Set S->gc to a suitable GC for drawing glyph string S in cursor | ||
| 813 | face. */ | ||
| 814 | |||
| 815 | static void | ||
| 816 | android_set_cursor_gc (struct glyph_string *s) | ||
| 817 | { | ||
| 818 | if (s->font == FRAME_FONT (s->f) | ||
| 819 | && s->face->background == FRAME_BACKGROUND_PIXEL (s->f) | ||
| 820 | && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) | ||
| 821 | && !s->cmp) | ||
| 822 | s->gc = s->f->output_data.android->cursor_gc; | ||
| 823 | else | ||
| 824 | { | ||
| 825 | /* Cursor on non-default face: must merge. */ | ||
| 826 | struct android_gc_values xgcv; | ||
| 827 | unsigned long mask; | ||
| 828 | |||
| 829 | xgcv.background = s->f->output_data.android->cursor_pixel; | ||
| 830 | xgcv.foreground = s->face->background; | ||
| 831 | |||
| 832 | /* If the glyph would be invisible, try a different foreground. */ | ||
| 833 | if (xgcv.foreground == xgcv.background) | ||
| 834 | xgcv.foreground = s->face->foreground; | ||
| 835 | if (xgcv.foreground == xgcv.background) | ||
| 836 | xgcv.foreground = s->f->output_data.android->cursor_foreground_pixel; | ||
| 837 | if (xgcv.foreground == xgcv.background) | ||
| 838 | xgcv.foreground = s->face->foreground; | ||
| 839 | |||
| 840 | /* Make sure the cursor is distinct from text in this face. */ | ||
| 841 | if (xgcv.background == s->face->background | ||
| 842 | && xgcv.foreground == s->face->foreground) | ||
| 843 | { | ||
| 844 | xgcv.background = s->face->foreground; | ||
| 845 | xgcv.foreground = s->face->background; | ||
| 846 | } | ||
| 847 | |||
| 848 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 849 | |||
| 850 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 851 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 852 | mask, &xgcv); | ||
| 853 | else | ||
| 854 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 855 | = android_create_gc (mask, &xgcv); | ||
| 856 | |||
| 857 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | |||
| 861 | |||
| 862 | /* Set up S->gc of glyph string S for drawing text in mouse face. */ | ||
| 863 | |||
| 864 | static void | ||
| 865 | android_set_mouse_face_gc (struct glyph_string *s) | ||
| 866 | { | ||
| 867 | if (s->font == s->face->font) | ||
| 868 | s->gc = s->face->gc; | ||
| 869 | else | ||
| 870 | { | ||
| 871 | /* Otherwise construct scratch_cursor_gc with values from FACE | ||
| 872 | except for FONT. */ | ||
| 873 | struct android_gc_values xgcv; | ||
| 874 | unsigned long mask; | ||
| 875 | |||
| 876 | xgcv.background = s->face->background; | ||
| 877 | xgcv.foreground = s->face->foreground; | ||
| 878 | |||
| 879 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 880 | |||
| 881 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 882 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 883 | mask, &xgcv); | ||
| 884 | else | ||
| 885 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 886 | = android_create_gc (mask, &xgcv); | ||
| 887 | |||
| 888 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 889 | } | ||
| 890 | |||
| 891 | eassert (s->gc != 0); | ||
| 892 | } | ||
| 893 | |||
| 894 | |||
| 895 | /* Set S->gc of glyph string S to a GC suitable for drawing a mode line. | ||
| 896 | Faces to use in the mode line have already been computed when the | ||
| 897 | matrix was built, so there isn't much to do, here. */ | ||
| 898 | |||
| 899 | static void | ||
| 900 | android_set_mode_line_face_gc (struct glyph_string *s) | ||
| 901 | { | ||
| 902 | s->gc = s->face->gc; | ||
| 903 | } | ||
| 904 | |||
| 905 | /* Set S->gc of glyph string S for drawing that glyph string. Set | ||
| 906 | S->stippled_p to a non-zero value if the face of S has a stipple | ||
| 907 | pattern. */ | ||
| 908 | |||
| 909 | static void | ||
| 910 | android_set_glyph_string_gc (struct glyph_string *s) | ||
| 911 | { | ||
| 912 | prepare_face_for_display (s->f, s->face); | ||
| 913 | |||
| 914 | if (s->hl == DRAW_NORMAL_TEXT) | ||
| 915 | { | ||
| 916 | s->gc = s->face->gc; | ||
| 917 | s->stippled_p = s->face->stipple != 0; | ||
| 918 | } | ||
| 919 | else if (s->hl == DRAW_INVERSE_VIDEO) | ||
| 920 | { | ||
| 921 | android_set_mode_line_face_gc (s); | ||
| 922 | s->stippled_p = s->face->stipple != 0; | ||
| 923 | } | ||
| 924 | else if (s->hl == DRAW_CURSOR) | ||
| 925 | { | ||
| 926 | android_set_cursor_gc (s); | ||
| 927 | s->stippled_p = false; | ||
| 928 | } | ||
| 929 | else if (s->hl == DRAW_MOUSE_FACE) | ||
| 930 | { | ||
| 931 | android_set_mouse_face_gc (s); | ||
| 932 | s->stippled_p = s->face->stipple != 0; | ||
| 933 | } | ||
| 934 | else if (s->hl == DRAW_IMAGE_RAISED | ||
| 935 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 936 | { | ||
| 937 | s->gc = s->face->gc; | ||
| 938 | s->stippled_p = s->face->stipple != 0; | ||
| 939 | } | ||
| 940 | else | ||
| 941 | emacs_abort (); | ||
| 942 | |||
| 943 | /* GC must have been set. */ | ||
| 944 | eassert (s->gc != 0); | ||
| 945 | } | ||
| 946 | |||
| 947 | |||
| 948 | /* Set clipping for output of glyph string S. S may be part of a mode | ||
| 949 | line or menu if we don't have X toolkit support. */ | ||
| 950 | |||
| 951 | static void | ||
| 952 | android_set_glyph_string_clipping (struct glyph_string *s) | ||
| 953 | { | ||
| 954 | struct android_rectangle *r = s->clip; | ||
| 955 | int n = get_glyph_string_clip_rects (s, r, 2); | ||
| 956 | |||
| 957 | if (n > 0) | ||
| 958 | android_set_clip_rectangles (s->gc, 0, 0, r, n); | ||
| 959 | s->num_clips = n; | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | /* Set SRC's clipping for output of glyph string DST. This is called | ||
| 964 | when we are drawing DST's left_overhang or right_overhang only in | ||
| 965 | the area of SRC. */ | ||
| 966 | |||
| 967 | static void | ||
| 968 | android_set_glyph_string_clipping_exactly (struct glyph_string *src, | ||
| 969 | struct glyph_string *dst) | ||
| 970 | { | ||
| 971 | struct android_rectangle r; | ||
| 972 | |||
| 973 | r.x = src->x; | ||
| 974 | r.width = src->width; | ||
| 975 | r.y = src->y; | ||
| 976 | r.height = src->height; | ||
| 977 | dst->clip[0] = r; | ||
| 978 | dst->num_clips = 1; | ||
| 979 | android_set_clip_rectangles (dst->gc, 0, 0, &r, 1); | ||
| 980 | } | ||
| 981 | |||
| 982 | static void | ||
| 983 | android_compute_glyph_string_overhangs (struct glyph_string *s) | ||
| 984 | { | ||
| 985 | if (s->cmp == NULL | ||
| 986 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 987 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 988 | { | ||
| 989 | struct font_metrics metrics; | ||
| 990 | |||
| 991 | if (s->first_glyph->type == CHAR_GLYPH) | ||
| 992 | { | ||
| 993 | struct font *font = s->font; | ||
| 994 | font->driver->text_extents (font, s->char2b, s->nchars, &metrics); | ||
| 995 | } | ||
| 996 | else | ||
| 997 | { | ||
| 998 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 999 | |||
| 1000 | composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); | ||
| 1001 | } | ||
| 1002 | s->right_overhang = (metrics.rbearing > metrics.width | ||
| 1003 | ? metrics.rbearing - metrics.width : 0); | ||
| 1004 | s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; | ||
| 1005 | } | ||
| 1006 | else if (s->cmp) | ||
| 1007 | { | ||
| 1008 | s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; | ||
| 1009 | s->left_overhang = - s->cmp->lbearing; | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static void | ||
| 1014 | android_clear_glyph_string_rect (struct glyph_string *s, int x, int y, | ||
| 1015 | int w, int h) | ||
| 1016 | { | ||
| 1017 | android_clear_rectangle (s->f, s->gc, x, y, w, h); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static void | ||
| 1021 | android_draw_glyph_string_background (struct glyph_string *s, bool force_p) | ||
| 1022 | { | ||
| 1023 | /* Nothing to do if background has already been drawn or if it | ||
| 1024 | shouldn't be drawn in the first place. */ | ||
| 1025 | if (!s->background_filled_p) | ||
| 1026 | { | ||
| 1027 | int box_line_width = max (s->face->box_horizontal_line_width, 0); | ||
| 1028 | |||
| 1029 | if (s->stippled_p) | ||
| 1030 | { | ||
| 1031 | /* Fill background with a stipple pattern. */ | ||
| 1032 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1033 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1034 | s->x, s->y + box_line_width, | ||
| 1035 | s->background_width, | ||
| 1036 | s->height - 2 * box_line_width); | ||
| 1037 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1038 | s->background_filled_p = true; | ||
| 1039 | } | ||
| 1040 | else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width | ||
| 1041 | /* When xdisp.c ignores FONT_HEIGHT, we cannot trust | ||
| 1042 | font dimensions, since the actual glyphs might be | ||
| 1043 | much smaller. So in that case we always clear the | ||
| 1044 | rectangle with background color. */ | ||
| 1045 | || FONT_TOO_HIGH (s->font) | ||
| 1046 | || s->font_not_found_p | ||
| 1047 | || s->extends_to_end_of_line_p | ||
| 1048 | || force_p) | ||
| 1049 | { | ||
| 1050 | android_clear_glyph_string_rect (s, s->x, s->y + box_line_width, | ||
| 1051 | s->background_width, | ||
| 1052 | s->height - 2 * box_line_width); | ||
| 1053 | s->background_filled_p = true; | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | static void | ||
| 1059 | android_fill_triangle (struct frame *f, struct android_gc *gc, | ||
| 1060 | struct android_point point1, | ||
| 1061 | struct android_point point2, | ||
| 1062 | struct android_point point3) | ||
| 1063 | { | ||
| 1064 | struct android_point abc[3]; | ||
| 1065 | |||
| 1066 | abc[0] = point1; | ||
| 1067 | abc[1] = point2; | ||
| 1068 | abc[2] = point3; | ||
| 1069 | |||
| 1070 | android_fill_polygon (FRAME_ANDROID_WINDOW (f), | ||
| 1071 | gc, abc, 3, ANDROID_CONVEX, | ||
| 1072 | ANDROID_COORD_MODE_ORIGIN); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static struct android_point | ||
| 1076 | android_make_point (int x, int y) | ||
| 1077 | { | ||
| 1078 | struct android_point pt; | ||
| 1079 | |||
| 1080 | pt.x = x; | ||
| 1081 | pt.y = y; | ||
| 1082 | |||
| 1083 | return pt; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | static bool | ||
| 1087 | android_inside_rect_p (struct android_rectangle *rects, int nrects, int x, | ||
| 1088 | int y) | ||
| 1089 | { | ||
| 1090 | int i; | ||
| 1091 | |||
| 1092 | for (i = 0; i < nrects; ++i) | ||
| 1093 | { | ||
| 1094 | if (x >= rects[i].x && y >= rects[i].y | ||
| 1095 | && x < rects[i].x + rects[i].width | ||
| 1096 | && y < rects[i].y + rects[i].height) | ||
| 1097 | return true; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | return false; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static void | ||
| 1104 | android_clear_point (struct frame *f, struct android_gc *gc, | ||
| 1105 | int x, int y) | ||
| 1106 | { | ||
| 1107 | struct android_gc_values xgcv; | ||
| 1108 | |||
| 1109 | android_get_gc_values (gc, ANDROID_GC_BACKGROUND | ANDROID_GC_FOREGROUND, | ||
| 1110 | &xgcv); | ||
| 1111 | android_set_foreground (gc, xgcv.background); | ||
| 1112 | android_draw_point (FRAME_ANDROID_WINDOW (f), gc, x, y); | ||
| 1113 | android_set_foreground (gc, xgcv.foreground); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | static void | ||
| 1117 | android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x, | ||
| 1118 | int bottom_y, int hwidth, int vwidth, bool raised_p, | ||
| 1119 | bool top_p, bool bot_p, bool left_p, bool right_p, | ||
| 1120 | struct android_rectangle *clip_rect) | ||
| 1121 | { | ||
| 1122 | struct android_gc *gc, *white_gc, *black_gc, *normal_gc; | ||
| 1123 | android_drawable drawable; | ||
| 1124 | |||
| 1125 | /* This code is more complicated than it has to be, because of two | ||
| 1126 | minor hacks to make the boxes look nicer: (i) if width > 1, draw | ||
| 1127 | the outermost line using the black relief. (ii) Omit the four | ||
| 1128 | corner pixels. */ | ||
| 1129 | |||
| 1130 | white_gc = f->output_data.android->white_relief.gc; | ||
| 1131 | black_gc = f->output_data.android->black_relief.gc; | ||
| 1132 | normal_gc = f->output_data.android->normal_gc; | ||
| 1133 | |||
| 1134 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 1135 | |||
| 1136 | android_set_clip_rectangles (white_gc, 0, 0, clip_rect, 1); | ||
| 1137 | android_set_clip_rectangles (black_gc, 0, 0, clip_rect, 1); | ||
| 1138 | |||
| 1139 | if (raised_p) | ||
| 1140 | gc = white_gc; | ||
| 1141 | else | ||
| 1142 | gc = black_gc; | ||
| 1143 | |||
| 1144 | /* Draw lines. */ | ||
| 1145 | |||
| 1146 | if (top_p) | ||
| 1147 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1148 | right_x - left_x + 1, hwidth); | ||
| 1149 | |||
| 1150 | if (left_p) | ||
| 1151 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1152 | vwidth, bottom_y - top_y + 1); | ||
| 1153 | |||
| 1154 | if (raised_p) | ||
| 1155 | gc = black_gc; | ||
| 1156 | else | ||
| 1157 | gc = white_gc; | ||
| 1158 | |||
| 1159 | if (bot_p) | ||
| 1160 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, | ||
| 1161 | bottom_y - hwidth + 1, | ||
| 1162 | right_x - left_x + 1, hwidth); | ||
| 1163 | |||
| 1164 | if (right_p) | ||
| 1165 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 1166 | right_x - vwidth + 1, | ||
| 1167 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1168 | |||
| 1169 | /* Draw corners. */ | ||
| 1170 | |||
| 1171 | if (bot_p && left_p) | ||
| 1172 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1173 | android_make_point (left_x, bottom_y - hwidth), | ||
| 1174 | android_make_point (left_x + vwidth, | ||
| 1175 | bottom_y - hwidth), | ||
| 1176 | android_make_point (left_x, bottom_y)); | ||
| 1177 | |||
| 1178 | if (top_p && right_p) | ||
| 1179 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1180 | android_make_point (right_x - vwidth, top_y), | ||
| 1181 | android_make_point (right_x, top_y), | ||
| 1182 | android_make_point (right_x - vwidth, | ||
| 1183 | top_y + hwidth)); | ||
| 1184 | |||
| 1185 | /* Draw outer line. */ | ||
| 1186 | |||
| 1187 | if (top_p && left_p && bot_p && right_p | ||
| 1188 | && hwidth > 1 && vwidth > 1) | ||
| 1189 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 1190 | black_gc, left_x, top_y, | ||
| 1191 | right_x - left_x, bottom_y - top_y); | ||
| 1192 | else | ||
| 1193 | { | ||
| 1194 | if (top_p && hwidth > 1) | ||
| 1195 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1196 | right_x + 1, top_y); | ||
| 1197 | |||
| 1198 | if (bot_p && hwidth > 1) | ||
| 1199 | android_draw_line (drawable, black_gc, left_x, bottom_y, | ||
| 1200 | right_x + 1, bottom_y); | ||
| 1201 | |||
| 1202 | if (left_p && vwidth > 1) | ||
| 1203 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1204 | left_x, bottom_y + 1); | ||
| 1205 | |||
| 1206 | if (right_p && vwidth > 1) | ||
| 1207 | android_draw_line (drawable, black_gc, right_x, top_y, | ||
| 1208 | right_x, bottom_y + 1); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | /* Erase corners. */ | ||
| 1212 | |||
| 1213 | if (hwidth > 1 && vwidth > 1) | ||
| 1214 | { | ||
| 1215 | if (left_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1216 | left_x, top_y)) | ||
| 1217 | android_clear_point (f, normal_gc, left_x, top_y); | ||
| 1218 | |||
| 1219 | if (left_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1220 | left_x, bottom_y)) | ||
| 1221 | android_clear_point (f, normal_gc, left_x, bottom_y); | ||
| 1222 | |||
| 1223 | if (right_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1224 | right_x, top_y)) | ||
| 1225 | android_clear_point (f, normal_gc, right_x, top_y); | ||
| 1226 | |||
| 1227 | if (right_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1228 | right_x, bottom_y)) | ||
| 1229 | android_clear_point (f, normal_gc, right_x, bottom_y); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | android_reset_clip_rectangles (f, white_gc); | ||
| 1233 | android_reset_clip_rectangles (f, black_gc); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static void | ||
| 1237 | android_draw_box_rect (struct glyph_string *s, | ||
| 1238 | int left_x, int top_y, int right_x, int bottom_y, | ||
| 1239 | int hwidth, int vwidth, bool left_p, bool right_p, | ||
| 1240 | struct android_rectangle *clip_rect) | ||
| 1241 | { | ||
| 1242 | struct android_gc_values xgcv; | ||
| 1243 | |||
| 1244 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 1245 | android_set_foreground (s->gc, s->face->box_color); | ||
| 1246 | android_set_clip_rectangles (s->gc, 0, 0, clip_rect, 1); | ||
| 1247 | |||
| 1248 | /* Top. */ | ||
| 1249 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1250 | left_x, right_x - left_x + 1, hwidth); | ||
| 1251 | |||
| 1252 | /* Left. */ | ||
| 1253 | if (left_p) | ||
| 1254 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1255 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1256 | |||
| 1257 | /* Bottom. */ | ||
| 1258 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1259 | bottom_y - hwidth + 1, right_x - left_x + 1, | ||
| 1260 | hwidth); | ||
| 1261 | |||
| 1262 | /* Right. */ | ||
| 1263 | if (right_p) | ||
| 1264 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1265 | right_x - vwidth + 1, top_y, vwidth, | ||
| 1266 | bottom_y - top_y + 1); | ||
| 1267 | |||
| 1268 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 1269 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000 | ||
| 1273 | |||
| 1274 | static bool | ||
| 1275 | android_alloc_lighter_color (struct frame *f, unsigned long *pixel, | ||
| 1276 | double factor, int delta) | ||
| 1277 | { | ||
| 1278 | Emacs_Color color, new; | ||
| 1279 | long bright; | ||
| 1280 | bool success_p; | ||
| 1281 | |||
| 1282 | /* Get RGB color values. */ | ||
| 1283 | color.pixel = *pixel; | ||
| 1284 | android_query_colors (f, &color, 1); | ||
| 1285 | |||
| 1286 | /* Change RGB values by specified FACTOR. Avoid overflow! */ | ||
| 1287 | eassert (factor >= 0); | ||
| 1288 | new.red = min (0xffff, factor * color.red); | ||
| 1289 | new.green = min (0xffff, factor * color.green); | ||
| 1290 | new.blue = min (0xffff, factor * color.blue); | ||
| 1291 | |||
| 1292 | /* Calculate brightness of COLOR. */ | ||
| 1293 | bright = (2 * color.red + 3 * color.green + color.blue) / 6; | ||
| 1294 | |||
| 1295 | /* We only boost colors that are darker than | ||
| 1296 | HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */ | ||
| 1297 | if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT) | ||
| 1298 | /* Make an additive adjustment to NEW, because it's dark enough so | ||
| 1299 | that scaling by FACTOR alone isn't enough. */ | ||
| 1300 | { | ||
| 1301 | /* How far below the limit this color is (0 - 1, 1 being darker). */ | ||
| 1302 | double dimness = 1 - (double) bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT; | ||
| 1303 | /* The additive adjustment. */ | ||
| 1304 | int min_delta = delta * dimness * factor / 2; | ||
| 1305 | |||
| 1306 | if (factor < 1) | ||
| 1307 | { | ||
| 1308 | new.red = max (0, new.red - min_delta); | ||
| 1309 | new.green = max (0, new.green - min_delta); | ||
| 1310 | new.blue = max (0, new.blue - min_delta); | ||
| 1311 | } | ||
| 1312 | else | ||
| 1313 | { | ||
| 1314 | new.red = min (0xffff, min_delta + new.red); | ||
| 1315 | new.green = min (0xffff, min_delta + new.green); | ||
| 1316 | new.blue = min (0xffff, min_delta + new.blue); | ||
| 1317 | } | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | /* Try to allocate the color. */ | ||
| 1321 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1322 | |||
| 1323 | if (success_p) | ||
| 1324 | { | ||
| 1325 | if (new.pixel == *pixel) | ||
| 1326 | { | ||
| 1327 | /* If we end up with the same color as before, try adding | ||
| 1328 | delta to the RGB values. */ | ||
| 1329 | new.red = min (0xffff, delta + color.red); | ||
| 1330 | new.green = min (0xffff, delta + color.green); | ||
| 1331 | new.blue = min (0xffff, delta + color.blue); | ||
| 1332 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1333 | } | ||
| 1334 | else | ||
| 1335 | success_p = true; | ||
| 1336 | |||
| 1337 | *pixel = new.pixel; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | return success_p; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | /* Set up the foreground color for drawing relief lines of glyph | ||
| 1344 | string S. RELIEF is a pointer to a struct relief containing the GC | ||
| 1345 | with which lines will be drawn. Use a color that is FACTOR or | ||
| 1346 | DELTA lighter or darker than the relief's background which is found | ||
| 1347 | in S->f->output_data.android->relief_background. If such a color | ||
| 1348 | cannot be allocated, use DEFAULT_PIXEL, instead. */ | ||
| 1349 | |||
| 1350 | static void | ||
| 1351 | android_setup_relief_color (struct frame *f, struct relief *relief, | ||
| 1352 | double factor, int delta, | ||
| 1353 | unsigned long default_pixel) | ||
| 1354 | { | ||
| 1355 | struct android_gc_values xgcv; | ||
| 1356 | struct android_output *di = f->output_data.android; | ||
| 1357 | unsigned long mask = ANDROID_GC_FOREGROUND; | ||
| 1358 | unsigned long pixel; | ||
| 1359 | unsigned long background = di->relief_background; | ||
| 1360 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 1361 | |||
| 1362 | if (relief->gc && relief->pixel != -1) | ||
| 1363 | relief->pixel = -1; | ||
| 1364 | |||
| 1365 | /* Allocate new color. */ | ||
| 1366 | xgcv.foreground = default_pixel; | ||
| 1367 | pixel = background; | ||
| 1368 | |||
| 1369 | if (dpyinfo->n_planes != 1 | ||
| 1370 | && android_alloc_lighter_color (f, &pixel, factor, delta)) | ||
| 1371 | xgcv.foreground = relief->pixel = pixel; | ||
| 1372 | |||
| 1373 | if (relief->gc == 0) | ||
| 1374 | relief->gc = android_create_gc (mask, &xgcv); | ||
| 1375 | else | ||
| 1376 | android_change_gc (relief->gc, mask, &xgcv); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | /* Set up colors for the relief lines around glyph string S. */ | ||
| 1380 | |||
| 1381 | static void | ||
| 1382 | android_setup_relief_colors (struct glyph_string *s) | ||
| 1383 | { | ||
| 1384 | struct android_output *di; | ||
| 1385 | unsigned long color; | ||
| 1386 | |||
| 1387 | di = s->f->output_data.android; | ||
| 1388 | |||
| 1389 | if (s->face->use_box_color_for_shadows_p) | ||
| 1390 | color = s->face->box_color; | ||
| 1391 | else if (s->first_glyph->type == IMAGE_GLYPH | ||
| 1392 | && s->img->pixmap | ||
| 1393 | && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) | ||
| 1394 | color = IMAGE_BACKGROUND (s->img, s->f, 0); | ||
| 1395 | else | ||
| 1396 | { | ||
| 1397 | struct android_gc_values xgcv; | ||
| 1398 | |||
| 1399 | /* Get the background color of the face. */ | ||
| 1400 | android_get_gc_values (s->gc, ANDROID_GC_BACKGROUND, &xgcv); | ||
| 1401 | color = xgcv.background; | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | if (di->white_relief.gc == 0 | ||
| 1405 | || color != di->relief_background) | ||
| 1406 | { | ||
| 1407 | di->relief_background = color; | ||
| 1408 | android_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000, | ||
| 1409 | WHITE_PIX_DEFAULT (s->f)); | ||
| 1410 | android_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000, | ||
| 1411 | BLACK_PIX_DEFAULT (s->f)); | ||
| 1412 | } | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | static void | ||
| 1416 | android_draw_glyph_string_box (struct glyph_string *s) | ||
| 1417 | { | ||
| 1418 | int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x; | ||
| 1419 | bool raised_p, left_p, right_p; | ||
| 1420 | struct glyph *last_glyph; | ||
| 1421 | struct android_rectangle clip_rect; | ||
| 1422 | |||
| 1423 | last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) | ||
| 1424 | ? WINDOW_RIGHT_EDGE_X (s->w) | ||
| 1425 | : window_box_right (s->w, s->area)); | ||
| 1426 | |||
| 1427 | /* The glyph that may have a right box line. For static | ||
| 1428 | compositions and images, the right-box flag is on the first glyph | ||
| 1429 | of the glyph string; for other types it's on the last glyph. */ | ||
| 1430 | if (s->cmp || s->img) | ||
| 1431 | last_glyph = s->first_glyph; | ||
| 1432 | else if (s->first_glyph->type == COMPOSITE_GLYPH | ||
| 1433 | && s->first_glyph->u.cmp.automatic) | ||
| 1434 | { | ||
| 1435 | /* For automatic compositions, we need to look up the last glyph | ||
| 1436 | in the composition. */ | ||
| 1437 | struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area]; | ||
| 1438 | struct glyph *g = s->first_glyph; | ||
| 1439 | for (last_glyph = g++; | ||
| 1440 | g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id | ||
| 1441 | && g->slice.cmp.to < s->cmp_to; | ||
| 1442 | last_glyph = g++) | ||
| 1443 | ; | ||
| 1444 | } | ||
| 1445 | else | ||
| 1446 | last_glyph = s->first_glyph + s->nchars - 1; | ||
| 1447 | |||
| 1448 | vwidth = eabs (s->face->box_vertical_line_width); | ||
| 1449 | hwidth = eabs (s->face->box_horizontal_line_width); | ||
| 1450 | raised_p = s->face->box == FACE_RAISED_BOX; | ||
| 1451 | left_x = s->x; | ||
| 1452 | right_x = (s->row->full_width_p && s->extends_to_end_of_line_p | ||
| 1453 | ? last_x - 1 | ||
| 1454 | : min (last_x, s->x + s->background_width) - 1); | ||
| 1455 | top_y = s->y; | ||
| 1456 | bottom_y = top_y + s->height - 1; | ||
| 1457 | |||
| 1458 | left_p = (s->first_glyph->left_box_line_p | ||
| 1459 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1460 | && (s->prev == NULL | ||
| 1461 | || s->prev->hl != s->hl))); | ||
| 1462 | right_p = (last_glyph->right_box_line_p | ||
| 1463 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1464 | && (s->next == NULL | ||
| 1465 | || s->next->hl != s->hl))); | ||
| 1466 | |||
| 1467 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1468 | |||
| 1469 | if (s->face->box == FACE_SIMPLE_BOX) | ||
| 1470 | android_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1471 | vwidth, left_p, right_p, &clip_rect); | ||
| 1472 | else | ||
| 1473 | { | ||
| 1474 | android_setup_relief_colors (s); | ||
| 1475 | android_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1476 | vwidth, raised_p, true, true, left_p, right_p, | ||
| 1477 | &clip_rect); | ||
| 1478 | } | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | static void | ||
| 1482 | android_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, | ||
| 1483 | int w, int h) | ||
| 1484 | { | ||
| 1485 | if (s->stippled_p) | ||
| 1486 | { | ||
| 1487 | /* Fill background with a stipple pattern. */ | ||
| 1488 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1489 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, | ||
| 1490 | y, w, h); | ||
| 1491 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1492 | } | ||
| 1493 | else | ||
| 1494 | android_clear_glyph_string_rect (s, x, y, w, h); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static void | ||
| 1498 | android_draw_image_relief (struct glyph_string *s) | ||
| 1499 | { | ||
| 1500 | int x1, y1, thick; | ||
| 1501 | bool raised_p, top_p, bot_p, left_p, right_p; | ||
| 1502 | int extra_x, extra_y; | ||
| 1503 | struct android_rectangle r; | ||
| 1504 | int x = s->x; | ||
| 1505 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1506 | |||
| 1507 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1508 | right of that line. */ | ||
| 1509 | if (s->face->box != FACE_NO_BOX | ||
| 1510 | && s->first_glyph->left_box_line_p | ||
| 1511 | && s->slice.x == 0) | ||
| 1512 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1513 | |||
| 1514 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1515 | by that margin. */ | ||
| 1516 | if (s->slice.x == 0) | ||
| 1517 | x += s->img->hmargin; | ||
| 1518 | if (s->slice.y == 0) | ||
| 1519 | y += s->img->vmargin; | ||
| 1520 | |||
| 1521 | if (s->hl == DRAW_IMAGE_SUNKEN | ||
| 1522 | || s->hl == DRAW_IMAGE_RAISED) | ||
| 1523 | { | ||
| 1524 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1525 | thick = (tab_bar_button_relief < 0 | ||
| 1526 | ? DEFAULT_TAB_BAR_BUTTON_RELIEF | ||
| 1527 | : min (tab_bar_button_relief, 1000000)); | ||
| 1528 | else | ||
| 1529 | thick = (tool_bar_button_relief < 0 | ||
| 1530 | ? DEFAULT_TOOL_BAR_BUTTON_RELIEF | ||
| 1531 | : min (tool_bar_button_relief, 1000000)); | ||
| 1532 | raised_p = s->hl == DRAW_IMAGE_RAISED; | ||
| 1533 | } | ||
| 1534 | else | ||
| 1535 | { | ||
| 1536 | thick = eabs (s->img->relief); | ||
| 1537 | raised_p = s->img->relief > 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | x1 = x + s->slice.width - 1; | ||
| 1541 | y1 = y + s->slice.height - 1; | ||
| 1542 | |||
| 1543 | extra_x = extra_y = 0; | ||
| 1544 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1545 | { | ||
| 1546 | if (CONSP (Vtab_bar_button_margin) | ||
| 1547 | && FIXNUMP (XCAR (Vtab_bar_button_margin)) | ||
| 1548 | && FIXNUMP (XCDR (Vtab_bar_button_margin))) | ||
| 1549 | { | ||
| 1550 | extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick; | ||
| 1551 | extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick; | ||
| 1552 | } | ||
| 1553 | else if (FIXNUMP (Vtab_bar_button_margin)) | ||
| 1554 | extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | if (s->face->id == TOOL_BAR_FACE_ID) | ||
| 1558 | { | ||
| 1559 | if (CONSP (Vtool_bar_button_margin) | ||
| 1560 | && FIXNUMP (XCAR (Vtool_bar_button_margin)) | ||
| 1561 | && FIXNUMP (XCDR (Vtool_bar_button_margin))) | ||
| 1562 | { | ||
| 1563 | extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin)); | ||
| 1564 | extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin)); | ||
| 1565 | } | ||
| 1566 | else if (FIXNUMP (Vtool_bar_button_margin)) | ||
| 1567 | extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin); | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | top_p = bot_p = left_p = right_p = false; | ||
| 1571 | |||
| 1572 | if (s->slice.x == 0) | ||
| 1573 | x -= thick + extra_x, left_p = true; | ||
| 1574 | if (s->slice.y == 0) | ||
| 1575 | y -= thick + extra_y, top_p = true; | ||
| 1576 | if (s->slice.x + s->slice.width == s->img->width) | ||
| 1577 | x1 += thick + extra_x, right_p = true; | ||
| 1578 | if (s->slice.y + s->slice.height == s->img->height) | ||
| 1579 | y1 += thick + extra_y, bot_p = true; | ||
| 1580 | |||
| 1581 | android_setup_relief_colors (s); | ||
| 1582 | get_glyph_string_clip_rect (s, &r); | ||
| 1583 | android_draw_relief_rect (s->f, x, y, x1, y1, thick, thick, raised_p, | ||
| 1584 | top_p, bot_p, left_p, right_p, &r); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | static void | ||
| 1588 | android_draw_image_foreground (struct glyph_string *s) | ||
| 1589 | { | ||
| 1590 | int x = s->x; | ||
| 1591 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1592 | |||
| 1593 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1594 | right of that line. */ | ||
| 1595 | if (s->face->box != FACE_NO_BOX | ||
| 1596 | && s->first_glyph->left_box_line_p | ||
| 1597 | && s->slice.x == 0) | ||
| 1598 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1599 | |||
| 1600 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1601 | by that margin. */ | ||
| 1602 | if (s->slice.x == 0) | ||
| 1603 | x += s->img->hmargin; | ||
| 1604 | if (s->slice.y == 0) | ||
| 1605 | y += s->img->vmargin; | ||
| 1606 | |||
| 1607 | if (s->img->pixmap) | ||
| 1608 | { | ||
| 1609 | if (s->img->mask) | ||
| 1610 | { | ||
| 1611 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1612 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1613 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1614 | | ANDROID_GC_FUNCTION); | ||
| 1615 | struct android_gc_values xgcv; | ||
| 1616 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1617 | |||
| 1618 | xgcv.clip_mask = s->img->mask; | ||
| 1619 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1620 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1621 | xgcv.function = ANDROID_GC_COPY; | ||
| 1622 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1623 | |||
| 1624 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1625 | image_rect.x = x; | ||
| 1626 | image_rect.y = y; | ||
| 1627 | image_rect.width = s->slice.width; | ||
| 1628 | image_rect.height = s->slice.height; | ||
| 1629 | |||
| 1630 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1631 | android_copy_area (s->img->pixmap, FRAME_ANDROID_WINDOW (s->f), | ||
| 1632 | s->gc, s->slice.x + r.x - x, | ||
| 1633 | s->slice.y + r.y - y, | ||
| 1634 | r.x, r.y, r.width, r.height); | ||
| 1635 | } | ||
| 1636 | else | ||
| 1637 | { | ||
| 1638 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1639 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1640 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1641 | | ANDROID_GC_FUNCTION); | ||
| 1642 | struct android_gc_values xgcv; | ||
| 1643 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1644 | |||
| 1645 | xgcv.clip_mask = s->img->mask; | ||
| 1646 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1647 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1648 | xgcv.function = ANDROID_GC_COPY; | ||
| 1649 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1650 | |||
| 1651 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1652 | image_rect.x = x; | ||
| 1653 | image_rect.y = y; | ||
| 1654 | image_rect.width = s->slice.width; | ||
| 1655 | image_rect.height = s->slice.height; | ||
| 1656 | |||
| 1657 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1658 | android_copy_area (s->img->pixmap, | ||
| 1659 | FRAME_ANDROID_WINDOW (s->f), | ||
| 1660 | s->gc, s->slice.x + r.x - x, | ||
| 1661 | s->slice.y + r.y - y, | ||
| 1662 | r.x, r.y, r.width, r.height); | ||
| 1663 | |||
| 1664 | /* When the image has a mask, we can expect that at | ||
| 1665 | least part of a mouse highlight or a block cursor will | ||
| 1666 | be visible. If the image doesn't have a mask, make | ||
| 1667 | a block cursor visible by drawing a rectangle around | ||
| 1668 | the image. I believe it's looking better if we do | ||
| 1669 | nothing here for mouse-face. */ | ||
| 1670 | if (s->hl == DRAW_CURSOR) | ||
| 1671 | { | ||
| 1672 | int relief = eabs (s->img->relief); | ||
| 1673 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1674 | x - relief, y - relief, | ||
| 1675 | s->slice.width + relief*2 - 1, | ||
| 1676 | s->slice.height + relief*2 - 1); | ||
| 1677 | } | ||
| 1678 | } | ||
| 1679 | } | ||
| 1680 | else | ||
| 1681 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1682 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1683 | s->slice.width - 1, s->slice.height - 1); | ||
| 1684 | } | ||
| 1685 | |||
| 1686 | /* Draw the foreground of image glyph string S to PIXMAP. */ | ||
| 1687 | |||
| 1688 | static void | ||
| 1689 | android_draw_image_foreground_1 (struct glyph_string *s, | ||
| 1690 | android_pixmap pixmap) | ||
| 1691 | { | ||
| 1692 | int x = 0; | ||
| 1693 | int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice); | ||
| 1694 | |||
| 1695 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1696 | right of that line. */ | ||
| 1697 | if (s->face->box != FACE_NO_BOX | ||
| 1698 | && s->first_glyph->left_box_line_p | ||
| 1699 | && s->slice.x == 0) | ||
| 1700 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1701 | |||
| 1702 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1703 | by that margin. */ | ||
| 1704 | if (s->slice.x == 0) | ||
| 1705 | x += s->img->hmargin; | ||
| 1706 | if (s->slice.y == 0) | ||
| 1707 | y += s->img->vmargin; | ||
| 1708 | |||
| 1709 | if (s->img->pixmap) | ||
| 1710 | { | ||
| 1711 | if (s->img->mask) | ||
| 1712 | { | ||
| 1713 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1714 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1715 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1716 | | ANDROID_GC_FUNCTION); | ||
| 1717 | struct android_gc_values xgcv; | ||
| 1718 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1719 | |||
| 1720 | xgcv.clip_mask = s->img->mask; | ||
| 1721 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1722 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1723 | xgcv.function = ANDROID_GC_COPY; | ||
| 1724 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1725 | |||
| 1726 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1727 | image_rect.x = x; | ||
| 1728 | image_rect.y = y; | ||
| 1729 | image_rect.width = s->slice.width; | ||
| 1730 | image_rect.height = s->slice.height; | ||
| 1731 | |||
| 1732 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1733 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1734 | s->slice.x + r.x - x, | ||
| 1735 | s->slice.y + r.y - y, | ||
| 1736 | r.x, r.y, r.width, r.height); | ||
| 1737 | |||
| 1738 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1739 | } | ||
| 1740 | else | ||
| 1741 | { | ||
| 1742 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1743 | s->slice.x, s->slice.y, | ||
| 1744 | s->slice.width, s->slice.height, x, y); | ||
| 1745 | |||
| 1746 | /* When the image has a mask, we can expect that at | ||
| 1747 | least part of a mouse highlight or a block cursor will | ||
| 1748 | be visible. If the image doesn't have a mask, make | ||
| 1749 | a block cursor visible by drawing a rectangle around | ||
| 1750 | the image. I believe it's looking better if we do | ||
| 1751 | nothing here for mouse-face. */ | ||
| 1752 | if (s->hl == DRAW_CURSOR) | ||
| 1753 | { | ||
| 1754 | int r = eabs (s->img->relief); | ||
| 1755 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1756 | s->gc, x - r, y - r, | ||
| 1757 | s->slice.width + r*2 - 1, | ||
| 1758 | s->slice.height + r*2 - 1); | ||
| 1759 | } | ||
| 1760 | } | ||
| 1761 | } | ||
| 1762 | else | ||
| 1763 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1764 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1765 | s->slice.width - 1, s->slice.height - 1); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | static void | ||
| 1769 | android_draw_image_glyph_string (struct glyph_string *s) | ||
| 1770 | { | ||
| 1771 | int box_line_hwidth = max (s->face->box_vertical_line_width, 0); | ||
| 1772 | int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); | ||
| 1773 | int height; | ||
| 1774 | android_pixmap pixmap = ANDROID_NONE; | ||
| 1775 | |||
| 1776 | height = s->height; | ||
| 1777 | if (s->slice.y == 0) | ||
| 1778 | height -= box_line_vwidth; | ||
| 1779 | if (s->slice.y + s->slice.height >= s->img->height) | ||
| 1780 | height -= box_line_vwidth; | ||
| 1781 | |||
| 1782 | /* Fill background with face under the image. Do it only if row is | ||
| 1783 | taller than image or if image has a clip mask to reduce | ||
| 1784 | flickering. */ | ||
| 1785 | s->stippled_p = s->face->stipple != 0; | ||
| 1786 | if (height > s->slice.height | ||
| 1787 | || s->img->hmargin | ||
| 1788 | || s->img->vmargin | ||
| 1789 | || s->img->mask | ||
| 1790 | || s->img->pixmap == 0 | ||
| 1791 | || s->width != s->background_width) | ||
| 1792 | { | ||
| 1793 | if (s->stippled_p) | ||
| 1794 | s->row->stipple_p = true; | ||
| 1795 | |||
| 1796 | if (s->img->mask) | ||
| 1797 | { | ||
| 1798 | /* Create a pixmap as large as the glyph string. Fill it | ||
| 1799 | with the background color. Copy the image to it, using | ||
| 1800 | its mask. Copy the temporary pixmap to the display. */ | ||
| 1801 | int depth = FRAME_DISPLAY_INFO (s->f)->n_planes; | ||
| 1802 | |||
| 1803 | /* Create a pixmap as large as the glyph string. */ | ||
| 1804 | pixmap = android_create_pixmap (s->background_width, | ||
| 1805 | s->height, depth); | ||
| 1806 | |||
| 1807 | /* Don't clip in the following because we're working on the | ||
| 1808 | pixmap. */ | ||
| 1809 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1810 | |||
| 1811 | /* Fill the pixmap with the background color/stipple. */ | ||
| 1812 | if (s->stippled_p) | ||
| 1813 | { | ||
| 1814 | /* Fill background with a stipple pattern. */ | ||
| 1815 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1816 | android_set_ts_origin (s->gc, - s->x, - s->y); | ||
| 1817 | android_fill_rectangle (pixmap, s->gc, | ||
| 1818 | 0, 0, s->background_width, s->height); | ||
| 1819 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1820 | android_set_ts_origin (s->gc, 0, 0); | ||
| 1821 | } | ||
| 1822 | else | ||
| 1823 | { | ||
| 1824 | struct android_gc_values xgcv; | ||
| 1825 | |||
| 1826 | android_get_gc_values (s->gc, (ANDROID_GC_FOREGROUND | ||
| 1827 | | ANDROID_GC_BACKGROUND), | ||
| 1828 | &xgcv); | ||
| 1829 | android_set_foreground (s->gc, xgcv.background); | ||
| 1830 | android_fill_rectangle (pixmap, s->gc, | ||
| 1831 | 0, 0, s->background_width, s->height); | ||
| 1832 | android_set_background (s->gc, xgcv.foreground); | ||
| 1833 | } | ||
| 1834 | } | ||
| 1835 | else | ||
| 1836 | { | ||
| 1837 | int x = s->x; | ||
| 1838 | int y = s->y; | ||
| 1839 | int width = s->background_width; | ||
| 1840 | |||
| 1841 | if (s->first_glyph->left_box_line_p | ||
| 1842 | && s->slice.x == 0) | ||
| 1843 | { | ||
| 1844 | x += box_line_hwidth; | ||
| 1845 | width -= box_line_hwidth; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | if (s->slice.y == 0) | ||
| 1849 | y += box_line_vwidth; | ||
| 1850 | |||
| 1851 | android_draw_glyph_string_bg_rect (s, x, y, width, height); | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | s->background_filled_p = true; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | /* Draw the foreground. */ | ||
| 1858 | if (pixmap != ANDROID_NONE) | ||
| 1859 | { | ||
| 1860 | android_draw_image_foreground_1 (s, pixmap); | ||
| 1861 | android_set_glyph_string_clipping (s); | ||
| 1862 | android_copy_area (pixmap, FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1863 | 0, 0, s->background_width, s->height, s->x, | ||
| 1864 | s->y); | ||
| 1865 | android_free_pixmap (pixmap); | ||
| 1866 | } | ||
| 1867 | else | ||
| 1868 | android_draw_image_foreground (s); | ||
| 1869 | |||
| 1870 | /* If we must draw a relief around the image, do it. */ | ||
| 1871 | if (s->img->relief | ||
| 1872 | || s->hl == DRAW_IMAGE_RAISED | ||
| 1873 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 1874 | android_draw_image_relief (s); | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | static void | ||
| 1878 | android_draw_stretch_glyph_string (struct glyph_string *s) | ||
| 1879 | { | ||
| 1880 | eassert (s->first_glyph->type == STRETCH_GLYPH); | ||
| 1881 | |||
| 1882 | if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p) | ||
| 1883 | { | ||
| 1884 | /* If `x-stretch-cursor' is nil, don't draw a block cursor as | ||
| 1885 | wide as the stretch glyph. */ | ||
| 1886 | int width, background_width = s->background_width; | ||
| 1887 | int x = s->x; | ||
| 1888 | |||
| 1889 | if (!s->row->reversed_p) | ||
| 1890 | { | ||
| 1891 | int left_x = window_box_left_offset (s->w, TEXT_AREA); | ||
| 1892 | |||
| 1893 | if (x < left_x) | ||
| 1894 | { | ||
| 1895 | background_width -= left_x - x; | ||
| 1896 | x = left_x; | ||
| 1897 | } | ||
| 1898 | } | ||
| 1899 | else | ||
| 1900 | { | ||
| 1901 | /* In R2L rows, draw the cursor on the right edge of the | ||
| 1902 | stretch glyph. */ | ||
| 1903 | int right_x = window_box_right (s->w, TEXT_AREA); | ||
| 1904 | |||
| 1905 | if (x + background_width > right_x) | ||
| 1906 | background_width -= x - right_x; | ||
| 1907 | x += background_width; | ||
| 1908 | } | ||
| 1909 | width = min (FRAME_COLUMN_WIDTH (s->f), background_width); | ||
| 1910 | if (s->row->reversed_p) | ||
| 1911 | x -= width; | ||
| 1912 | |||
| 1913 | /* Draw cursor. */ | ||
| 1914 | android_draw_glyph_string_bg_rect (s, x, s->y, width, s->height); | ||
| 1915 | |||
| 1916 | /* Clear rest using the GC of the original non-cursor face. */ | ||
| 1917 | if (width < background_width) | ||
| 1918 | { | ||
| 1919 | int y = s->y; | ||
| 1920 | int w = background_width - width, h = s->height; | ||
| 1921 | struct android_rectangle r; | ||
| 1922 | struct android_gc *gc; | ||
| 1923 | |||
| 1924 | if (!s->row->reversed_p) | ||
| 1925 | x += width; | ||
| 1926 | else | ||
| 1927 | x = s->x; | ||
| 1928 | if (s->row->mouse_face_p | ||
| 1929 | && cursor_in_mouse_face_p (s->w)) | ||
| 1930 | { | ||
| 1931 | android_set_mouse_face_gc (s); | ||
| 1932 | gc = s->gc; | ||
| 1933 | } | ||
| 1934 | else | ||
| 1935 | gc = s->face->gc; | ||
| 1936 | |||
| 1937 | get_glyph_string_clip_rect (s, &r); | ||
| 1938 | android_set_clip_rectangles (gc, 0, 0, &r, 1); | ||
| 1939 | |||
| 1940 | if (s->face->stipple) | ||
| 1941 | { | ||
| 1942 | /* Fill background with a stipple pattern. */ | ||
| 1943 | android_set_fill_style (gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1945 | gc, x, y, w, h); | ||
| 1946 | android_set_fill_style (gc, ANDROID_FILL_SOLID); | ||
| 1947 | |||
| 1948 | s->row->stipple_p = true; | ||
| 1949 | } | ||
| 1950 | else | ||
| 1951 | { | ||
| 1952 | struct android_gc_values xgcv; | ||
| 1953 | android_get_gc_values (gc, (ANDROID_GC_FOREGROUND | ||
| 1954 | | ANDROID_GC_BACKGROUND), | ||
| 1955 | &xgcv); | ||
| 1956 | android_set_foreground (gc, xgcv.background); | ||
| 1957 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1958 | gc, x, y, w, h); | ||
| 1959 | android_set_foreground (gc, xgcv.foreground); | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | android_reset_clip_rectangles (s->f, gc); | ||
| 1963 | } | ||
| 1964 | } | ||
| 1965 | else if (!s->background_filled_p) | ||
| 1966 | { | ||
| 1967 | int background_width = s->background_width; | ||
| 1968 | int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA); | ||
| 1969 | |||
| 1970 | /* Don't draw into left fringe or scrollbar area except for | ||
| 1971 | header line and mode line. */ | ||
| 1972 | if (s->area == TEXT_AREA | ||
| 1973 | && x < text_left_x && !s->row->mode_line_p) | ||
| 1974 | { | ||
| 1975 | background_width -= text_left_x - x; | ||
| 1976 | x = text_left_x; | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | if (!s->row->stipple_p) | ||
| 1980 | s->row->stipple_p = s->stippled_p; | ||
| 1981 | |||
| 1982 | if (background_width > 0) | ||
| 1983 | android_draw_glyph_string_bg_rect (s, x, s->y, | ||
| 1984 | background_width, | ||
| 1985 | s->height); | ||
| 1986 | } | ||
| 1987 | |||
| 1988 | s->background_filled_p = true; | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | static void | ||
| 1992 | android_draw_underwave (struct glyph_string *s, int decoration_width) | ||
| 1993 | { | ||
| 1994 | int wave_height = 3, wave_length = 2; | ||
| 1995 | int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax; | ||
| 1996 | bool odd; | ||
| 1997 | struct android_rectangle wave_clip, string_clip, final_clip; | ||
| 1998 | |||
| 1999 | dx = wave_length; | ||
| 2000 | dy = wave_height - 1; | ||
| 2001 | x0 = s->x; | ||
| 2002 | y0 = s->ybase + wave_height / 2; | ||
| 2003 | width = decoration_width; | ||
| 2004 | xmax = x0 + width; | ||
| 2005 | |||
| 2006 | /* Find and set clipping rectangle */ | ||
| 2007 | |||
| 2008 | wave_clip.x = x0; | ||
| 2009 | wave_clip.y = y0; | ||
| 2010 | wave_clip.width = width; | ||
| 2011 | wave_clip.height = wave_height; | ||
| 2012 | get_glyph_string_clip_rect (s, &string_clip); | ||
| 2013 | |||
| 2014 | if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) | ||
| 2015 | return; | ||
| 2016 | |||
| 2017 | android_set_clip_rectangles (s->gc, 0, 0, &final_clip, 1); | ||
| 2018 | |||
| 2019 | /* Draw the waves */ | ||
| 2020 | |||
| 2021 | x1 = x0 - (x0 % dx); | ||
| 2022 | x2 = x1 + dx; | ||
| 2023 | odd = (x1 / dx) & 1; | ||
| 2024 | y1 = y2 = y0; | ||
| 2025 | |||
| 2026 | if (odd) | ||
| 2027 | y1 += dy; | ||
| 2028 | else | ||
| 2029 | y2 += dy; | ||
| 2030 | |||
| 2031 | if (INT_MAX - dx < xmax) | ||
| 2032 | emacs_abort (); | ||
| 2033 | |||
| 2034 | while (x1 <= xmax) | ||
| 2035 | { | ||
| 2036 | android_draw_line (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2037 | x1, y1, x2, y2); | ||
| 2038 | x1 = x2, y1 = y2; | ||
| 2039 | x2 += dx, y2 = y0 + odd*dy; | ||
| 2040 | odd = !odd; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | /* Restore previous clipping rectangle(s) */ | ||
| 2044 | android_set_clip_rectangles (s->gc, 0, 0, s->clip, s->num_clips); | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | static void | ||
| 2048 | android_draw_glyph_string_foreground (struct glyph_string *s) | ||
| 2049 | { | ||
| 2050 | int i, x; | ||
| 2051 | |||
| 2052 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2053 | of S to the right of that box line. */ | ||
| 2054 | if (s->face->box != FACE_NO_BOX | ||
| 2055 | && s->first_glyph->left_box_line_p) | ||
| 2056 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2057 | else | ||
| 2058 | x = s->x; | ||
| 2059 | |||
| 2060 | /* Draw characters of S as rectangles if S's font could not be | ||
| 2061 | loaded. */ | ||
| 2062 | if (s->font_not_found_p) | ||
| 2063 | { | ||
| 2064 | for (i = 0; i < s->nchars; ++i) | ||
| 2065 | { | ||
| 2066 | struct glyph *g = s->first_glyph + i; | ||
| 2067 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2068 | s->gc, x, s->y, | ||
| 2069 | g->pixel_width - 1, | ||
| 2070 | s->height - 1); | ||
| 2071 | x += g->pixel_width; | ||
| 2072 | } | ||
| 2073 | } | ||
| 2074 | else | ||
| 2075 | { | ||
| 2076 | struct font *font = s->font; | ||
| 2077 | int boff = font->baseline_offset; | ||
| 2078 | int y; | ||
| 2079 | |||
| 2080 | if (font->vertical_centering) | ||
| 2081 | boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff; | ||
| 2082 | |||
| 2083 | y = s->ybase - boff; | ||
| 2084 | if (s->for_overlaps | ||
| 2085 | || (s->background_filled_p && s->hl != DRAW_CURSOR)) | ||
| 2086 | font->driver->draw (s, 0, s->nchars, x, y, false); | ||
| 2087 | else | ||
| 2088 | font->driver->draw (s, 0, s->nchars, x, y, true); | ||
| 2089 | if (s->face->overstrike) | ||
| 2090 | font->driver->draw (s, 0, s->nchars, x + 1, y, false); | ||
| 2091 | } | ||
| 2092 | } | ||
| 2093 | |||
| 2094 | static void | ||
| 2095 | android_draw_composite_glyph_string_foreground (struct glyph_string *s) | ||
| 2096 | { | ||
| 2097 | int i, j, x; | ||
| 2098 | struct font *font = s->font; | ||
| 2099 | |||
| 2100 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2101 | of S to the right of that box line. */ | ||
| 2102 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2103 | && s->first_glyph->left_box_line_p) | ||
| 2104 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2105 | else | ||
| 2106 | x = s->x; | ||
| 2107 | |||
| 2108 | /* S is a glyph string for a composition. S->cmp_from is the index | ||
| 2109 | of the first character drawn for glyphs of this composition. | ||
| 2110 | S->cmp_from == 0 means we are drawing the very first character of | ||
| 2111 | this composition. */ | ||
| 2112 | |||
| 2113 | /* Draw a rectangle for the composition if the font for the very | ||
| 2114 | first character of the composition could not be loaded. */ | ||
| 2115 | if (s->font_not_found_p) | ||
| 2116 | { | ||
| 2117 | if (s->cmp_from == 0) | ||
| 2118 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2119 | s->gc, x, s->y, | ||
| 2120 | s->width - 1, s->height - 1); | ||
| 2121 | } | ||
| 2122 | else if (! s->first_glyph->u.cmp.automatic) | ||
| 2123 | { | ||
| 2124 | int y = s->ybase; | ||
| 2125 | |||
| 2126 | for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++) | ||
| 2127 | /* TAB in a composition means display glyphs with | ||
| 2128 | padding space on the left or right. */ | ||
| 2129 | if (COMPOSITION_GLYPH (s->cmp, j) != '\t') | ||
| 2130 | { | ||
| 2131 | int xx = x + s->cmp->offsets[j * 2]; | ||
| 2132 | int yy = y - s->cmp->offsets[j * 2 + 1]; | ||
| 2133 | |||
| 2134 | font->driver->draw (s, j, j + 1, xx, yy, false); | ||
| 2135 | if (s->face->overstrike) | ||
| 2136 | font->driver->draw (s, j, j + 1, xx + 1, yy, false); | ||
| 2137 | } | ||
| 2138 | } | ||
| 2139 | else | ||
| 2140 | { | ||
| 2141 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 2142 | Lisp_Object glyph; | ||
| 2143 | int y = s->ybase; | ||
| 2144 | int width = 0; | ||
| 2145 | |||
| 2146 | for (i = j = s->cmp_from; i < s->cmp_to; i++) | ||
| 2147 | { | ||
| 2148 | glyph = LGSTRING_GLYPH (gstring, i); | ||
| 2149 | if (NILP (LGLYPH_ADJUSTMENT (glyph))) | ||
| 2150 | width += LGLYPH_WIDTH (glyph); | ||
| 2151 | else | ||
| 2152 | { | ||
| 2153 | int xoff, yoff, wadjust; | ||
| 2154 | |||
| 2155 | if (j < i) | ||
| 2156 | { | ||
| 2157 | font->driver->draw (s, j, i, x, y, false); | ||
| 2158 | if (s->face->overstrike) | ||
| 2159 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2160 | x += width; | ||
| 2161 | } | ||
| 2162 | xoff = LGLYPH_XOFF (glyph); | ||
| 2163 | yoff = LGLYPH_YOFF (glyph); | ||
| 2164 | wadjust = LGLYPH_WADJUST (glyph); | ||
| 2165 | font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false); | ||
| 2166 | if (s->face->overstrike) | ||
| 2167 | font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, | ||
| 2168 | false); | ||
| 2169 | x += wadjust; | ||
| 2170 | j = i + 1; | ||
| 2171 | width = 0; | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | if (j < i) | ||
| 2175 | { | ||
| 2176 | font->driver->draw (s, j, i, x, y, false); | ||
| 2177 | if (s->face->overstrike) | ||
| 2178 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | } | ||
| 2182 | |||
| 2183 | static void | ||
| 2184 | android_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | ||
| 2185 | { | ||
| 2186 | struct glyph *glyph = s->first_glyph; | ||
| 2187 | unsigned char2b[8]; | ||
| 2188 | int x, i, j; | ||
| 2189 | |||
| 2190 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2191 | of S to the right of that box line. */ | ||
| 2192 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2193 | && s->first_glyph->left_box_line_p) | ||
| 2194 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2195 | else | ||
| 2196 | x = s->x; | ||
| 2197 | |||
| 2198 | s->char2b = char2b; | ||
| 2199 | |||
| 2200 | for (i = 0; i < s->nchars; i++, glyph++) | ||
| 2201 | { | ||
| 2202 | #ifdef GCC_LINT | ||
| 2203 | enum { PACIFY_GCC_BUG_81401 = 1 }; | ||
| 2204 | #else | ||
| 2205 | enum { PACIFY_GCC_BUG_81401 = 0 }; | ||
| 2206 | #endif | ||
| 2207 | char buf[7 + PACIFY_GCC_BUG_81401]; | ||
| 2208 | char *str = NULL; | ||
| 2209 | int len = glyph->u.glyphless.len; | ||
| 2210 | |||
| 2211 | if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 2212 | { | ||
| 2213 | if (len > 0 | ||
| 2214 | && CHAR_TABLE_P (Vglyphless_char_display) | ||
| 2215 | && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) | ||
| 2216 | >= 1)) | ||
| 2217 | { | ||
| 2218 | Lisp_Object acronym | ||
| 2219 | = (! glyph->u.glyphless.for_no_font | ||
| 2220 | ? CHAR_TABLE_REF (Vglyphless_char_display, | ||
| 2221 | glyph->u.glyphless.ch) | ||
| 2222 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 2223 | if (CONSP (acronym)) | ||
| 2224 | acronym = XCAR (acronym); | ||
| 2225 | if (STRINGP (acronym)) | ||
| 2226 | str = SSDATA (acronym); | ||
| 2227 | } | ||
| 2228 | } | ||
| 2229 | else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE) | ||
| 2230 | { | ||
| 2231 | unsigned int ch = glyph->u.glyphless.ch; | ||
| 2232 | eassume (ch <= MAX_CHAR); | ||
| 2233 | sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch); | ||
| 2234 | str = buf; | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | if (str) | ||
| 2238 | { | ||
| 2239 | int upper_len = (len + 1) / 2; | ||
| 2240 | |||
| 2241 | /* It is assured that all LEN characters in STR is ASCII. */ | ||
| 2242 | for (j = 0; j < len; j++) | ||
| 2243 | char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF; | ||
| 2244 | s->font->driver->draw (s, 0, upper_len, | ||
| 2245 | x + glyph->slice.glyphless.upper_xoff, | ||
| 2246 | s->ybase + glyph->slice.glyphless.upper_yoff, | ||
| 2247 | false); | ||
| 2248 | s->font->driver->draw (s, upper_len, len, | ||
| 2249 | x + glyph->slice.glyphless.lower_xoff, | ||
| 2250 | s->ybase + glyph->slice.glyphless.lower_yoff, | ||
| 2251 | false); | ||
| 2252 | } | ||
| 2253 | if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 2254 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2255 | x, s->ybase - glyph->ascent, | ||
| 2256 | glyph->pixel_width - 1, | ||
| 2257 | glyph->ascent + glyph->descent - 1); | ||
| 2258 | x += glyph->pixel_width; | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | /* Defend against hypothetical bad code elsewhere that uses | ||
| 2262 | s->char2b after this function returns. */ | ||
| 2263 | s->char2b = NULL; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | static void | ||
| 2267 | android_draw_glyph_string (struct glyph_string *s) | ||
| 2268 | { | ||
| 2269 | bool relief_drawn_p = false; | ||
| 2270 | |||
| 2271 | /* If S draws into the background of its successors, draw the | ||
| 2272 | background of the successors first so that S can draw into it. | ||
| 2273 | This makes S->next use XDrawString instead of XDrawImageString. */ | ||
| 2274 | if (s->next && s->right_overhang && !s->for_overlaps) | ||
| 2275 | { | ||
| 2276 | int width; | ||
| 2277 | struct glyph_string *next; | ||
| 2278 | |||
| 2279 | for (width = 0, next = s->next; | ||
| 2280 | next && width < s->right_overhang; | ||
| 2281 | width += next->width, next = next->next) | ||
| 2282 | if (next->first_glyph->type != IMAGE_GLYPH) | ||
| 2283 | { | ||
| 2284 | android_set_glyph_string_gc (next); | ||
| 2285 | android_set_glyph_string_clipping (next); | ||
| 2286 | if (next->first_glyph->type == STRETCH_GLYPH) | ||
| 2287 | android_draw_stretch_glyph_string (next); | ||
| 2288 | else | ||
| 2289 | android_draw_glyph_string_background (next, true); | ||
| 2290 | next->num_clips = 0; | ||
| 2291 | } | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | /* Set up S->gc, set clipping and draw S. */ | ||
| 2295 | android_set_glyph_string_gc (s); | ||
| 2296 | |||
| 2297 | /* Draw relief (if any) in advance for char/composition so that the | ||
| 2298 | glyph string can be drawn over it. */ | ||
| 2299 | if (!s->for_overlaps | ||
| 2300 | && s->face->box != FACE_NO_BOX | ||
| 2301 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 2302 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 2303 | |||
| 2304 | { | ||
| 2305 | android_set_glyph_string_clipping (s); | ||
| 2306 | android_draw_glyph_string_background (s, true); | ||
| 2307 | android_draw_glyph_string_box (s); | ||
| 2308 | android_set_glyph_string_clipping (s); | ||
| 2309 | relief_drawn_p = true; | ||
| 2310 | } | ||
| 2311 | else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ | ||
| 2312 | && !s->clip_tail | ||
| 2313 | && ((s->prev && s->prev->hl != s->hl && s->left_overhang) | ||
| 2314 | || (s->next && s->next->hl != s->hl && s->right_overhang))) | ||
| 2315 | /* We must clip just this glyph. left_overhang part has already | ||
| 2316 | drawn when s->prev was drawn, and right_overhang part will be | ||
| 2317 | drawn later when s->next is drawn. */ | ||
| 2318 | android_set_glyph_string_clipping_exactly (s, s); | ||
| 2319 | else | ||
| 2320 | android_set_glyph_string_clipping (s); | ||
| 2321 | |||
| 2322 | switch (s->first_glyph->type) | ||
| 2323 | { | ||
| 2324 | case IMAGE_GLYPH: | ||
| 2325 | android_draw_image_glyph_string (s); | ||
| 2326 | break; | ||
| 2327 | |||
| 2328 | case XWIDGET_GLYPH: | ||
| 2329 | emacs_abort (); | ||
| 2330 | break; | ||
| 2331 | |||
| 2332 | case STRETCH_GLYPH: | ||
| 2333 | android_draw_stretch_glyph_string (s); | ||
| 2334 | break; | ||
| 2335 | |||
| 2336 | case CHAR_GLYPH: | ||
| 2337 | if (s->for_overlaps) | ||
| 2338 | s->background_filled_p = true; | ||
| 2339 | else | ||
| 2340 | android_draw_glyph_string_background (s, false); | ||
| 2341 | android_draw_glyph_string_foreground (s); | ||
| 2342 | break; | ||
| 2343 | |||
| 2344 | case COMPOSITE_GLYPH: | ||
| 2345 | if (s->for_overlaps || (s->cmp_from > 0 | ||
| 2346 | && ! s->first_glyph->u.cmp.automatic)) | ||
| 2347 | s->background_filled_p = true; | ||
| 2348 | else | ||
| 2349 | android_draw_glyph_string_background (s, true); | ||
| 2350 | android_draw_composite_glyph_string_foreground (s); | ||
| 2351 | break; | ||
| 2352 | |||
| 2353 | case GLYPHLESS_GLYPH: | ||
| 2354 | if (s->for_overlaps) | ||
| 2355 | s->background_filled_p = true; | ||
| 2356 | else | ||
| 2357 | android_draw_glyph_string_background (s, true); | ||
| 2358 | android_draw_glyphless_glyph_string_foreground (s); | ||
| 2359 | break; | ||
| 2360 | |||
| 2361 | default: | ||
| 2362 | emacs_abort (); | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | if (!s->for_overlaps) | ||
| 2366 | { | ||
| 2367 | int area_x, area_y, area_width, area_height; | ||
| 2368 | int area_max_x, decoration_width; | ||
| 2369 | |||
| 2370 | /* Prevent the underline from overwriting surrounding areas | ||
| 2371 | and the fringe. */ | ||
| 2372 | window_box (s->w, s->area, &area_x, &area_y, | ||
| 2373 | &area_width, &area_height); | ||
| 2374 | area_max_x = area_x + area_width - 1; | ||
| 2375 | |||
| 2376 | decoration_width = s->width; | ||
| 2377 | if (!s->row->mode_line_p | ||
| 2378 | && !s->row->tab_line_p | ||
| 2379 | && area_max_x < (s->x + decoration_width - 1)) | ||
| 2380 | decoration_width -= (s->x + decoration_width - 1) - area_max_x; | ||
| 2381 | |||
| 2382 | /* Draw relief if not yet drawn. */ | ||
| 2383 | if (!relief_drawn_p && s->face->box != FACE_NO_BOX) | ||
| 2384 | android_draw_glyph_string_box (s); | ||
| 2385 | |||
| 2386 | /* Draw underline. */ | ||
| 2387 | if (s->face->underline) | ||
| 2388 | { | ||
| 2389 | if (s->face->underline == FACE_UNDER_WAVE) | ||
| 2390 | { | ||
| 2391 | if (s->face->underline_defaulted_p) | ||
| 2392 | android_draw_underwave (s, decoration_width); | ||
| 2393 | else | ||
| 2394 | { | ||
| 2395 | struct android_gc_values xgcv; | ||
| 2396 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2397 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2398 | android_draw_underwave (s, decoration_width); | ||
| 2399 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2400 | } | ||
| 2401 | } | ||
| 2402 | else if (s->face->underline == FACE_UNDER_LINE) | ||
| 2403 | { | ||
| 2404 | unsigned long thickness, position; | ||
| 2405 | int y; | ||
| 2406 | |||
| 2407 | if (s->prev | ||
| 2408 | && s->prev->face->underline == FACE_UNDER_LINE | ||
| 2409 | && (s->prev->face->underline_at_descent_line_p | ||
| 2410 | == s->face->underline_at_descent_line_p) | ||
| 2411 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 2412 | == s->face->underline_pixels_above_descent_line)) | ||
| 2413 | { | ||
| 2414 | /* We use the same underline style as the previous one. */ | ||
| 2415 | thickness = s->prev->underline_thickness; | ||
| 2416 | position = s->prev->underline_position; | ||
| 2417 | } | ||
| 2418 | else | ||
| 2419 | { | ||
| 2420 | struct font *font = font_for_underline_metrics (s); | ||
| 2421 | unsigned long minimum_offset; | ||
| 2422 | bool underline_at_descent_line; | ||
| 2423 | bool use_underline_position_properties; | ||
| 2424 | Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2425 | (Qunderline_minimum_offset, s->w)); | ||
| 2426 | |||
| 2427 | if (FIXNUMP (val)) | ||
| 2428 | minimum_offset = max (0, XFIXNUM (val)); | ||
| 2429 | else | ||
| 2430 | minimum_offset = 1; | ||
| 2431 | |||
| 2432 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2433 | (Qx_underline_at_descent_line, s->w)); | ||
| 2434 | underline_at_descent_line | ||
| 2435 | = (!(NILP (val) || BASE_EQ (val, Qunbound)) | ||
| 2436 | || s->face->underline_at_descent_line_p); | ||
| 2437 | |||
| 2438 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2439 | (Qx_use_underline_position_properties, s->w)); | ||
| 2440 | use_underline_position_properties | ||
| 2441 | = !(NILP (val) || BASE_EQ (val, Qunbound)); | ||
| 2442 | |||
| 2443 | /* Get the underline thickness. Default is 1 pixel. */ | ||
| 2444 | if (font && font->underline_thickness > 0) | ||
| 2445 | thickness = font->underline_thickness; | ||
| 2446 | else | ||
| 2447 | thickness = 1; | ||
| 2448 | if (underline_at_descent_line) | ||
| 2449 | position = ((s->height - thickness) | ||
| 2450 | - (s->ybase - s->y) | ||
| 2451 | - s->face->underline_pixels_above_descent_line); | ||
| 2452 | else | ||
| 2453 | { | ||
| 2454 | /* Get the underline position. This is the | ||
| 2455 | recommended vertical offset in pixels from | ||
| 2456 | the baseline to the top of the underline. | ||
| 2457 | This is a signed value according to the | ||
| 2458 | specs, and its default is | ||
| 2459 | |||
| 2460 | ROUND ((maximum descent) / 2), with | ||
| 2461 | ROUND(x) = floor (x + 0.5) */ | ||
| 2462 | |||
| 2463 | if (use_underline_position_properties | ||
| 2464 | && font && font->underline_position >= 0) | ||
| 2465 | position = font->underline_position; | ||
| 2466 | else if (font) | ||
| 2467 | position = (font->descent + 1) / 2; | ||
| 2468 | else | ||
| 2469 | position = minimum_offset; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | /* Ignore minimum_offset if the amount of pixels was | ||
| 2473 | explicitly specified. */ | ||
| 2474 | if (!s->face->underline_pixels_above_descent_line) | ||
| 2475 | position = max (position, minimum_offset); | ||
| 2476 | } | ||
| 2477 | /* Check the sanity of thickness and position. We should | ||
| 2478 | avoid drawing underline out of the current line area. */ | ||
| 2479 | if (s->y + s->height <= s->ybase + position) | ||
| 2480 | position = (s->height - 1) - (s->ybase - s->y); | ||
| 2481 | if (s->y + s->height < s->ybase + position + thickness) | ||
| 2482 | thickness = (s->y + s->height) - (s->ybase + position); | ||
| 2483 | s->underline_thickness = thickness; | ||
| 2484 | s->underline_position = position; | ||
| 2485 | y = s->ybase + position; | ||
| 2486 | if (s->face->underline_defaulted_p) | ||
| 2487 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2488 | s->x, y, decoration_width, thickness); | ||
| 2489 | else | ||
| 2490 | { | ||
| 2491 | struct android_gc_values xgcv; | ||
| 2492 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2493 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2494 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2495 | s->x, y, decoration_width, thickness); | ||
| 2496 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2497 | } | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | /* Draw overline. */ | ||
| 2501 | if (s->face->overline_p) | ||
| 2502 | { | ||
| 2503 | unsigned long dy = 0, h = 1; | ||
| 2504 | |||
| 2505 | if (s->face->overline_color_defaulted_p) | ||
| 2506 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2507 | s->gc, s->x, s->y + dy, | ||
| 2508 | decoration_width, h); | ||
| 2509 | else | ||
| 2510 | { | ||
| 2511 | struct android_gc_values xgcv; | ||
| 2512 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2513 | android_set_foreground (s->gc, s->face->overline_color); | ||
| 2514 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2515 | s->y + dy, decoration_width, h); | ||
| 2516 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2517 | } | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | /* Draw strike-through. */ | ||
| 2521 | if (s->face->strike_through_p) | ||
| 2522 | { | ||
| 2523 | /* Y-coordinate and height of the glyph string's first | ||
| 2524 | glyph. We cannot use s->y and s->height because those | ||
| 2525 | could be larger if there are taller display elements | ||
| 2526 | (e.g., characters displayed with a larger font) in the | ||
| 2527 | same glyph row. */ | ||
| 2528 | int glyph_y = s->ybase - s->first_glyph->ascent; | ||
| 2529 | int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; | ||
| 2530 | /* Strike-through width and offset from the glyph string's | ||
| 2531 | top edge. */ | ||
| 2532 | unsigned long h = 1; | ||
| 2533 | unsigned long dy = (glyph_height - h) / 2; | ||
| 2534 | |||
| 2535 | if (s->face->strike_through_color_defaulted_p) | ||
| 2536 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2537 | s->gc, s->x, glyph_y + dy, | ||
| 2538 | s->width, h); | ||
| 2539 | else | ||
| 2540 | { | ||
| 2541 | struct android_gc_values xgcv; | ||
| 2542 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2543 | android_set_foreground (s->gc, s->face->strike_through_color); | ||
| 2544 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2545 | glyph_y + dy, decoration_width, h); | ||
| 2546 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2547 | } | ||
| 2548 | } | ||
| 2549 | |||
| 2550 | if (s->prev) | ||
| 2551 | { | ||
| 2552 | struct glyph_string *prev; | ||
| 2553 | |||
| 2554 | for (prev = s->prev; prev; prev = prev->prev) | ||
| 2555 | if (prev->hl != s->hl | ||
| 2556 | && prev->x + prev->width + prev->right_overhang > s->x) | ||
| 2557 | { | ||
| 2558 | /* As prev was drawn while clipped to its own area, we | ||
| 2559 | must draw the right_overhang part using s->hl now. */ | ||
| 2560 | enum draw_glyphs_face save = prev->hl; | ||
| 2561 | |||
| 2562 | prev->hl = s->hl; | ||
| 2563 | android_set_glyph_string_gc (prev); | ||
| 2564 | android_set_glyph_string_clipping_exactly (s, prev); | ||
| 2565 | if (prev->first_glyph->type == CHAR_GLYPH) | ||
| 2566 | android_draw_glyph_string_foreground (prev); | ||
| 2567 | else | ||
| 2568 | android_draw_composite_glyph_string_foreground (prev); | ||
| 2569 | android_reset_clip_rectangles (prev->f, prev->gc); | ||
| 2570 | prev->hl = save; | ||
| 2571 | prev->num_clips = 0; | ||
| 2572 | } | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | if (s->next) | ||
| 2576 | { | ||
| 2577 | struct glyph_string *next; | ||
| 2578 | |||
| 2579 | for (next = s->next; next; next = next->next) | ||
| 2580 | if (next->hl != s->hl | ||
| 2581 | && next->x - next->left_overhang < s->x + s->width) | ||
| 2582 | { | ||
| 2583 | /* As next will be drawn while clipped to its own area, | ||
| 2584 | we must draw the left_overhang part using s->hl now. */ | ||
| 2585 | enum draw_glyphs_face save = next->hl; | ||
| 2586 | |||
| 2587 | next->hl = s->hl; | ||
| 2588 | android_set_glyph_string_gc (next); | ||
| 2589 | android_set_glyph_string_clipping_exactly (s, next); | ||
| 2590 | if (next->first_glyph->type == CHAR_GLYPH) | ||
| 2591 | android_draw_glyph_string_foreground (next); | ||
| 2592 | else | ||
| 2593 | android_draw_composite_glyph_string_foreground (next); | ||
| 2594 | android_reset_clip_rectangles (next->f, next->gc); | ||
| 2595 | next->hl = save; | ||
| 2596 | next->num_clips = 0; | ||
| 2597 | next->clip_head = s->next; | ||
| 2598 | } | ||
| 2599 | } | ||
| 2600 | } | ||
| 2601 | |||
| 2602 | /* Reset clipping. */ | ||
| 2603 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 2604 | s->num_clips = 0; | ||
| 2605 | |||
| 2606 | /* Set the stippled flag that tells redisplay whether or not a | ||
| 2607 | stipple was actually draw. */ | ||
| 2608 | |||
| 2609 | if (s->first_glyph->type != STRETCH_GLYPH | ||
| 2610 | && s->first_glyph->type != IMAGE_GLYPH | ||
| 2611 | && !s->row->stipple_p) | ||
| 2612 | s->row->stipple_p = s->stippled_p; | ||
| 2613 | } | ||
| 2614 | |||
| 2615 | static void | ||
| 2616 | android_define_frame_cursor (struct frame *f, Emacs_Cursor cursor) | ||
| 2617 | { | ||
| 2618 | /* Not supported, because cursors are not supported on Android. */ | ||
| 2619 | } | ||
| 2620 | |||
| 2621 | static void | ||
| 2622 | android_clear_frame_area (struct frame *f, int x, int y, | ||
| 2623 | int width, int height) | ||
| 2624 | { | ||
| 2625 | android_clear_area (FRAME_ANDROID_WINDOW (f), | ||
| 2626 | x, y, width, height); | ||
| 2627 | } | ||
| 2628 | |||
| 2629 | void | ||
| 2630 | android_clear_under_internal_border (struct frame *f) | ||
| 2631 | { | ||
| 2632 | if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) | ||
| 2633 | { | ||
| 2634 | int border = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 2635 | int width = FRAME_PIXEL_WIDTH (f); | ||
| 2636 | int height = FRAME_PIXEL_HEIGHT (f); | ||
| 2637 | int margin = FRAME_TOP_MARGIN_HEIGHT (f); | ||
| 2638 | int face_id = | ||
| 2639 | (FRAME_PARENT_FRAME (f) | ||
| 2640 | ? (!NILP (Vface_remapping_alist) | ||
| 2641 | ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID) | ||
| 2642 | : CHILD_FRAME_BORDER_FACE_ID) | ||
| 2643 | : (!NILP (Vface_remapping_alist) | ||
| 2644 | ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) | ||
| 2645 | : INTERNAL_BORDER_FACE_ID)); | ||
| 2646 | struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); | ||
| 2647 | |||
| 2648 | if (face) | ||
| 2649 | { | ||
| 2650 | unsigned long color = face->background; | ||
| 2651 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 2652 | |||
| 2653 | android_set_foreground (gc, color); | ||
| 2654 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, margin, | ||
| 2655 | width, border); | ||
| 2656 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, 0, | ||
| 2657 | border, height); | ||
| 2658 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, width - border, | ||
| 2659 | 0, border, height); | ||
| 2660 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, | ||
| 2661 | height - border, width, border); | ||
| 2662 | android_set_foreground (gc, FRAME_FOREGROUND_PIXEL (f)); | ||
| 2663 | } | ||
| 2664 | else | ||
| 2665 | { | ||
| 2666 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, 0, | ||
| 2667 | border, height); | ||
| 2668 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2669 | margin, width, border); | ||
| 2670 | android_clear_area (FRAME_ANDROID_WINDOW (f), width - border, | ||
| 2671 | 0, border, height); | ||
| 2672 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2673 | height - border, width, border); | ||
| 2674 | } | ||
| 2675 | } | ||
| 2676 | } | ||
| 2677 | |||
| 2678 | static void | ||
| 2679 | android_draw_hollow_cursor (struct window *w, struct glyph_row *row) | ||
| 2680 | { | ||
| 2681 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2682 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 2683 | int x, y, wd, h; | ||
| 2684 | struct android_gc_values xgcv; | ||
| 2685 | struct glyph *cursor_glyph; | ||
| 2686 | struct android_gc *gc; | ||
| 2687 | |||
| 2688 | /* Get the glyph the cursor is on. If we can't tell because | ||
| 2689 | the current matrix is invalid or such, give up. */ | ||
| 2690 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2691 | if (cursor_glyph == NULL) | ||
| 2692 | return; | ||
| 2693 | |||
| 2694 | /* Compute frame-relative coordinates for phys cursor. */ | ||
| 2695 | get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h); | ||
| 2696 | wd = w->phys_cursor_width - 1; | ||
| 2697 | |||
| 2698 | /* The foreground of cursor_gc is typically the same as the normal | ||
| 2699 | background color, which can cause the cursor box to be invisible. */ | ||
| 2700 | xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2701 | if (dpyinfo->scratch_cursor_gc) | ||
| 2702 | android_change_gc (dpyinfo->scratch_cursor_gc, | ||
| 2703 | ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2704 | else | ||
| 2705 | dpyinfo->scratch_cursor_gc | ||
| 2706 | = android_create_gc (ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2707 | gc = dpyinfo->scratch_cursor_gc; | ||
| 2708 | |||
| 2709 | /* When on R2L character, show cursor at the right edge of the | ||
| 2710 | glyph, unless the cursor box is as wide as the glyph or wider | ||
| 2711 | (the latter happens when x-stretch-cursor is non-nil). */ | ||
| 2712 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2713 | && cursor_glyph->pixel_width > wd) | ||
| 2714 | { | ||
| 2715 | x += cursor_glyph->pixel_width - wd; | ||
| 2716 | if (wd > 0) | ||
| 2717 | wd -= 1; | ||
| 2718 | } | ||
| 2719 | /* Set clipping, draw the rectangle, and reset clipping again. */ | ||
| 2720 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2721 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, y, wd, h - 1); | ||
| 2722 | android_reset_clip_rectangles (f, gc); | ||
| 2723 | } | ||
| 2724 | |||
| 2725 | static void | ||
| 2726 | android_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, | ||
| 2727 | enum text_cursor_kinds kind) | ||
| 2728 | { | ||
| 2729 | struct frame *f = XFRAME (w->frame); | ||
| 2730 | struct glyph *cursor_glyph; | ||
| 2731 | int cursor_start_y; | ||
| 2732 | |||
| 2733 | /* If cursor is out of bounds, don't draw garbage. This can happen | ||
| 2734 | in mini-buffer windows when switching between echo area glyphs | ||
| 2735 | and mini-buffer. */ | ||
| 2736 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2737 | if (cursor_glyph == NULL) | ||
| 2738 | return; | ||
| 2739 | |||
| 2740 | /* Experimental avoidance of cursor on xwidget. */ | ||
| 2741 | if (cursor_glyph->type == XWIDGET_GLYPH) | ||
| 2742 | return; | ||
| 2743 | |||
| 2744 | /* If on an image, draw like a normal cursor. That's usually better | ||
| 2745 | visible than drawing a bar, esp. if the image is large so that | ||
| 2746 | the bar might not be in the window. */ | ||
| 2747 | if (cursor_glyph->type == IMAGE_GLYPH) | ||
| 2748 | { | ||
| 2749 | struct glyph_row *r; | ||
| 2750 | r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos); | ||
| 2751 | draw_phys_cursor_glyph (w, r, DRAW_CURSOR); | ||
| 2752 | } | ||
| 2753 | else | ||
| 2754 | { | ||
| 2755 | struct android_gc *gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc; | ||
| 2756 | unsigned long mask = ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND; | ||
| 2757 | struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); | ||
| 2758 | struct android_gc_values xgcv; | ||
| 2759 | |||
| 2760 | /* If the glyph's background equals the color we normally draw | ||
| 2761 | the bars cursor in, the bar cursor in its normal color is | ||
| 2762 | invisible. Use the glyph's foreground color instead in this | ||
| 2763 | case, on the assumption that the glyph's colors are chosen so | ||
| 2764 | that the glyph is legible. */ | ||
| 2765 | if (face->background == f->output_data.android->cursor_pixel) | ||
| 2766 | xgcv.background = xgcv.foreground = face->foreground; | ||
| 2767 | else | ||
| 2768 | xgcv.background = xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2769 | |||
| 2770 | if (gc) | ||
| 2771 | android_change_gc (gc, mask, &xgcv); | ||
| 2772 | else | ||
| 2773 | { | ||
| 2774 | gc = android_create_gc (mask, &xgcv); | ||
| 2775 | FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; | ||
| 2776 | } | ||
| 2777 | |||
| 2778 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2779 | |||
| 2780 | if (kind == BAR_CURSOR) | ||
| 2781 | { | ||
| 2782 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2783 | |||
| 2784 | if (width < 0) | ||
| 2785 | width = FRAME_CURSOR_WIDTH (f); | ||
| 2786 | width = min (cursor_glyph->pixel_width, width); | ||
| 2787 | |||
| 2788 | w->phys_cursor_width = width; | ||
| 2789 | |||
| 2790 | /* If the character under cursor is R2L, draw the bar cursor | ||
| 2791 | on the right of its glyph, rather than on the left. */ | ||
| 2792 | if ((cursor_glyph->resolved_level & 1) != 0) | ||
| 2793 | x += cursor_glyph->pixel_width - width; | ||
| 2794 | |||
| 2795 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2796 | WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), | ||
| 2797 | width, row->height); | ||
| 2798 | } | ||
| 2799 | else /* HBAR_CURSOR */ | ||
| 2800 | { | ||
| 2801 | int dummy_x, dummy_y, dummy_h; | ||
| 2802 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2803 | |||
| 2804 | if (width < 0) | ||
| 2805 | width = row->height; | ||
| 2806 | |||
| 2807 | width = min (row->height, width); | ||
| 2808 | |||
| 2809 | get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x, | ||
| 2810 | &dummy_y, &dummy_h); | ||
| 2811 | |||
| 2812 | cursor_start_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y | ||
| 2813 | + row->height - width); | ||
| 2814 | |||
| 2815 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2816 | && cursor_glyph->pixel_width > w->phys_cursor_width - 1) | ||
| 2817 | x += cursor_glyph->pixel_width - w->phys_cursor_width + 1; | ||
| 2818 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2819 | cursor_start_y, | ||
| 2820 | w->phys_cursor_width - 1, width); | ||
| 2821 | } | ||
| 2822 | |||
| 2823 | android_reset_clip_rectangles (f, gc); | ||
| 2824 | } | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | static void | ||
| 2828 | android_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, | ||
| 2829 | int x, int y, enum text_cursor_kinds cursor_type, | ||
| 2830 | int cursor_width, bool on_p, bool active_p) | ||
| 2831 | { | ||
| 2832 | if (on_p) | ||
| 2833 | { | ||
| 2834 | w->phys_cursor_type = cursor_type; | ||
| 2835 | w->phys_cursor_on_p = true; | ||
| 2836 | |||
| 2837 | if (glyph_row->exact_window_width_line_p | ||
| 2838 | && (glyph_row->reversed_p | ||
| 2839 | ? (w->phys_cursor.hpos < 0) | ||
| 2840 | : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]))) | ||
| 2841 | { | ||
| 2842 | glyph_row->cursor_in_fringe_p = true; | ||
| 2843 | draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p); | ||
| 2844 | } | ||
| 2845 | else | ||
| 2846 | { | ||
| 2847 | switch (cursor_type) | ||
| 2848 | { | ||
| 2849 | case HOLLOW_BOX_CURSOR: | ||
| 2850 | android_draw_hollow_cursor (w, glyph_row); | ||
| 2851 | break; | ||
| 2852 | |||
| 2853 | case FILLED_BOX_CURSOR: | ||
| 2854 | draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); | ||
| 2855 | break; | ||
| 2856 | |||
| 2857 | case BAR_CURSOR: | ||
| 2858 | android_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR); | ||
| 2859 | break; | ||
| 2860 | |||
| 2861 | case HBAR_CURSOR: | ||
| 2862 | android_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR); | ||
| 2863 | break; | ||
| 2864 | |||
| 2865 | case NO_CURSOR: | ||
| 2866 | w->phys_cursor_width = 0; | ||
| 2867 | break; | ||
| 2868 | |||
| 2869 | default: | ||
| 2870 | emacs_abort (); | ||
| 2871 | } | ||
| 2872 | } | ||
| 2873 | } | ||
| 2874 | } | ||
| 2875 | |||
| 2876 | static void | ||
| 2877 | android_draw_vertical_window_border (struct window *w, int x, int y0, int y1) | ||
| 2878 | { | ||
| 2879 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2880 | struct face *face; | ||
| 2881 | |||
| 2882 | face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); | ||
| 2883 | if (face) | ||
| 2884 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2885 | face->foreground); | ||
| 2886 | |||
| 2887 | android_draw_line (FRAME_ANDROID_WINDOW (f), | ||
| 2888 | f->output_data.android->normal_gc, | ||
| 2889 | x, y0, x, y1); | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | static void | ||
| 2893 | android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) | ||
| 2894 | { | ||
| 2895 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2896 | struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); | ||
| 2897 | struct face *face_first | ||
| 2898 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); | ||
| 2899 | struct face *face_last | ||
| 2900 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); | ||
| 2901 | unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); | ||
| 2902 | unsigned long color_first = (face_first | ||
| 2903 | ? face_first->foreground | ||
| 2904 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2905 | unsigned long color_last = (face_last | ||
| 2906 | ? face_last->foreground | ||
| 2907 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2908 | |||
| 2909 | if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3)) | ||
| 2910 | /* A vertical divider, at least three pixels wide: Draw first and | ||
| 2911 | last pixels differently. */ | ||
| 2912 | { | ||
| 2913 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2914 | color_first); | ||
| 2915 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2916 | f->output_data.android->normal_gc, | ||
| 2917 | x0, y0, 1, y1 - y0); | ||
| 2918 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2919 | color); | ||
| 2920 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2921 | f->output_data.android->normal_gc, | ||
| 2922 | x0 + 1, y0, x1 - x0 - 2, y1 - y0); | ||
| 2923 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2924 | color_last); | ||
| 2925 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2926 | f->output_data.android->normal_gc, | ||
| 2927 | x1 - 1, y0, 1, y1 - y0); | ||
| 2928 | } | ||
| 2929 | else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3)) | ||
| 2930 | /* A horizontal divider, at least three pixels high: Draw first | ||
| 2931 | and last pixels differently. */ | ||
| 2932 | { | ||
| 2933 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2934 | color_first); | ||
| 2935 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2936 | f->output_data.android->normal_gc, | ||
| 2937 | x0, y0, x1 - x0, 1); | ||
| 2938 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2939 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2940 | f->output_data.android->normal_gc, | ||
| 2941 | x0, y0 + 1, x1 - x0, y1 - y0 - 2); | ||
| 2942 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2943 | color_last); | ||
| 2944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2945 | f->output_data.android->normal_gc, | ||
| 2946 | x0, y1 - 1, x1 - x0, 1); | ||
| 2947 | } | ||
| 2948 | else | ||
| 2949 | { | ||
| 2950 | /* In any other case do not draw the first and last pixels | ||
| 2951 | differently. */ | ||
| 2952 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2953 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2954 | f->output_data.android->normal_gc, | ||
| 2955 | x0, y0, x1 - x0, y1 - y0); | ||
| 2956 | } | ||
| 2957 | } | ||
| 2958 | |||
| 2959 | |||
| 2960 | |||
| 2961 | extern frame_parm_handler android_frame_parm_handlers[]; | ||
| 2962 | |||
| 2963 | #endif /* !ANDROID_STUBIFY */ | ||
| 2964 | |||
| 2965 | static struct redisplay_interface android_redisplay_interface = | ||
| 2966 | { | ||
| 2967 | #ifndef ANDROID_STUBIFY | ||
| 2968 | android_frame_parm_handlers, | ||
| 2969 | gui_produce_glyphs, | ||
| 2970 | gui_write_glyphs, | ||
| 2971 | gui_insert_glyphs, | ||
| 2972 | gui_clear_end_of_line, | ||
| 2973 | android_scroll_run, | ||
| 2974 | android_after_update_window_line, | ||
| 2975 | NULL, /* update_window_begin */ | ||
| 2976 | NULL, /* update_window_end */ | ||
| 2977 | android_flip_and_flush, | ||
| 2978 | gui_clear_window_mouse_face, | ||
| 2979 | gui_get_glyph_overhangs, | ||
| 2980 | gui_fix_overlapping_area, | ||
| 2981 | android_draw_fringe_bitmap, | ||
| 2982 | NULL, /* define_fringe_bitmap */ | ||
| 2983 | NULL, /* destroy_fringe_bitmap */ | ||
| 2984 | android_compute_glyph_string_overhangs, | ||
| 2985 | android_draw_glyph_string, | ||
| 2986 | android_define_frame_cursor, | ||
| 2987 | android_clear_frame_area, | ||
| 2988 | android_clear_under_internal_border, | ||
| 2989 | android_draw_window_cursor, | ||
| 2990 | android_draw_vertical_window_border, | ||
| 2991 | android_draw_window_divider, | ||
| 2992 | NULL, | ||
| 2993 | NULL, | ||
| 2994 | NULL, | ||
| 2995 | android_default_font_parameter, | ||
| 2996 | #endif | ||
| 2997 | }; | ||
| 2998 | |||
| 2999 | |||
| 3000 | |||
| 3001 | void | ||
| 3002 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | ||
| 3003 | { | ||
| 3004 | /* This cannot be implemented on Android, and as such is left | ||
| 3005 | blank. */ | ||
| 3006 | } | ||
| 3007 | |||
| 3008 | char * | ||
| 3009 | get_keysym_name (int keysym) | ||
| 3010 | { | ||
| 3011 | return (char *) "UNKNOWN KEYSYM"; | ||
| 3012 | } | ||
| 3013 | |||
| 3014 | |||
| 3015 | |||
| 3016 | /* Create a struct terminal, initialize it with the Android specific | ||
| 3017 | functions and make DISPLAY->TERMINAL point to it. */ | ||
| 3018 | |||
| 3019 | static struct terminal * | ||
| 3020 | android_create_terminal (struct android_display_info *dpyinfo) | ||
| 3021 | { | ||
| 3022 | struct terminal *terminal; | ||
| 3023 | |||
| 3024 | terminal = create_terminal (output_android, | ||
| 3025 | &android_redisplay_interface); | ||
| 3026 | terminal->display_info.android = dpyinfo; | ||
| 3027 | dpyinfo->terminal = terminal; | ||
| 3028 | |||
| 3029 | /* kboard is initialized in android_term_init. */ | ||
| 3030 | |||
| 3031 | #ifndef ANDROID_STUBIFY | ||
| 3032 | |||
| 3033 | terminal->clear_frame_hook = android_clear_frame; | ||
| 3034 | terminal->ring_bell_hook = android_ring_bell; | ||
| 3035 | terminal->toggle_invisible_pointer_hook | ||
| 3036 | = android_toggle_invisible_pointer; | ||
| 3037 | terminal->update_begin_hook = android_update_begin; | ||
| 3038 | terminal->update_end_hook = android_update_end; | ||
| 3039 | terminal->read_socket_hook = android_read_socket; | ||
| 3040 | terminal->frame_up_to_date_hook = android_frame_up_to_date; | ||
| 3041 | terminal->buffer_flipping_unblocked_hook | ||
| 3042 | = android_buffer_flipping_unblocked_hook; | ||
| 3043 | terminal->defined_color_hook = android_defined_color; | ||
| 3044 | terminal->query_frame_background_color | ||
| 3045 | = android_query_frame_background_color; | ||
| 3046 | terminal->query_colors = android_query_colors; | ||
| 3047 | terminal->mouse_position_hook = android_mouse_position; | ||
| 3048 | terminal->get_focus_frame = android_get_focus_frame; | ||
| 3049 | terminal->focus_frame_hook = android_focus_frame; | ||
| 3050 | terminal->frame_rehighlight_hook = android_frame_rehighlight; | ||
| 3051 | terminal->frame_raise_lower_hook = android_frame_raise_lower; | ||
| 3052 | terminal->frame_visible_invisible_hook | ||
| 3053 | = android_make_frame_visible_invisible; | ||
| 3054 | terminal->fullscreen_hook = android_fullscreen_hook; | ||
| 3055 | terminal->iconify_frame_hook = android_iconify_frame; | ||
| 3056 | terminal->set_window_size_hook = android_set_window_size; | ||
| 3057 | terminal->set_frame_offset_hook = android_set_offset; | ||
| 3058 | terminal->set_frame_alpha_hook = android_set_alpha; | ||
| 3059 | terminal->set_new_font_hook = android_new_font; | ||
| 3060 | terminal->set_bitmap_icon_hook = android_bitmap_icon; | ||
| 3061 | terminal->implicit_set_name_hook = android_implicitly_set_name; | ||
| 3062 | /* terminal->menu_show_hook = android_menu_show; XXX */ | ||
| 3063 | terminal->change_tab_bar_height_hook = android_change_tab_bar_height; | ||
| 3064 | terminal->change_tool_bar_height_hook = android_change_tool_bar_height; | ||
| 3065 | /* terminal->set_vertical_scroll_bar_hook */ | ||
| 3066 | /* = android_set_vertical_scroll_bar; */ | ||
| 3067 | /* terminal->set_horizontal_scroll_bar_hook */ | ||
| 3068 | /* = android_set_horizontal_scroll_bar; */ | ||
| 3069 | terminal->set_scroll_bar_default_width_hook | ||
| 3070 | = android_set_scroll_bar_default_width; | ||
| 3071 | terminal->set_scroll_bar_default_height_hook | ||
| 3072 | = android_set_scroll_bar_default_height; | ||
| 3073 | /* terminal->condemn_scroll_bars_hook = android_condemn_scroll_bars; */ | ||
| 3074 | /* terminal->redeem_scroll_bars_hook = android_redeem_scroll_bars; */ | ||
| 3075 | /* terminal->judge_scroll_bars_hook = android_judge_scroll_bars; */ | ||
| 3076 | terminal->free_pixmap = android_free_pixmap_hook; | ||
| 3077 | terminal->delete_frame_hook = android_delete_frame; | ||
| 3078 | terminal->delete_terminal_hook = android_delete_terminal; | ||
| 3079 | |||
| 3080 | #else | ||
| 3081 | emacs_abort (); | ||
| 3082 | #endif | ||
| 3083 | |||
| 3084 | return terminal; | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | /* Initialize the Android terminal interface. The display connection | ||
| 3088 | has already been set up by the system at this point. */ | ||
| 3089 | |||
| 3090 | void | ||
| 3091 | android_term_init (void) | ||
| 3092 | { | ||
| 3093 | struct terminal *terminal; | ||
| 3094 | struct android_display_info *dpyinfo; | ||
| 3095 | Lisp_Object color_file, color_map; | ||
| 3096 | |||
| 3097 | dpyinfo = xzalloc (sizeof *dpyinfo); | ||
| 3098 | terminal = android_create_terminal (dpyinfo); | ||
| 3099 | terminal->kboard = allocate_kboard (Qandroid); | ||
| 3100 | terminal->kboard->reference_count++; | ||
| 3101 | |||
| 3102 | dpyinfo->n_planes = 24; | ||
| 3103 | |||
| 3104 | /* This function should only be called once at startup. */ | ||
| 3105 | eassert (!x_display_list); | ||
| 3106 | x_display_list = dpyinfo; | ||
| 3107 | |||
| 3108 | dpyinfo->name_list_element | ||
| 3109 | = Fcons (build_pure_c_string ("android"), Qnil); | ||
| 3110 | |||
| 3111 | color_file = Fexpand_file_name (build_string ("rgb.txt"), | ||
| 3112 | Vdata_directory); | ||
| 3113 | color_map = Fx_load_color_file (color_file); | ||
| 3114 | |||
| 3115 | if (NILP (color_map)) | ||
| 3116 | fatal ("Could not read %s.\n", SDATA (color_file)); | ||
| 3117 | |||
| 3118 | dpyinfo->color_map = color_map; | ||
| 3119 | |||
| 3120 | /* TODO! */ | ||
| 3121 | dpyinfo->resx = 96.0; | ||
| 3122 | dpyinfo->resy = 96.0; | ||
| 3123 | |||
| 3124 | /* https://lists.gnu.org/r/emacs-devel/2015-11/msg00194.html */ | ||
| 3125 | dpyinfo->smallest_font_height = 1; | ||
| 3126 | dpyinfo->smallest_char_width = 1; | ||
| 3127 | |||
| 3128 | terminal->name = xstrdup ("android"); | ||
| 3129 | |||
| 3130 | /* The display "connection" is now set up, and it must never go | ||
| 3131 | away. */ | ||
| 3132 | terminal->reference_count = 30000; | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | |||
| 3136 | |||
| 3137 | void | ||
| 3138 | syms_of_androidterm (void) | ||
| 3139 | { | ||
| 3140 | Fprovide (Qandroid, Qnil); | ||
| 3141 | |||
| 3142 | DEFVAR_BOOL ("x-use-underline-position-properties", | ||
| 3143 | x_use_underline_position_properties, | ||
| 3144 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3145 | x_use_underline_position_properties = true; | ||
| 3146 | DEFSYM (Qx_use_underline_position_properties, | ||
| 3147 | "x-use-underline-position-properties"); | ||
| 3148 | |||
| 3149 | DEFVAR_BOOL ("x-underline-at-descent-line", | ||
| 3150 | x_underline_at_descent_line, | ||
| 3151 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3152 | x_underline_at_descent_line = false; | ||
| 3153 | DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | void | ||
| 3157 | mark_androidterm (void) | ||
| 3158 | { | ||
| 3159 | if (x_display_list) | ||
| 3160 | mark_object (x_display_list->color_map); | ||
| 3161 | } | ||
diff --git a/src/androidterm.h b/src/androidterm.h new file mode 100644 index 00000000000..3a0c9f60555 --- /dev/null +++ b/src/androidterm.h | |||
| @@ -0,0 +1,366 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #ifndef _ANDROID_TERM_H_ | ||
| 21 | #define _ANDROID_TERM_H_ | ||
| 22 | |||
| 23 | #include "androidgui.h" | ||
| 24 | #include "frame.h" | ||
| 25 | #include "character.h" | ||
| 26 | #include "dispextern.h" | ||
| 27 | #include "font.h" | ||
| 28 | |||
| 29 | struct android_bitmap_record | ||
| 30 | { | ||
| 31 | /* The image backing the bitmap. */ | ||
| 32 | Emacs_Pixmap img; | ||
| 33 | |||
| 34 | /* The file from which it comes. */ | ||
| 35 | char *file; | ||
| 36 | |||
| 37 | /* The number of references to it. */ | ||
| 38 | int refcount; | ||
| 39 | |||
| 40 | /* The height and width. */ | ||
| 41 | int height, width; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct android_display_info | ||
| 45 | { | ||
| 46 | /* Chain of all struct android_display_info structures. */ | ||
| 47 | struct android_display_info *next; | ||
| 48 | |||
| 49 | /* The terminal. */ | ||
| 50 | struct terminal *terminal; | ||
| 51 | |||
| 52 | /* The root window. This field is unused. */ | ||
| 53 | Emacs_Window root_window; | ||
| 54 | |||
| 55 | /* List possibly used only for the font cache but probably used for | ||
| 56 | something else too. */ | ||
| 57 | Lisp_Object name_list_element; | ||
| 58 | |||
| 59 | /* List of predefined X colors. */ | ||
| 60 | Lisp_Object color_map; | ||
| 61 | |||
| 62 | /* DPI of the display. */ | ||
| 63 | double resx, resy; | ||
| 64 | |||
| 65 | /* Scratch GC for drawing a cursor in a non-default face. */ | ||
| 66 | struct android_gc *scratch_cursor_gc; | ||
| 67 | |||
| 68 | /* Mouse highlight information. */ | ||
| 69 | Mouse_HLInfo mouse_highlight; | ||
| 70 | |||
| 71 | /* Number of planes on this screen. Always 24. */ | ||
| 72 | int n_planes; | ||
| 73 | |||
| 74 | /* Mask of things causing the mouse to be grabbed. */ | ||
| 75 | int grabbed; | ||
| 76 | |||
| 77 | /* Minimum width over all characters in all fonts in font_table. */ | ||
| 78 | int smallest_char_width; | ||
| 79 | |||
| 80 | /* Minimum font height over all fonts in font_table. */ | ||
| 81 | int smallest_font_height; | ||
| 82 | |||
| 83 | /* The number of fonts opened for this display. */ | ||
| 84 | int n_fonts; | ||
| 85 | |||
| 86 | /* Pointer to bitmap records. */ | ||
| 87 | struct android_bitmap_record *bitmaps; | ||
| 88 | |||
| 89 | /* Allocated size of bitmaps field. */ | ||
| 90 | ptrdiff_t bitmaps_size; | ||
| 91 | |||
| 92 | /* Last used bitmap index. */ | ||
| 93 | ptrdiff_t bitmaps_last; | ||
| 94 | |||
| 95 | /* The frame currently with the input focus. */ | ||
| 96 | struct frame *focus_frame; | ||
| 97 | |||
| 98 | /* The frame which currently has the visual highlight, and should | ||
| 99 | get keyboard input. It points to the focus frame's selected | ||
| 100 | window's frame, but can differ. */ | ||
| 101 | struct frame *highlight_frame; | ||
| 102 | |||
| 103 | /* The frame waiting to be auto-raised in android_read_socket. */ | ||
| 104 | struct frame *pending_autoraise_frame; | ||
| 105 | |||
| 106 | /* The frame where the mouse was the last time a button event | ||
| 107 | happened. */ | ||
| 108 | struct frame *last_mouse_frame; | ||
| 109 | |||
| 110 | /* The frame where the mouse was the last time the mouse glyph | ||
| 111 | changed. */ | ||
| 112 | struct frame *last_mouse_glyph_frame; | ||
| 113 | |||
| 114 | /* The frame where the mouse was the last time mouse motion | ||
| 115 | happened. */ | ||
| 116 | struct frame *last_mouse_motion_frame; | ||
| 117 | |||
| 118 | /* Position where the mouse was last time we reported a motion. | ||
| 119 | This is a position on last_mouse_motion_frame. It is used in to | ||
| 120 | report the mouse position as well: see | ||
| 121 | android_mouse_position. */ | ||
| 122 | int last_mouse_motion_x, last_mouse_motion_y; | ||
| 123 | |||
| 124 | /* Where the mouse was the last time the mouse moved. */ | ||
| 125 | Emacs_Rectangle last_mouse_glyph; | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct android_output | ||
| 129 | { | ||
| 130 | /* Graphics contexts for the default font. */ | ||
| 131 | struct android_gc *normal_gc, *reverse_gc, *cursor_gc; | ||
| 132 | |||
| 133 | /* The window used for this frame. */ | ||
| 134 | Emacs_Window window; | ||
| 135 | |||
| 136 | /* Unused field. */ | ||
| 137 | Emacs_Window parent_desc; | ||
| 138 | |||
| 139 | /* Default ASCII font of this frame. */ | ||
| 140 | struct font *font; | ||
| 141 | |||
| 142 | /* The baseline offset of the default ASCII font. */ | ||
| 143 | int baseline_offset; | ||
| 144 | |||
| 145 | /* If a fontset is specified for this frame instead of font, this | ||
| 146 | value contains an ID of the fontset, else -1. */ | ||
| 147 | int fontset; | ||
| 148 | |||
| 149 | /* Various colors. */ | ||
| 150 | unsigned long cursor_pixel; | ||
| 151 | unsigned long cursor_foreground_pixel; | ||
| 152 | |||
| 153 | /* Foreground color for scroll bars. A value of -1 means use the | ||
| 154 | default (black for non-toolkit scroll bars). */ | ||
| 155 | unsigned long scroll_bar_foreground_pixel; | ||
| 156 | |||
| 157 | /* Background color for scroll bars. A value of -1 means use the | ||
| 158 | default (background color of the frame for non-toolkit scroll | ||
| 159 | bars). */ | ||
| 160 | unsigned long scroll_bar_background_pixel; | ||
| 161 | |||
| 162 | /* Unused stuff (cursors). */ | ||
| 163 | Emacs_Cursor text_cursor; | ||
| 164 | Emacs_Cursor nontext_cursor; | ||
| 165 | Emacs_Cursor modeline_cursor; | ||
| 166 | Emacs_Cursor hand_cursor; | ||
| 167 | Emacs_Cursor hourglass_cursor; | ||
| 168 | Emacs_Cursor horizontal_drag_cursor; | ||
| 169 | Emacs_Cursor vertical_drag_cursor; | ||
| 170 | Emacs_Cursor current_cursor; | ||
| 171 | Emacs_Cursor left_edge_cursor; | ||
| 172 | Emacs_Cursor top_left_corner_cursor; | ||
| 173 | Emacs_Cursor top_edge_cursor; | ||
| 174 | Emacs_Cursor top_right_corner_cursor; | ||
| 175 | Emacs_Cursor right_edge_cursor; | ||
| 176 | Emacs_Cursor bottom_right_corner_cursor; | ||
| 177 | Emacs_Cursor bottom_edge_cursor; | ||
| 178 | Emacs_Cursor bottom_left_corner_cursor; | ||
| 179 | |||
| 180 | /* This is the Emacs structure for the display this frame is on. */ | ||
| 181 | struct android_display_info *display_info; | ||
| 182 | |||
| 183 | /* True if this frame was ever previously visible. */ | ||
| 184 | bool_bf has_been_visible : 1; | ||
| 185 | |||
| 186 | /* True if this frame's alpha value is the same for both the active | ||
| 187 | and inactive states. */ | ||
| 188 | bool_bf alpha_identical_p : 1; | ||
| 189 | |||
| 190 | /* Flag that indicates whether we've modified the back buffer and | ||
| 191 | need to publish our modifications to the front buffer at a | ||
| 192 | convenient time. */ | ||
| 193 | bool_bf need_buffer_flip : 1; | ||
| 194 | |||
| 195 | /* Flag that indicates whether or not the frame contents are | ||
| 196 | complete and can be safely flushed while handling async | ||
| 197 | input. */ | ||
| 198 | bool_bf complete : 1; | ||
| 199 | |||
| 200 | /* Relief GCs, colors etc. */ | ||
| 201 | struct relief { | ||
| 202 | struct android_gc *gc; | ||
| 203 | unsigned long pixel; | ||
| 204 | } black_relief, white_relief; | ||
| 205 | |||
| 206 | /* The background for which the above relief GCs were set up. | ||
| 207 | They are changed only when a different background is involved. */ | ||
| 208 | unsigned long relief_background; | ||
| 209 | }; | ||
| 210 | |||
| 211 | /* Return the Android output data for frame F. */ | ||
| 212 | #define FRAME_ANDROID_OUTPUT(f) ((f)->output_data.android) | ||
| 213 | #define FRAME_OUTPUT_DATA(f) ((f)->output_data.android) | ||
| 214 | |||
| 215 | /* Return the Android window used for displaying data in frame F. */ | ||
| 216 | #define FRAME_ANDROID_WINDOW(f) ((f)->output_data.android->window) | ||
| 217 | #define FRAME_NATIVE_WINDOW(f) ((f)->output_data.android->window) | ||
| 218 | |||
| 219 | /* Return the need-buffer-flip flag for frame F. */ | ||
| 220 | #define FRAME_ANDROID_NEED_BUFFER_FLIP(f) \ | ||
| 221 | ((f)->output_data.android->need_buffer_flip) | ||
| 222 | |||
| 223 | /* Return whether or not the frame F has been completely drawn. Used | ||
| 224 | while handling async input. */ | ||
| 225 | #define FRAME_ANDROID_COMPLETE_P(f) \ | ||
| 226 | ((f)->output_data.android->complete) | ||
| 227 | |||
| 228 | #define FRAME_FONT(f) ((f)->output_data.android->font) | ||
| 229 | #define FRAME_FONTSET(f) ((f)->output_data.android->fontset) | ||
| 230 | |||
| 231 | #define FRAME_BASELINE_OFFSET(f) \ | ||
| 232 | ((f)->output_data.android->baseline_offset) | ||
| 233 | |||
| 234 | /* This gives the android_display_info structure for the display F is | ||
| 235 | on. */ | ||
| 236 | #define FRAME_DISPLAY_INFO(f) ((f)->output_data.android->display_info) | ||
| 237 | |||
| 238 | /* Some things for X compatibility. */ | ||
| 239 | #define BLACK_PIX_DEFAULT(f) 0 | ||
| 240 | #define WHITE_PIX_DEFAULT(f) 0xffffffff | ||
| 241 | |||
| 242 | /* Android-specific scroll bar stuff. */ | ||
| 243 | |||
| 244 | /* We represent scroll bars as lisp vectors. This allows us to place | ||
| 245 | references to them in windows without worrying about whether we'll | ||
| 246 | end up with windows referring to dead scroll bars; the garbage | ||
| 247 | collector will free it when its time comes. | ||
| 248 | |||
| 249 | We use struct scroll_bar as a template for accessing fields of the | ||
| 250 | vector. */ | ||
| 251 | |||
| 252 | struct scroll_bar | ||
| 253 | { | ||
| 254 | /* These fields are shared by all vectors. */ | ||
| 255 | union vectorlike_header header; | ||
| 256 | |||
| 257 | /* The window we're a scroll bar for. */ | ||
| 258 | Lisp_Object window; | ||
| 259 | |||
| 260 | /* The next and previous in the chain of scroll bars in this frame. */ | ||
| 261 | Lisp_Object next, prev; | ||
| 262 | |||
| 263 | /* Fields after 'prev' are not traced by the GC. */ | ||
| 264 | |||
| 265 | /* The X window representing this scroll bar. */ | ||
| 266 | Emacs_Window x_window; | ||
| 267 | |||
| 268 | /* The position and size of the scroll bar in pixels, relative to the | ||
| 269 | frame. */ | ||
| 270 | int top, left, width, height; | ||
| 271 | |||
| 272 | /* The starting and ending positions of the handle, relative to the | ||
| 273 | handle area (i.e. zero is the top position, not | ||
| 274 | SCROLL_BAR_TOP_BORDER). If they're equal, that means the handle | ||
| 275 | hasn't been drawn yet. | ||
| 276 | |||
| 277 | These are not actually the locations where the beginning and end | ||
| 278 | are drawn; in order to keep handles from becoming invisible when | ||
| 279 | editing large files, we establish a minimum height by always | ||
| 280 | drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below | ||
| 281 | where they would be normally; the bottom and top are in a | ||
| 282 | different coordinate system. */ | ||
| 283 | int start, end; | ||
| 284 | |||
| 285 | /* If the scroll bar handle is currently being dragged by the user, | ||
| 286 | this is the number of pixels from the top of the handle to the | ||
| 287 | place where the user grabbed it. If the handle isn't currently | ||
| 288 | being dragged, this is -1. */ | ||
| 289 | int dragging; | ||
| 290 | |||
| 291 | /* True if the scroll bar is horizontal. */ | ||
| 292 | bool horizontal; | ||
| 293 | }; | ||
| 294 | |||
| 295 | /* Turning a lisp vector value into a pointer to a struct scroll_bar. */ | ||
| 296 | #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec)) | ||
| 297 | |||
| 298 | |||
| 299 | |||
| 300 | /* This is a chain of structures for all the Android displays | ||
| 301 | currently in use. There is only ever one, but the rest of Emacs is | ||
| 302 | written with systems on which there can be many in mind. */ | ||
| 303 | extern struct android_display_info *x_display_list; | ||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | /* Start of function definitions. These should be a neat subset of | ||
| 308 | the same ones in xterm.h, and come in the same order. */ | ||
| 309 | |||
| 310 | /* From androidfns.c. */ | ||
| 311 | |||
| 312 | extern void android_free_gcs (struct frame *); | ||
| 313 | extern void android_default_font_parameter (struct frame *, Lisp_Object); | ||
| 314 | |||
| 315 | /* Defined in androidterm.c. */ | ||
| 316 | |||
| 317 | extern void android_term_init (void); | ||
| 318 | extern void android_set_window_size (struct frame *, bool, int, int); | ||
| 319 | extern void android_iconify_frame (struct frame *); | ||
| 320 | extern void android_make_frame_visible (struct frame *); | ||
| 321 | extern void android_make_frame_invisible (struct frame *); | ||
| 322 | extern void android_free_frame_resources (struct frame *); | ||
| 323 | |||
| 324 | extern int android_parse_color (struct frame *, const char *, | ||
| 325 | Emacs_Color *); | ||
| 326 | extern bool android_alloc_nearest_color (struct frame *, Emacs_Color *); | ||
| 327 | extern void android_query_colors (struct frame *, Emacs_Color *, int); | ||
| 328 | extern void android_clear_under_internal_border (struct frame *); | ||
| 329 | |||
| 330 | extern void syms_of_androidterm (void); | ||
| 331 | extern void mark_androidterm (void); | ||
| 332 | |||
| 333 | /* Defined in androidfns.c. */ | ||
| 334 | |||
| 335 | extern void android_change_tab_bar_height (struct frame *, int); | ||
| 336 | extern void android_change_tool_bar_height (struct frame *, int); | ||
| 337 | extern void android_set_scroll_bar_default_width (struct frame *); | ||
| 338 | extern void android_set_scroll_bar_default_height (struct frame *); | ||
| 339 | extern bool android_defined_color (struct frame *, const char *, | ||
| 340 | Emacs_Color *, bool, bool); | ||
| 341 | extern void android_implicitly_set_name (struct frame *, Lisp_Object, | ||
| 342 | Lisp_Object); | ||
| 343 | extern void android_explicitly_set_name (struct frame *, Lisp_Object, | ||
| 344 | Lisp_Object); | ||
| 345 | |||
| 346 | extern void syms_of_androidfns (void); | ||
| 347 | |||
| 348 | /* Defined in androidfont.c. */ | ||
| 349 | |||
| 350 | extern struct font_driver androidfont_driver; | ||
| 351 | |||
| 352 | extern void init_androidfont (void); | ||
| 353 | extern void syms_of_androidfont (void); | ||
| 354 | |||
| 355 | extern void android_finalize_font_entity (struct font_entity *); | ||
| 356 | |||
| 357 | |||
| 358 | |||
| 359 | #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) | ||
| 360 | #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) | ||
| 361 | #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) | ||
| 362 | #define BLUE_FROM_ULONG(color) ((color) & 0xff) | ||
| 363 | |||
| 364 | |||
| 365 | |||
| 366 | #endif /* _ANDROID_TERM_H_ */ | ||
diff --git a/src/dired.c b/src/dired.c index ef729df5d2b..e7d4c75092a 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -979,14 +979,15 @@ file_attributes (int fd, char const *name, | |||
| 979 | 979 | ||
| 980 | int err = EINVAL; | 980 | int err = EINVAL; |
| 981 | 981 | ||
| 982 | #if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG | 982 | #if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG \ |
| 983 | && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 983 | int namefd = emacs_openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW, 0); | 984 | int namefd = emacs_openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW, 0); |
| 984 | if (namefd < 0) | 985 | if (namefd < 0) |
| 985 | err = errno; | 986 | err = errno; |
| 986 | else | 987 | else |
| 987 | { | 988 | { |
| 988 | record_unwind_protect_int (close_file_unwind, namefd); | 989 | record_unwind_protect_int (close_file_unwind, namefd); |
| 989 | if (fstat (namefd, &s) != 0) | 990 | if (sys_fstat (namefd, &s) != 0) |
| 990 | { | 991 | { |
| 991 | err = errno; | 992 | err = errno; |
| 992 | /* The Linux kernel before version 3.6 does not support | 993 | /* The Linux kernel before version 3.6 does not support |
diff --git a/src/dispextern.h b/src/dispextern.h index e6c4270bebd..e521dffc37c 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -53,8 +53,15 @@ typedef struct | |||
| 53 | unsigned short red, green, blue; | 53 | unsigned short red, green, blue; |
| 54 | } Emacs_Color; | 54 | } Emacs_Color; |
| 55 | 55 | ||
| 56 | #ifndef HAVE_ANDROID | ||
| 56 | /* Accommodate X's usage of None as a null resource ID. */ | 57 | /* Accommodate X's usage of None as a null resource ID. */ |
| 57 | #define No_Cursor (NULL) | 58 | #define No_Cursor (NULL) |
| 59 | #else | ||
| 60 | /* Android doesn't support cursors and also uses handles. */ | ||
| 61 | #define No_Cursor 0 | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifndef HAVE_ANDROID | ||
| 58 | 65 | ||
| 59 | /* XRectangle-like struct used by non-X GUI code. */ | 66 | /* XRectangle-like struct used by non-X GUI code. */ |
| 60 | typedef struct | 67 | typedef struct |
| @@ -63,6 +70,12 @@ typedef struct | |||
| 63 | unsigned width, height; | 70 | unsigned width, height; |
| 64 | } Emacs_Rectangle; | 71 | } Emacs_Rectangle; |
| 65 | 72 | ||
| 73 | #else | ||
| 74 | |||
| 75 | typedef struct android_rectangle Emacs_Rectangle; | ||
| 76 | |||
| 77 | #endif | ||
| 78 | |||
| 66 | /* XGCValues-like struct used by non-X GUI code. */ | 79 | /* XGCValues-like struct used by non-X GUI code. */ |
| 67 | typedef struct | 80 | typedef struct |
| 68 | { | 81 | { |
| @@ -144,6 +157,13 @@ typedef Emacs_Pixmap Emacs_Pix_Container; | |||
| 144 | typedef Emacs_Pixmap Emacs_Pix_Context; | 157 | typedef Emacs_Pixmap Emacs_Pix_Context; |
| 145 | #endif | 158 | #endif |
| 146 | 159 | ||
| 160 | #ifdef HAVE_ANDROID | ||
| 161 | #include "androidgui.h" | ||
| 162 | typedef struct android_display_info Display_Info; | ||
| 163 | typedef Emacs_Pixmap Emacs_Pix_Container; | ||
| 164 | typedef Emacs_Pixmap Emacs_Pix_Context; | ||
| 165 | #endif | ||
| 166 | |||
| 147 | #ifdef HAVE_WINDOW_SYSTEM | 167 | #ifdef HAVE_WINDOW_SYSTEM |
| 148 | # include <time.h> | 168 | # include <time.h> |
| 149 | # include "fontset.h" | 169 | # include "fontset.h" |
| @@ -1401,6 +1421,8 @@ struct glyph_string | |||
| 1401 | /* The GC to use for drawing this glyph string. */ | 1421 | /* The GC to use for drawing this glyph string. */ |
| 1402 | #if defined (HAVE_X_WINDOWS) | 1422 | #if defined (HAVE_X_WINDOWS) |
| 1403 | GC gc; | 1423 | GC gc; |
| 1424 | #elif defined HAVE_ANDROID | ||
| 1425 | struct android_gc *gc; | ||
| 1404 | #endif | 1426 | #endif |
| 1405 | #if defined (HAVE_NTGUI) | 1427 | #if defined (HAVE_NTGUI) |
| 1406 | Emacs_GC *gc; | 1428 | Emacs_GC *gc; |
| @@ -1681,6 +1703,8 @@ struct face | |||
| 1681 | drawing the characters in this face. */ | 1703 | drawing the characters in this face. */ |
| 1682 | # ifdef HAVE_X_WINDOWS | 1704 | # ifdef HAVE_X_WINDOWS |
| 1683 | GC gc; | 1705 | GC gc; |
| 1706 | # elif defined HAVE_ANDROID | ||
| 1707 | struct android_gc *gc; | ||
| 1684 | # else | 1708 | # else |
| 1685 | Emacs_GC *gc; | 1709 | Emacs_GC *gc; |
| 1686 | # endif | 1710 | # endif |
| @@ -3502,9 +3526,11 @@ extern void gui_clear_window_mouse_face (struct window *); | |||
| 3502 | extern void cancel_mouse_face (struct frame *); | 3526 | extern void cancel_mouse_face (struct frame *); |
| 3503 | extern bool clear_mouse_face (Mouse_HLInfo *); | 3527 | extern bool clear_mouse_face (Mouse_HLInfo *); |
| 3504 | extern bool cursor_in_mouse_face_p (struct window *w); | 3528 | extern bool cursor_in_mouse_face_p (struct window *w); |
| 3529 | #ifndef HAVE_ANDROID | ||
| 3505 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, | 3530 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, |
| 3506 | int, int, enum draw_glyphs_face); | 3531 | int, int, enum draw_glyphs_face); |
| 3507 | extern void display_tty_menu_item (const char *, int, int, int, int, bool); | 3532 | extern void display_tty_menu_item (const char *, int, int, int, int, bool); |
| 3533 | #endif | ||
| 3508 | extern struct glyph *x_y_to_hpos_vpos (struct window *, int, int, int *, int *, | 3534 | extern struct glyph *x_y_to_hpos_vpos (struct window *, int, int, int *, int *, |
| 3509 | int *, int *, int *); | 3535 | int *, int *, int *); |
| 3510 | /* Flags passed to try_window. */ | 3536 | /* Flags passed to try_window. */ |
| @@ -3566,7 +3592,7 @@ void prepare_image_for_display (struct frame *, struct image *); | |||
| 3566 | ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); | 3592 | ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); |
| 3567 | 3593 | ||
| 3568 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \ | 3594 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \ |
| 3569 | || defined HAVE_HAIKU | 3595 | || defined HAVE_HAIKU || defined HAVE_ANDROID |
| 3570 | #define RGB_PIXEL_COLOR unsigned long | 3596 | #define RGB_PIXEL_COLOR unsigned long |
| 3571 | #endif | 3597 | #endif |
| 3572 | 3598 | ||
| @@ -3647,6 +3673,9 @@ void gamma_correct (struct frame *, COLORREF *); | |||
| 3647 | #ifdef HAVE_HAIKU | 3673 | #ifdef HAVE_HAIKU |
| 3648 | void gamma_correct (struct frame *, Emacs_Color *); | 3674 | void gamma_correct (struct frame *, Emacs_Color *); |
| 3649 | #endif | 3675 | #endif |
| 3676 | #ifdef HAVE_ANDROID | ||
| 3677 | extern void gamma_correct (struct frame *, Emacs_Color *); | ||
| 3678 | #endif | ||
| 3650 | 3679 | ||
| 3651 | #ifdef HAVE_WINDOW_SYSTEM | 3680 | #ifdef HAVE_WINDOW_SYSTEM |
| 3652 | 3681 | ||
diff --git a/src/dispnew.c b/src/dispnew.c index 5a9ba8909e3..ed10accac7b 100644 --- a/src/dispnew.c +++ b/src/dispnew.c | |||
| @@ -43,6 +43,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 43 | #include "xwidget.h" | 43 | #include "xwidget.h" |
| 44 | #include "pdumper.h" | 44 | #include "pdumper.h" |
| 45 | 45 | ||
| 46 | #ifdef HAVE_ANDROID | ||
| 47 | #include "android.h" | ||
| 48 | #endif | ||
| 49 | |||
| 46 | #ifdef HAVE_WINDOW_SYSTEM | 50 | #ifdef HAVE_WINDOW_SYSTEM |
| 47 | #include TERM_HEADER | 51 | #include TERM_HEADER |
| 48 | #endif /* HAVE_WINDOW_SYSTEM */ | 52 | #endif /* HAVE_WINDOW_SYSTEM */ |
| @@ -788,7 +792,7 @@ clear_current_matrices (register struct frame *f) | |||
| 788 | if (f->current_matrix) | 792 | if (f->current_matrix) |
| 789 | clear_glyph_matrix (f->current_matrix); | 793 | clear_glyph_matrix (f->current_matrix); |
| 790 | 794 | ||
| 791 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 795 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 792 | /* Clear the matrix of the menu bar window, if such a window exists. | 796 | /* Clear the matrix of the menu bar window, if such a window exists. |
| 793 | The menu bar window is currently used to display menus on X when | 797 | The menu bar window is currently used to display menus on X when |
| 794 | no toolkit support is compiled in. */ | 798 | no toolkit support is compiled in. */ |
| @@ -822,7 +826,7 @@ clear_desired_matrices (register struct frame *f) | |||
| 822 | if (f->desired_matrix) | 826 | if (f->desired_matrix) |
| 823 | clear_glyph_matrix (f->desired_matrix); | 827 | clear_glyph_matrix (f->desired_matrix); |
| 824 | 828 | ||
| 825 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 829 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 826 | if (WINDOWP (f->menu_bar_window)) | 830 | if (WINDOWP (f->menu_bar_window)) |
| 827 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); | 831 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); |
| 828 | #endif | 832 | #endif |
| @@ -1156,6 +1160,7 @@ prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p) | |||
| 1156 | } | 1160 | } |
| 1157 | } | 1161 | } |
| 1158 | 1162 | ||
| 1163 | #ifndef HAVE_ANDROID | ||
| 1159 | 1164 | ||
| 1160 | /* Return a hash code for glyph row ROW, which may | 1165 | /* Return a hash code for glyph row ROW, which may |
| 1161 | be from current or desired matrix of frame F. */ | 1166 | be from current or desired matrix of frame F. */ |
| @@ -1248,6 +1253,7 @@ line_draw_cost (struct frame *f, struct glyph_matrix *matrix, int vpos) | |||
| 1248 | return len; | 1253 | return len; |
| 1249 | } | 1254 | } |
| 1250 | 1255 | ||
| 1256 | #endif | ||
| 1251 | 1257 | ||
| 1252 | /* Return true if the glyph rows A and B have equal contents. | 1258 | /* Return true if the glyph rows A and B have equal contents. |
| 1253 | MOUSE_FACE_P means compare the mouse_face_p flags of A and B, too. */ | 1259 | MOUSE_FACE_P means compare the mouse_face_p flags of A and B, too. */ |
| @@ -2160,7 +2166,7 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f) | |||
| 2160 | /* Allocate/reallocate window matrices. */ | 2166 | /* Allocate/reallocate window matrices. */ |
| 2161 | allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f))); | 2167 | allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f))); |
| 2162 | 2168 | ||
| 2163 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 2169 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 2164 | /* Allocate/ reallocate matrices of the dummy window used to display | 2170 | /* Allocate/ reallocate matrices of the dummy window used to display |
| 2165 | the menu bar under X when no X toolkit support is available. */ | 2171 | the menu bar under X when no X toolkit support is available. */ |
| 2166 | { | 2172 | { |
| @@ -2296,7 +2302,7 @@ free_glyphs (struct frame *f) | |||
| 2296 | if (!NILP (f->root_window)) | 2302 | if (!NILP (f->root_window)) |
| 2297 | free_window_matrices (XWINDOW (f->root_window)); | 2303 | free_window_matrices (XWINDOW (f->root_window)); |
| 2298 | 2304 | ||
| 2299 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 2305 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 2300 | /* Free the dummy window for menu bars without X toolkit and its | 2306 | /* Free the dummy window for menu bars without X toolkit and its |
| 2301 | glyph matrices. */ | 2307 | glyph matrices. */ |
| 2302 | if (!NILP (f->menu_bar_window)) | 2308 | if (!NILP (f->menu_bar_window)) |
| @@ -3234,7 +3240,7 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) | |||
| 3234 | when pending input is detected. */ | 3240 | when pending input is detected. */ |
| 3235 | update_begin (f); | 3241 | update_begin (f); |
| 3236 | 3242 | ||
| 3237 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 3243 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 3238 | /* Update the menu bar on X frames that don't have toolkit | 3244 | /* Update the menu bar on X frames that don't have toolkit |
| 3239 | support. */ | 3245 | support. */ |
| 3240 | if (WINDOWP (f->menu_bar_window)) | 3246 | if (WINDOWP (f->menu_bar_window)) |
| @@ -5059,6 +5065,10 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, | |||
| 5059 | static bool | 5065 | static bool |
| 5060 | scrolling (struct frame *frame) | 5066 | scrolling (struct frame *frame) |
| 5061 | { | 5067 | { |
| 5068 | /* In fact this code should never be reached at all under | ||
| 5069 | Android. */ | ||
| 5070 | |||
| 5071 | #ifndef HAVE_ANDROID | ||
| 5062 | int unchanged_at_top, unchanged_at_bottom; | 5072 | int unchanged_at_top, unchanged_at_bottom; |
| 5063 | int window_size; | 5073 | int window_size; |
| 5064 | int changed_lines; | 5074 | int changed_lines; |
| @@ -5149,6 +5159,7 @@ scrolling (struct frame *frame) | |||
| 5149 | free_at_end_vpos - unchanged_at_top); | 5159 | free_at_end_vpos - unchanged_at_top); |
| 5150 | 5160 | ||
| 5151 | SAFE_FREE (); | 5161 | SAFE_FREE (); |
| 5162 | #endif | ||
| 5152 | return false; | 5163 | return false; |
| 5153 | } | 5164 | } |
| 5154 | 5165 | ||
| @@ -5190,7 +5201,9 @@ count_match (struct glyph *str1, struct glyph *end1, struct glyph *str2, struct | |||
| 5190 | 5201 | ||
| 5191 | /* Char insertion/deletion cost vector, from term.c */ | 5202 | /* Char insertion/deletion cost vector, from term.c */ |
| 5192 | 5203 | ||
| 5204 | #ifndef HAVE_ANDROID | ||
| 5193 | #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS ((f))]) | 5205 | #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS ((f))]) |
| 5206 | #endif | ||
| 5194 | 5207 | ||
| 5195 | 5208 | ||
| 5196 | /* Perform a frame-based update on line VPOS in frame FRAME. */ | 5209 | /* Perform a frame-based update on line VPOS in frame FRAME. */ |
| @@ -5395,7 +5408,10 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) | |||
| 5395 | tem = (nlen - nsp) - (olen - osp); | 5408 | tem = (nlen - nsp) - (olen - osp); |
| 5396 | if (endmatch && tem | 5409 | if (endmatch && tem |
| 5397 | && (!FRAME_CHAR_INS_DEL_OK (f) | 5410 | && (!FRAME_CHAR_INS_DEL_OK (f) |
| 5398 | || endmatch <= char_ins_del_cost (f)[tem])) | 5411 | #ifndef HAVE_ANDROID |
| 5412 | || endmatch <= char_ins_del_cost (f)[tem] | ||
| 5413 | #endif | ||
| 5414 | )) | ||
| 5399 | endmatch = 0; | 5415 | endmatch = 0; |
| 5400 | 5416 | ||
| 5401 | /* nsp - osp is the distance to insert or delete. | 5417 | /* nsp - osp is the distance to insert or delete. |
| @@ -5405,7 +5421,10 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) | |||
| 5405 | 5421 | ||
| 5406 | if (nsp != osp | 5422 | if (nsp != osp |
| 5407 | && (!FRAME_CHAR_INS_DEL_OK (f) | 5423 | && (!FRAME_CHAR_INS_DEL_OK (f) |
| 5408 | || begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp])) | 5424 | #ifndef HAVE_ANDROID |
| 5425 | || begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp] | ||
| 5426 | #endif | ||
| 5427 | )) | ||
| 5409 | { | 5428 | { |
| 5410 | begmatch = 0; | 5429 | begmatch = 0; |
| 5411 | endmatch = 0; | 5430 | endmatch = 0; |
| @@ -6528,6 +6547,15 @@ init_display_interactive (void) | |||
| 6528 | } | 6547 | } |
| 6529 | #endif /* HAVE_X_WINDOWS */ | 6548 | #endif /* HAVE_X_WINDOWS */ |
| 6530 | 6549 | ||
| 6550 | #ifdef HAVE_ANDROID | ||
| 6551 | if (!inhibit_window_system && android_init_gui) | ||
| 6552 | { | ||
| 6553 | Vinitial_window_system = Qandroid; | ||
| 6554 | android_term_init (); | ||
| 6555 | return; | ||
| 6556 | } | ||
| 6557 | #endif | ||
| 6558 | |||
| 6531 | #ifdef HAVE_NTGUI | 6559 | #ifdef HAVE_NTGUI |
| 6532 | if (!inhibit_window_system) | 6560 | if (!inhibit_window_system) |
| 6533 | { | 6561 | { |
| @@ -6582,6 +6610,7 @@ init_display_interactive (void) | |||
| 6582 | exit (1); | 6610 | exit (1); |
| 6583 | } | 6611 | } |
| 6584 | 6612 | ||
| 6613 | #ifndef HAVE_ANDROID | ||
| 6585 | { | 6614 | { |
| 6586 | struct terminal *t; | 6615 | struct terminal *t; |
| 6587 | struct frame *f = XFRAME (selected_frame); | 6616 | struct frame *f = XFRAME (selected_frame); |
| @@ -6624,6 +6653,11 @@ init_display_interactive (void) | |||
| 6624 | : Qnil)); | 6653 | : Qnil)); |
| 6625 | Fmodify_frame_parameters (selected_frame, tty_arg); | 6654 | Fmodify_frame_parameters (selected_frame, tty_arg); |
| 6626 | } | 6655 | } |
| 6656 | #else | ||
| 6657 | fatal ("Could not establish a connection to the Android application.\n" | ||
| 6658 | "Emacs does not work on text terminals when built to run as" | ||
| 6659 | " part of an Android application package."); | ||
| 6660 | #endif | ||
| 6627 | 6661 | ||
| 6628 | { | 6662 | { |
| 6629 | struct frame *sf = SELECTED_FRAME (); | 6663 | struct frame *sf = SELECTED_FRAME (); |
diff --git a/src/editfns.c b/src/editfns.c index 8d56ef21d90..f061199705f 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -33,6 +33,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include <sys/utsname.h> | 33 | #include <sys/utsname.h> |
| 34 | #endif | 34 | #endif |
| 35 | 35 | ||
| 36 | #ifdef HAVE_ANDROID | ||
| 37 | #include "android.h" | ||
| 38 | #endif | ||
| 39 | |||
| 36 | #include "lisp.h" | 40 | #include "lisp.h" |
| 37 | 41 | ||
| 38 | #include <float.h> | 42 | #include <float.h> |
| @@ -1264,7 +1268,11 @@ is in general a comma-separated list. */) | |||
| 1264 | if (!pw) | 1268 | if (!pw) |
| 1265 | return Qnil; | 1269 | return Qnil; |
| 1266 | 1270 | ||
| 1271 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 1272 | p = android_user_full_name (pw); | ||
| 1273 | #else | ||
| 1267 | p = USER_FULL_NAME; | 1274 | p = USER_FULL_NAME; |
| 1275 | #endif | ||
| 1268 | /* Chop off everything after the first comma, since 'pw_gecos' is a | 1276 | /* Chop off everything after the first comma, since 'pw_gecos' is a |
| 1269 | comma-separated list. */ | 1277 | comma-separated list. */ |
| 1270 | q = strchr (p, ','); | 1278 | q = strchr (p, ','); |
diff --git a/src/emacs.c b/src/emacs.c index d8a2863fd9c..b6686f88096 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -33,6 +33,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include "lisp.h" | 33 | #include "lisp.h" |
| 34 | #include "sysstdio.h" | 34 | #include "sysstdio.h" |
| 35 | 35 | ||
| 36 | #ifdef HAVE_ANDROID | ||
| 37 | #include "androidterm.h" | ||
| 38 | #endif | ||
| 39 | |||
| 36 | #ifdef WINDOWSNT | 40 | #ifdef WINDOWSNT |
| 37 | #include <fcntl.h> | 41 | #include <fcntl.h> |
| 38 | #include <sys/socket.h> | 42 | #include <sys/socket.h> |
| @@ -137,6 +141,10 @@ extern char etext; | |||
| 137 | #include <sys/resource.h> | 141 | #include <sys/resource.h> |
| 138 | #endif | 142 | #endif |
| 139 | 143 | ||
| 144 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 145 | #include "android.h" | ||
| 146 | #endif | ||
| 147 | |||
| 140 | /* We don't guard this with HAVE_TREE_SITTER because treesit.o is | 148 | /* We don't guard this with HAVE_TREE_SITTER because treesit.o is |
| 141 | always compiled (to provide treesit-available-p). */ | 149 | always compiled (to provide treesit-available-p). */ |
| 142 | #include "treesit.h" | 150 | #include "treesit.h" |
| @@ -1123,7 +1131,7 @@ load_seccomp (const char *file) | |||
| 1123 | goto out; | 1131 | goto out; |
| 1124 | } | 1132 | } |
| 1125 | struct stat stat; | 1133 | struct stat stat; |
| 1126 | if (fstat (fd, &stat) != 0) | 1134 | if (sys_fstat (fd, &stat) != 0) |
| 1127 | { | 1135 | { |
| 1128 | emacs_perror ("fstat"); | 1136 | emacs_perror ("fstat"); |
| 1129 | goto out; | 1137 | goto out; |
| @@ -1225,12 +1233,18 @@ maybe_load_seccomp (int argc, char **argv) | |||
| 1225 | 1233 | ||
| 1226 | #endif /* SECCOMP_USABLE */ | 1234 | #endif /* SECCOMP_USABLE */ |
| 1227 | 1235 | ||
| 1236 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 1237 | int | ||
| 1238 | android_emacs_init (int argc, char **argv) | ||
| 1239 | #else | ||
| 1228 | int | 1240 | int |
| 1229 | main (int argc, char **argv) | 1241 | main (int argc, char **argv) |
| 1242 | #endif | ||
| 1230 | { | 1243 | { |
| 1231 | /* Variable near the bottom of the stack, and aligned appropriately | 1244 | /* Variable near the bottom of the stack, and aligned appropriately |
| 1232 | for pointers. */ | 1245 | for pointers. */ |
| 1233 | void *stack_bottom_variable; | 1246 | void *stack_bottom_variable; |
| 1247 | int old_argc; | ||
| 1234 | 1248 | ||
| 1235 | /* First, check whether we should apply a seccomp filter. This | 1249 | /* First, check whether we should apply a seccomp filter. This |
| 1236 | should come at the very beginning to allow the filter to protect | 1250 | should come at the very beginning to allow the filter to protect |
| @@ -1425,8 +1439,10 @@ main (int argc, char **argv) | |||
| 1425 | 1439 | ||
| 1426 | bool only_version = false; | 1440 | bool only_version = false; |
| 1427 | sort_args (argc, argv); | 1441 | sort_args (argc, argv); |
| 1428 | argc = 0; | 1442 | old_argc = argc, argc = 0; |
| 1429 | while (argv[argc]) argc++; | 1443 | while (argv[argc] |
| 1444 | /* Don't allow going past argv. */ | ||
| 1445 | && argc < old_argc) argc++; | ||
| 1430 | 1446 | ||
| 1431 | skip_args = 0; | 1447 | skip_args = 0; |
| 1432 | if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args)) | 1448 | if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args)) |
| @@ -2375,6 +2391,14 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2375 | #endif | 2391 | #endif |
| 2376 | syms_of_fontset (); | 2392 | syms_of_fontset (); |
| 2377 | #endif /* HAVE_HAIKU */ | 2393 | #endif /* HAVE_HAIKU */ |
| 2394 | #ifdef HAVE_ANDROID | ||
| 2395 | syms_of_androidterm (); | ||
| 2396 | syms_of_androidfns (); | ||
| 2397 | syms_of_fontset (); | ||
| 2398 | #if !defined ANDROID_STUBIFY | ||
| 2399 | syms_of_androidfont (); | ||
| 2400 | #endif /* !ANDROID_STUBIFY */ | ||
| 2401 | #endif /* HAVE_ANDROID */ | ||
| 2378 | 2402 | ||
| 2379 | syms_of_gnutls (); | 2403 | syms_of_gnutls (); |
| 2380 | 2404 | ||
| @@ -2436,6 +2460,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2436 | init_haiku_select (); | 2460 | init_haiku_select (); |
| 2437 | #endif | 2461 | #endif |
| 2438 | 2462 | ||
| 2463 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2464 | init_androidfont (); | ||
| 2465 | #endif | ||
| 2466 | |||
| 2439 | init_charset (); | 2467 | init_charset (); |
| 2440 | 2468 | ||
| 2441 | /* This calls putenv and so must precede init_process_emacs. */ | 2469 | /* This calls putenv and so must precede init_process_emacs. */ |
| @@ -2950,7 +2978,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) | |||
| 2950 | Vinhibit_redisplay = Qt; | 2978 | Vinhibit_redisplay = Qt; |
| 2951 | 2979 | ||
| 2952 | /* If we are controlling the terminal, reset terminal modes. */ | 2980 | /* If we are controlling the terminal, reset terminal modes. */ |
| 2953 | #ifndef DOS_NT | 2981 | #if !defined DOS_NT && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2954 | pid_t tpgrp = tcgetpgrp (STDIN_FILENO); | 2982 | pid_t tpgrp = tcgetpgrp (STDIN_FILENO); |
| 2955 | if (tpgrp != -1 && tpgrp == getpgrp ()) | 2983 | if (tpgrp != -1 && tpgrp == getpgrp ()) |
| 2956 | { | 2984 | { |
| @@ -3469,6 +3497,7 @@ Special values: | |||
| 3469 | `windows-nt' compiled as a native W32 application. | 3497 | `windows-nt' compiled as a native W32 application. |
| 3470 | `cygwin' compiled using the Cygwin library. | 3498 | `cygwin' compiled using the Cygwin library. |
| 3471 | `haiku' compiled for a Haiku system. | 3499 | `haiku' compiled for a Haiku system. |
| 3500 | `android' compiled for Android. | ||
| 3472 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, | 3501 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, |
| 3473 | hpux, usg-unix-v) indicates some sort of Unix system. */); | 3502 | hpux, usg-unix-v) indicates some sort of Unix system. */); |
| 3474 | Vsystem_type = intern_c_string (SYSTEM_TYPE); | 3503 | Vsystem_type = intern_c_string (SYSTEM_TYPE); |
diff --git a/src/epaths.in b/src/epaths.in index 2eccd0ac603..7ab1b4b3d86 100644 --- a/src/epaths.in +++ b/src/epaths.in | |||
| @@ -18,6 +18,7 @@ GNU General Public License for more details. | |||
| 18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
| 19 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | 19 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ |
| 20 | 20 | ||
| 21 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 21 | 22 | ||
| 22 | /* Together with PATH_SITELOADSEARCH, this gives the default value of | 23 | /* Together with PATH_SITELOADSEARCH, this gives the default value of |
| 23 | load-path, which is the search path for the Lisp function "load". | 24 | load-path, which is the search path for the Lisp function "load". |
| @@ -79,3 +80,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 79 | 80 | ||
| 80 | /* Where Emacs should look for the application default file. */ | 81 | /* Where Emacs should look for the application default file. */ |
| 81 | #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" | 82 | #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" |
| 83 | |||
| 84 | #else | ||
| 85 | |||
| 86 | /* Replace the defines above with links to files in the assets | ||
| 87 | pseudo-directory. Preserve the extra spaces, or epaths.in will not | ||
| 88 | be generated correctly. */ | ||
| 89 | |||
| 90 | # define PATH_EXEC (android_lib_dir) | ||
| 91 | # define PATH_LOADSEARCH "/assets/lisp/" | ||
| 92 | # define PATH_SITELOADSEARCH (android_site_load_path) | ||
| 93 | # define PATH_DUMPLOADSEARCH "/assets/lisp/" | ||
| 94 | # define PATH_DATA "/assets/etc/" | ||
| 95 | # define PATH_DOC "/assets/etc/" | ||
| 96 | # define PATH_INFO "/assets/info/" | ||
| 97 | # define PATH_GAME "" | ||
| 98 | # define PATH_BITMAPS "" | ||
| 99 | |||
| 100 | extern char *android_site_load_path; | ||
| 101 | extern char *android_lib_dir; | ||
| 102 | |||
| 103 | #endif | ||
diff --git a/src/fileio.c b/src/fileio.c index 66ce6b30887..1d22c51ebaa 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -56,6 +56,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 56 | #include "region-cache.h" | 56 | #include "region-cache.h" |
| 57 | #include "frame.h" | 57 | #include "frame.h" |
| 58 | 58 | ||
| 59 | #if defined HAVE_ANDROID | ||
| 60 | #include "android.h" | ||
| 61 | #endif | ||
| 62 | |||
| 59 | #ifdef HAVE_LINUX_FS_H | 63 | #ifdef HAVE_LINUX_FS_H |
| 60 | # include <sys/ioctl.h> | 64 | # include <sys/ioctl.h> |
| 61 | # include <linux/fs.h> | 65 | # include <linux/fs.h> |
| @@ -135,7 +139,6 @@ static dev_t timestamp_file_system; | |||
| 135 | static Lisp_Object Vwrite_region_annotation_buffers; | 139 | static Lisp_Object Vwrite_region_annotation_buffers; |
| 136 | 140 | ||
| 137 | static Lisp_Object emacs_readlinkat (int, char const *); | 141 | static Lisp_Object emacs_readlinkat (int, char const *); |
| 138 | static Lisp_Object file_name_directory (Lisp_Object); | ||
| 139 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 142 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| 140 | Lisp_Object *, struct coding_system *); | 143 | Lisp_Object *, struct coding_system *); |
| 141 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 144 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| @@ -160,6 +163,12 @@ file_access_p (char const *file, int amode) | |||
| 160 | } | 163 | } |
| 161 | #endif | 164 | #endif |
| 162 | 165 | ||
| 166 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 167 | /* FILE may be some kind of special Android file. */ | ||
| 168 | if (android_file_access_p (file, amode)) | ||
| 169 | return true; | ||
| 170 | #endif | ||
| 171 | |||
| 163 | if (faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) | 172 | if (faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) |
| 164 | return true; | 173 | return true; |
| 165 | 174 | ||
| @@ -370,7 +379,7 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 370 | /* Return the directory component of FILENAME, or nil if FILENAME does | 379 | /* Return the directory component of FILENAME, or nil if FILENAME does |
| 371 | not contain a directory component. */ | 380 | not contain a directory component. */ |
| 372 | 381 | ||
| 373 | static Lisp_Object | 382 | Lisp_Object |
| 374 | file_name_directory (Lisp_Object filename) | 383 | file_name_directory (Lisp_Object filename) |
| 375 | { | 384 | { |
| 376 | char *beg = SSDATA (filename); | 385 | char *beg = SSDATA (filename); |
| @@ -2227,7 +2236,7 @@ permissions. */) | |||
| 2227 | 2236 | ||
| 2228 | record_unwind_protect_int (close_file_unwind, ifd); | 2237 | record_unwind_protect_int (close_file_unwind, ifd); |
| 2229 | 2238 | ||
| 2230 | if (fstat (ifd, &st) != 0) | 2239 | if (sys_fstat (ifd, &st) != 0) |
| 2231 | report_file_error ("Input file status", file); | 2240 | report_file_error ("Input file status", file); |
| 2232 | 2241 | ||
| 2233 | if (!NILP (preserve_permissions)) | 2242 | if (!NILP (preserve_permissions)) |
| @@ -2273,7 +2282,7 @@ permissions. */) | |||
| 2273 | if (already_exists) | 2282 | if (already_exists) |
| 2274 | { | 2283 | { |
| 2275 | struct stat out_st; | 2284 | struct stat out_st; |
| 2276 | if (fstat (ofd, &out_st) != 0) | 2285 | if (sys_fstat (ofd, &out_st) != 0) |
| 2277 | report_file_error ("Output file status", newname); | 2286 | report_file_error ("Output file status", newname); |
| 2278 | if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) | 2287 | if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) |
| 2279 | report_file_errno ("Input and output files are the same", | 2288 | report_file_errno ("Input and output files are the same", |
| @@ -3078,7 +3087,7 @@ file_directory_p (Lisp_Object file) | |||
| 3078 | errno = ENOTDIR; /* like the non-DOS_NT branch below does */ | 3087 | errno = ENOTDIR; /* like the non-DOS_NT branch below does */ |
| 3079 | return retval; | 3088 | return retval; |
| 3080 | #else | 3089 | #else |
| 3081 | # ifdef O_PATH | 3090 | # if defined O_PATH && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 3082 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ | 3091 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ |
| 3083 | int fd = emacs_openat (AT_FDCWD, SSDATA (file), | 3092 | int fd = emacs_openat (AT_FDCWD, SSDATA (file), |
| 3084 | O_PATH | O_CLOEXEC | O_DIRECTORY, 0); | 3093 | O_PATH | O_CLOEXEC | O_DIRECTORY, 0); |
| @@ -4002,7 +4011,7 @@ by calling `format-decode', which see. */) | |||
| 4002 | XCAR (XCAR (window_markers))); | 4011 | XCAR (XCAR (window_markers))); |
| 4003 | } | 4012 | } |
| 4004 | 4013 | ||
| 4005 | if (fstat (fd, &st) != 0) | 4014 | if (sys_fstat (fd, &st) != 0) |
| 4006 | report_file_error ("Input file status", orig_filename); | 4015 | report_file_error ("Input file status", orig_filename); |
| 4007 | mtime = get_stat_mtime (&st); | 4016 | mtime = get_stat_mtime (&st); |
| 4008 | 4017 | ||
| @@ -5394,7 +5403,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, | |||
| 5394 | modtime = invalid_timespec (); | 5403 | modtime = invalid_timespec (); |
| 5395 | if (visiting) | 5404 | if (visiting) |
| 5396 | { | 5405 | { |
| 5397 | if (fstat (desc, &st) == 0) | 5406 | if (sys_fstat (desc, &st) == 0) |
| 5398 | modtime = get_stat_mtime (&st); | 5407 | modtime = get_stat_mtime (&st); |
| 5399 | else | 5408 | else |
| 5400 | ok = 0, save_errno = errno; | 5409 | ok = 0, save_errno = errno; |
| @@ -5432,7 +5441,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, | |||
| 5432 | if (desc1 >= 0) | 5441 | if (desc1 >= 0) |
| 5433 | { | 5442 | { |
| 5434 | struct stat st1; | 5443 | struct stat st1; |
| 5435 | if (fstat (desc1, &st1) == 0 | 5444 | if (sys_fstat (desc1, &st1) == 0 |
| 5436 | && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) | 5445 | && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) |
| 5437 | { | 5446 | { |
| 5438 | /* Use the heuristic if it appears to be valid. With neither | 5447 | /* Use the heuristic if it appears to be valid. With neither |
diff --git a/src/filelock.c b/src/filelock.c index a657cc4582c..e70c68501d1 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -120,6 +120,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 120 | * Non-forced locks on non-MS-Windows systems that support neither | 120 | * Non-forced locks on non-MS-Windows systems that support neither |
| 121 | hard nor symbolic links. */ | 121 | hard nor symbolic links. */ |
| 122 | 122 | ||
| 123 | /* Boot time is not available on Android. */ | ||
| 124 | |||
| 125 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 126 | #undef BOOT_TIME | ||
| 127 | #endif | ||
| 128 | |||
| 123 | 129 | ||
| 124 | /* Return the time of the last system boot. */ | 130 | /* Return the time of the last system boot. */ |
| 125 | 131 | ||
| @@ -3519,6 +3519,10 @@ The data read from the system are decoded using `locale-coding-system'. */) | |||
| 3519 | (Lisp_Object item) | 3519 | (Lisp_Object item) |
| 3520 | { | 3520 | { |
| 3521 | char *str = NULL; | 3521 | char *str = NULL; |
| 3522 | |||
| 3523 | /* STR is apparently unused on Android. */ | ||
| 3524 | ((void) str); | ||
| 3525 | |||
| 3522 | #ifdef HAVE_LANGINFO_CODESET | 3526 | #ifdef HAVE_LANGINFO_CODESET |
| 3523 | if (EQ (item, Qcodeset)) | 3527 | if (EQ (item, Qcodeset)) |
| 3524 | { | 3528 | { |
diff --git a/src/font.c b/src/font.c index 6e720bc2856..4ea18f4ce76 100644 --- a/src/font.c +++ b/src/font.c | |||
| @@ -180,6 +180,22 @@ font_make_entity (void) | |||
| 180 | return font_entity; | 180 | return font_entity; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | #ifdef HAVE_ANDROID | ||
| 184 | |||
| 185 | Lisp_Object | ||
| 186 | font_make_entity_android (int size) | ||
| 187 | { | ||
| 188 | Lisp_Object font_entity; | ||
| 189 | struct font_entity *entity | ||
| 190 | = ((struct font_entity *) | ||
| 191 | allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX, | ||
| 192 | PVEC_FONT)); | ||
| 193 | XSETFONT (font_entity, entity); | ||
| 194 | return font_entity; | ||
| 195 | } | ||
| 196 | |||
| 197 | #endif | ||
| 198 | |||
| 183 | /* Create a font-object whose structure size is SIZE. If ENTITY is | 199 | /* Create a font-object whose structure size is SIZE. If ENTITY is |
| 184 | not nil, copy properties from ENTITY to the font-object. If | 200 | not nil, copy properties from ENTITY to the font-object. If |
| 185 | PIXELSIZE is positive, set the `size' property to PIXELSIZE. */ | 201 | PIXELSIZE is positive, set the `size' property to PIXELSIZE. */ |
diff --git a/src/font.h b/src/font.h index d36c45a53c4..c1ab26b87cb 100644 --- a/src/font.h +++ b/src/font.h | |||
| @@ -823,6 +823,9 @@ extern Lisp_Object copy_font_spec (Lisp_Object); | |||
| 823 | extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object); | 823 | extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object); |
| 824 | 824 | ||
| 825 | extern Lisp_Object font_make_entity (void); | 825 | extern Lisp_Object font_make_entity (void); |
| 826 | #ifdef HAVE_ANDROID | ||
| 827 | extern Lisp_Object font_make_entity_android (int); | ||
| 828 | #endif | ||
| 826 | extern Lisp_Object font_make_object (int, Lisp_Object, int); | 829 | extern Lisp_Object font_make_object (int, Lisp_Object, int); |
| 827 | #if defined (HAVE_XFT) || defined (HAVE_FREETYPE) || defined (HAVE_NS) | 830 | #if defined (HAVE_XFT) || defined (HAVE_FREETYPE) || defined (HAVE_NS) |
| 828 | extern Lisp_Object font_build_object (int, Lisp_Object, Lisp_Object, double); | 831 | extern Lisp_Object font_build_object (int, Lisp_Object, Lisp_Object, double); |
diff --git a/src/frame.c b/src/frame.c index 7d902dabd4f..e843af257a4 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -228,6 +228,7 @@ Value is: | |||
| 228 | `pc' for a direct-write MS-DOS frame, | 228 | `pc' for a direct-write MS-DOS frame, |
| 229 | `pgtk' for an Emacs frame running on pure GTK. | 229 | `pgtk' for an Emacs frame running on pure GTK. |
| 230 | `haiku' for an Emacs frame running in Haiku. | 230 | `haiku' for an Emacs frame running in Haiku. |
| 231 | `android' for an Emacs frame running in Android. | ||
| 231 | See also `frame-live-p'. */) | 232 | See also `frame-live-p'. */) |
| 232 | (Lisp_Object object) | 233 | (Lisp_Object object) |
| 233 | { | 234 | { |
| @@ -250,6 +251,8 @@ See also `frame-live-p'. */) | |||
| 250 | return Qpgtk; | 251 | return Qpgtk; |
| 251 | case output_haiku: | 252 | case output_haiku: |
| 252 | return Qhaiku; | 253 | return Qhaiku; |
| 254 | case output_android: | ||
| 255 | return Qandroid; | ||
| 253 | default: | 256 | default: |
| 254 | emacs_abort (); | 257 | emacs_abort (); |
| 255 | } | 258 | } |
| @@ -279,6 +282,7 @@ The value is a symbol: | |||
| 279 | `pc' for a direct-write MS-DOS frame. | 282 | `pc' for a direct-write MS-DOS frame. |
| 280 | `pgtk' for an Emacs frame using pure GTK facilities. | 283 | `pgtk' for an Emacs frame using pure GTK facilities. |
| 281 | `haiku' for an Emacs frame running in Haiku. | 284 | `haiku' for an Emacs frame running in Haiku. |
| 285 | `android' for an Emacs frame running in Android/ | ||
| 282 | 286 | ||
| 283 | FRAME defaults to the currently selected frame. | 287 | FRAME defaults to the currently selected frame. |
| 284 | 288 | ||
| @@ -1228,6 +1232,7 @@ make_initial_frame (void) | |||
| 1228 | return f; | 1232 | return f; |
| 1229 | } | 1233 | } |
| 1230 | 1234 | ||
| 1235 | #ifndef HAVE_ANDROID | ||
| 1231 | 1236 | ||
| 1232 | static struct frame * | 1237 | static struct frame * |
| 1233 | make_terminal_frame (struct terminal *terminal) | 1238 | make_terminal_frame (struct terminal *terminal) |
| @@ -1317,6 +1322,8 @@ get_future_frame_param (Lisp_Object parameter, | |||
| 1317 | return result; | 1322 | return result; |
| 1318 | } | 1323 | } |
| 1319 | 1324 | ||
| 1325 | #endif | ||
| 1326 | |||
| 1320 | DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, | 1327 | DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, |
| 1321 | 1, 1, 0, | 1328 | 1, 1, 0, |
| 1322 | doc: /* Create an additional terminal frame, possibly on another terminal. | 1329 | doc: /* Create an additional terminal frame, possibly on another terminal. |
| @@ -1336,6 +1343,10 @@ Note that changing the size of one terminal frame automatically | |||
| 1336 | affects all frames on the same terminal device. */) | 1343 | affects all frames on the same terminal device. */) |
| 1337 | (Lisp_Object parms) | 1344 | (Lisp_Object parms) |
| 1338 | { | 1345 | { |
| 1346 | #ifdef HAVE_ANDROID | ||
| 1347 | error ("Text terminals are not supported on this platform"); | ||
| 1348 | return Qnil; | ||
| 1349 | #else | ||
| 1339 | struct frame *f; | 1350 | struct frame *f; |
| 1340 | struct terminal *t = NULL; | 1351 | struct terminal *t = NULL; |
| 1341 | Lisp_Object frame; | 1352 | Lisp_Object frame; |
| @@ -1436,6 +1447,7 @@ affects all frames on the same terminal device. */) | |||
| 1436 | f->after_make_frame = true; | 1447 | f->after_make_frame = true; |
| 1437 | 1448 | ||
| 1438 | return frame; | 1449 | return frame; |
| 1450 | #endif | ||
| 1439 | } | 1451 | } |
| 1440 | 1452 | ||
| 1441 | 1453 | ||
| @@ -5303,16 +5315,23 @@ gui_display_get_resource (Display_Info *dpyinfo, Lisp_Object attribute, | |||
| 5303 | *nz++ = '.'; | 5315 | *nz++ = '.'; |
| 5304 | lispstpcpy (nz, attribute); | 5316 | lispstpcpy (nz, attribute); |
| 5305 | 5317 | ||
| 5306 | const char *value = | 5318 | #ifndef HAVE_ANDROID |
| 5307 | dpyinfo->terminal->get_string_resource_hook (&dpyinfo->rdb, | 5319 | const char *value |
| 5308 | name_key, | 5320 | = dpyinfo->terminal->get_string_resource_hook (&dpyinfo->rdb, |
| 5309 | class_key); | 5321 | name_key, |
| 5310 | SAFE_FREE(); | 5322 | class_key); |
| 5323 | |||
| 5324 | SAFE_FREE (); | ||
| 5311 | 5325 | ||
| 5312 | if (value && *value) | 5326 | if (value && *value) |
| 5313 | return build_string (value); | 5327 | return build_string (value); |
| 5314 | else | 5328 | else |
| 5315 | return Qnil; | 5329 | return Qnil; |
| 5330 | #else | ||
| 5331 | |||
| 5332 | SAFE_FREE (); | ||
| 5333 | return Qnil; | ||
| 5334 | #endif | ||
| 5316 | } | 5335 | } |
| 5317 | 5336 | ||
| 5318 | 5337 | ||
| @@ -6218,6 +6237,7 @@ syms_of_frame (void) | |||
| 6218 | DEFSYM (Qns, "ns"); | 6237 | DEFSYM (Qns, "ns"); |
| 6219 | DEFSYM (Qpgtk, "pgtk"); | 6238 | DEFSYM (Qpgtk, "pgtk"); |
| 6220 | DEFSYM (Qhaiku, "haiku"); | 6239 | DEFSYM (Qhaiku, "haiku"); |
| 6240 | DEFSYM (Qandroid, "android"); | ||
| 6221 | DEFSYM (Qvisible, "visible"); | 6241 | DEFSYM (Qvisible, "visible"); |
| 6222 | DEFSYM (Qbuffer_predicate, "buffer-predicate"); | 6242 | DEFSYM (Qbuffer_predicate, "buffer-predicate"); |
| 6223 | DEFSYM (Qbuffer_list, "buffer-list"); | 6243 | DEFSYM (Qbuffer_list, "buffer-list"); |
diff --git a/src/frame.h b/src/frame.h index dcd32036b86..e0b47d26d69 100644 --- a/src/frame.h +++ b/src/frame.h | |||
| @@ -181,7 +181,7 @@ struct frame | |||
| 181 | most recently buried buffer is first. For last-buffer. */ | 181 | most recently buried buffer is first. For last-buffer. */ |
| 182 | Lisp_Object buried_buffer_list; | 182 | Lisp_Object buried_buffer_list; |
| 183 | 183 | ||
| 184 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 184 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 185 | /* A dummy window used to display menu bars under X when no X | 185 | /* A dummy window used to display menu bars under X when no X |
| 186 | toolkit support is available. */ | 186 | toolkit support is available. */ |
| 187 | Lisp_Object menu_bar_window; | 187 | Lisp_Object menu_bar_window; |
| @@ -377,7 +377,7 @@ struct frame | |||
| 377 | /* The output method says how the contents of this frame are | 377 | /* The output method says how the contents of this frame are |
| 378 | displayed. It could be using termcap, or using an X window. | 378 | displayed. It could be using termcap, or using an X window. |
| 379 | This must be the same as the terminal->type. */ | 379 | This must be the same as the terminal->type. */ |
| 380 | ENUM_BF (output_method) output_method : 3; | 380 | ENUM_BF (output_method) output_method : 4; |
| 381 | 381 | ||
| 382 | #ifdef HAVE_WINDOW_SYSTEM | 382 | #ifdef HAVE_WINDOW_SYSTEM |
| 383 | /* True if this frame is a tooltip frame. */ | 383 | /* True if this frame is a tooltip frame. */ |
| @@ -586,12 +586,13 @@ struct frame | |||
| 586 | well. */ | 586 | well. */ |
| 587 | union output_data | 587 | union output_data |
| 588 | { | 588 | { |
| 589 | struct tty_output *tty; /* From termchar.h. */ | 589 | struct tty_output *tty; /* From termchar.h. */ |
| 590 | struct x_output *x; /* From xterm.h. */ | 590 | struct x_output *x; /* From xterm.h. */ |
| 591 | struct w32_output *w32; /* From w32term.h. */ | 591 | struct w32_output *w32; /* From w32term.h. */ |
| 592 | struct ns_output *ns; /* From nsterm.h. */ | 592 | struct ns_output *ns; /* From nsterm.h. */ |
| 593 | struct pgtk_output *pgtk; /* From pgtkterm.h. */ | 593 | struct pgtk_output *pgtk; /* From pgtkterm.h. */ |
| 594 | struct haiku_output *haiku; /* From haikuterm.h. */ | 594 | struct haiku_output *haiku; /* From haikuterm.h. */ |
| 595 | struct android_output *android; /* From androidterm.h. */ | ||
| 595 | } | 596 | } |
| 596 | output_data; | 597 | output_data; |
| 597 | 598 | ||
| @@ -713,7 +714,7 @@ fset_menu_bar_vector (struct frame *f, Lisp_Object val) | |||
| 713 | { | 714 | { |
| 714 | f->menu_bar_vector = val; | 715 | f->menu_bar_vector = val; |
| 715 | } | 716 | } |
| 716 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 717 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 717 | INLINE void | 718 | INLINE void |
| 718 | fset_menu_bar_window (struct frame *f, Lisp_Object val) | 719 | fset_menu_bar_window (struct frame *f, Lisp_Object val) |
| 719 | { | 720 | { |
| @@ -872,6 +873,11 @@ default_pixels_per_inch_y (void) | |||
| 872 | #else | 873 | #else |
| 873 | #define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku) | 874 | #define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku) |
| 874 | #endif | 875 | #endif |
| 876 | #ifndef HAVE_ANDROID | ||
| 877 | #define FRAME_ANDROID_P(f) false | ||
| 878 | #else | ||
| 879 | #define FRAME_ANDROID_P(f) ((f)->output_method == output_android) | ||
| 880 | #endif | ||
| 875 | 881 | ||
| 876 | /* FRAME_WINDOW_P tests whether the frame is a graphical window system | 882 | /* FRAME_WINDOW_P tests whether the frame is a graphical window system |
| 877 | frame. */ | 883 | frame. */ |
| @@ -890,6 +896,9 @@ default_pixels_per_inch_y (void) | |||
| 890 | #ifdef HAVE_HAIKU | 896 | #ifdef HAVE_HAIKU |
| 891 | #define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f) | 897 | #define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f) |
| 892 | #endif | 898 | #endif |
| 899 | #ifdef HAVE_ANDROID | ||
| 900 | #define FRAME_WINDOW_P(f) FRAME_ANDROID_P (f) | ||
| 901 | #endif | ||
| 893 | #ifndef FRAME_WINDOW_P | 902 | #ifndef FRAME_WINDOW_P |
| 894 | #define FRAME_WINDOW_P(f) ((void) (f), false) | 903 | #define FRAME_WINDOW_P(f) ((void) (f), false) |
| 895 | #endif | 904 | #endif |
| @@ -917,11 +926,17 @@ default_pixels_per_inch_y (void) | |||
| 917 | frame F. We need to define two versions because a TTY-only build | 926 | frame F. We need to define two versions because a TTY-only build |
| 918 | does not have FRAME_DISPLAY_INFO. */ | 927 | does not have FRAME_DISPLAY_INFO. */ |
| 919 | #ifdef HAVE_WINDOW_SYSTEM | 928 | #ifdef HAVE_WINDOW_SYSTEM |
| 929 | #ifndef HAVE_ANDROID | ||
| 920 | # define MOUSE_HL_INFO(F) \ | 930 | # define MOUSE_HL_INFO(F) \ |
| 921 | (FRAME_WINDOW_P(F) \ | 931 | (FRAME_WINDOW_P (F) \ |
| 922 | ? &FRAME_DISPLAY_INFO(F)->mouse_highlight \ | 932 | ? &FRAME_DISPLAY_INFO(F)->mouse_highlight \ |
| 923 | : &(F)->output_data.tty->display_info->mouse_highlight) | 933 | : &(F)->output_data.tty->display_info->mouse_highlight) |
| 924 | #else | 934 | #else |
| 935 | /* There is no "struct tty_output" on Android at all. */ | ||
| 936 | # define MOUSE_HL_INFO(F) \ | ||
| 937 | (&FRAME_DISPLAY_INFO(F)->mouse_highlight) | ||
| 938 | #endif | ||
| 939 | #else | ||
| 925 | # define MOUSE_HL_INFO(F) \ | 940 | # define MOUSE_HL_INFO(F) \ |
| 926 | (&(F)->output_data.tty->display_info->mouse_highlight) | 941 | (&(F)->output_data.tty->display_info->mouse_highlight) |
| 927 | #endif | 942 | #endif |
diff --git a/src/image.c b/src/image.c index b881e43e951..986dd7aada4 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -175,6 +175,28 @@ typedef struct haiku_bitmap_record Bitmap_Record; | |||
| 175 | 175 | ||
| 176 | #endif | 176 | #endif |
| 177 | 177 | ||
| 178 | #ifdef HAVE_ANDROID | ||
| 179 | #include "androidterm.h" | ||
| 180 | typedef struct android_bitmap_record Bitmap_Record; | ||
| 181 | |||
| 182 | /* TODO: implement images on Android. */ | ||
| 183 | #define GET_PIXEL(ximg, x, y) 0 | ||
| 184 | #define PUT_PIXEL(ximg, x, y, pixel) ((void) (pixel)) | ||
| 185 | #define NO_PIXMAP 0 | ||
| 186 | |||
| 187 | #define PIX_MASK_RETAIN 0 | ||
| 188 | #define PIX_MASK_DRAW 1 | ||
| 189 | |||
| 190 | #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) | ||
| 191 | #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) | ||
| 192 | #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) | ||
| 193 | #define BLUE_FROM_ULONG(color) ((color) & 0xff) | ||
| 194 | #define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101) | ||
| 195 | #define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101) | ||
| 196 | #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101) | ||
| 197 | |||
| 198 | #endif | ||
| 199 | |||
| 178 | static void image_disable_image (struct frame *, struct image *); | 200 | static void image_disable_image (struct frame *, struct image *); |
| 179 | static void image_edge_detection (struct frame *, struct image *, Lisp_Object, | 201 | static void image_edge_detection (struct frame *, struct image *, Lisp_Object, |
| 180 | Lisp_Object); | 202 | Lisp_Object); |
| @@ -831,6 +853,18 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file) | |||
| 831 | xfree (contents); | 853 | xfree (contents); |
| 832 | return id; | 854 | return id; |
| 833 | #endif | 855 | #endif |
| 856 | |||
| 857 | #ifdef HAVE_ANDROID | ||
| 858 | #ifdef ANDROID_STUBIFY | ||
| 859 | ((void) dpyinfo); | ||
| 860 | |||
| 861 | /* This function should never be called when building stubs. */ | ||
| 862 | emacs_abort (); | ||
| 863 | #else | ||
| 864 | /* you lose, not yet implemented TODO */ | ||
| 865 | return 0; | ||
| 866 | #endif | ||
| 867 | #endif | ||
| 834 | } | 868 | } |
| 835 | 869 | ||
| 836 | /* Free bitmap B. */ | 870 | /* Free bitmap B. */ |
| @@ -3338,6 +3372,16 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d | |||
| 3338 | Emacs_Pix_Container *pimg, | 3372 | Emacs_Pix_Container *pimg, |
| 3339 | Emacs_Pixmap *pixmap, Picture *picture) | 3373 | Emacs_Pixmap *pixmap, Picture *picture) |
| 3340 | { | 3374 | { |
| 3375 | #ifdef HAVE_ANDROID | ||
| 3376 | #ifdef ANDROID_STUBIFY | ||
| 3377 | /* This function should never be called when building stubs. */ | ||
| 3378 | emacs_abort (); | ||
| 3379 | #else | ||
| 3380 | /* you lose, not yet implemented TODO */ | ||
| 3381 | return false; | ||
| 3382 | #endif | ||
| 3383 | #endif | ||
| 3384 | |||
| 3341 | #ifdef USE_CAIRO | 3385 | #ifdef USE_CAIRO |
| 3342 | eassert (input_blocked_p ()); | 3386 | eassert (input_blocked_p ()); |
| 3343 | 3387 | ||
| @@ -3646,6 +3690,16 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p, | |||
| 3646 | static Emacs_Pix_Container | 3690 | static Emacs_Pix_Container |
| 3647 | image_get_x_image (struct frame *f, struct image *img, bool mask_p) | 3691 | image_get_x_image (struct frame *f, struct image *img, bool mask_p) |
| 3648 | { | 3692 | { |
| 3693 | #ifdef HAVE_ANDROID | ||
| 3694 | #ifdef ANDROID_STUBIFY | ||
| 3695 | /* This function should never be called when building stubs. */ | ||
| 3696 | emacs_abort (); | ||
| 3697 | #else | ||
| 3698 | /* you lose, not yet implemented TODO */ | ||
| 3699 | return 0; | ||
| 3700 | #endif | ||
| 3701 | #endif | ||
| 3702 | |||
| 3649 | #if defined USE_CAIRO || defined (HAVE_HAIKU) | 3703 | #if defined USE_CAIRO || defined (HAVE_HAIKU) |
| 3650 | return !mask_p ? img->pixmap : img->mask; | 3704 | return !mask_p ? img->pixmap : img->mask; |
| 3651 | #elif defined HAVE_X_WINDOWS | 3705 | #elif defined HAVE_X_WINDOWS |
| @@ -3756,7 +3810,7 @@ slurp_file (int fd, ptrdiff_t *size) | |||
| 3756 | specpdl_ref count = SPECPDL_INDEX (); | 3810 | specpdl_ref count = SPECPDL_INDEX (); |
| 3757 | record_unwind_protect_ptr (fclose_unwind, fp); | 3811 | record_unwind_protect_ptr (fclose_unwind, fp); |
| 3758 | 3812 | ||
| 3759 | if (fstat (fileno (fp), &st) == 0 | 3813 | if (sys_fstat (fileno (fp), &st) == 0 |
| 3760 | && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX)) | 3814 | && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX)) |
| 3761 | { | 3815 | { |
| 3762 | /* Report an error if we read past the purported EOF. | 3816 | /* Report an error if we read past the purported EOF. |
| @@ -6074,7 +6128,8 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) | |||
| 6074 | { | 6128 | { |
| 6075 | #ifdef HAVE_NTGUI | 6129 | #ifdef HAVE_NTGUI |
| 6076 | return PALETTERGB (r >> 8, g >> 8, b >> 8); | 6130 | return PALETTERGB (r >> 8, g >> 8, b >> 8); |
| 6077 | #elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU | 6131 | #elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU \ |
| 6132 | || defined HAVE_ANDROID | ||
| 6078 | return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); | 6133 | return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); |
| 6079 | #else | 6134 | #else |
| 6080 | xsignal1 (Qfile_error, | 6135 | xsignal1 (Qfile_error, |
| @@ -6147,7 +6202,8 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6147 | p = colors; | 6202 | p = colors; |
| 6148 | for (y = 0; y < img->height; ++y) | 6203 | for (y = 0; y < img->height; ++y) |
| 6149 | { | 6204 | { |
| 6150 | #if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU | 6205 | #if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU \ |
| 6206 | && !defined HAVE_ANDROID | ||
| 6151 | Emacs_Color *row = p; | 6207 | Emacs_Color *row = p; |
| 6152 | for (x = 0; x < img->width; ++x, ++p) | 6208 | for (x = 0; x < img->width; ++x, ++p) |
| 6153 | p->pixel = GET_PIXEL (ximg, x, y); | 6209 | p->pixel = GET_PIXEL (ximg, x, y); |
| @@ -6155,7 +6211,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6155 | { | 6211 | { |
| 6156 | FRAME_TERMINAL (f)->query_colors (f, row, img->width); | 6212 | FRAME_TERMINAL (f)->query_colors (f, row, img->width); |
| 6157 | } | 6213 | } |
| 6158 | #else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU */ | 6214 | #else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU || HAVE_ANDROID */ |
| 6159 | for (x = 0; x < img->width; ++x, ++p) | 6215 | for (x = 0; x < img->width; ++x, ++p) |
| 6160 | { | 6216 | { |
| 6161 | p->pixel = GET_PIXEL (ximg, x, y); | 6217 | p->pixel = GET_PIXEL (ximg, x, y); |
| @@ -6166,7 +6222,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6166 | p->blue = BLUE16_FROM_ULONG (p->pixel); | 6222 | p->blue = BLUE16_FROM_ULONG (p->pixel); |
| 6167 | } | 6223 | } |
| 6168 | } | 6224 | } |
| 6169 | #endif /* USE_CAIRO || HAVE_NS */ | 6225 | #endif /* USE_CAIRO || HAVE_NS || HAVE_ANDROID */ |
| 6170 | } | 6226 | } |
| 6171 | 6227 | ||
| 6172 | image_unget_x_image_or_dc (img, 0, ximg, prev); | 6228 | image_unget_x_image_or_dc (img, 0, ximg, prev); |
| @@ -6231,7 +6287,11 @@ image_from_emacs_colors (struct frame *f, struct image *img, Emacs_Color *colors | |||
| 6231 | Emacs_Pix_Container ximage; | 6287 | Emacs_Pix_Container ximage; |
| 6232 | Emacs_Color *p; | 6288 | Emacs_Color *p; |
| 6233 | 6289 | ||
| 6290 | #ifndef HAVE_ANDROID | ||
| 6234 | ximage = NULL; | 6291 | ximage = NULL; |
| 6292 | #else | ||
| 6293 | ximage = 0; | ||
| 6294 | #endif | ||
| 6235 | 6295 | ||
| 6236 | init_color_table (); | 6296 | init_color_table (); |
| 6237 | 6297 | ||
| @@ -6393,7 +6453,9 @@ image_edge_detection (struct frame *f, struct image *img, | |||
| 6393 | } | 6453 | } |
| 6394 | 6454 | ||
| 6395 | 6455 | ||
| 6396 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU | 6456 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU \ |
| 6457 | || defined HAVE_ANDROID | ||
| 6458 | |||
| 6397 | static void | 6459 | static void |
| 6398 | image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, | 6460 | image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, |
| 6399 | int x, int y, unsigned int width, unsigned int height, | 6461 | int x, int y, unsigned int width, unsigned int height, |
| @@ -6429,8 +6491,16 @@ image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, | |||
| 6429 | XFreeGC (dpy, gc); | 6491 | XFreeGC (dpy, gc); |
| 6430 | #elif HAVE_HAIKU | 6492 | #elif HAVE_HAIKU |
| 6431 | be_draw_cross_on_pixmap (pixmap, x, y, width, height, color); | 6493 | be_draw_cross_on_pixmap (pixmap, x, y, width, height, color); |
| 6494 | #elif HAVE_ANDROID | ||
| 6495 | #ifdef ANDROID_STUBIFY | ||
| 6496 | /* This function should never be called when building stubs. */ | ||
| 6497 | emacs_abort (); | ||
| 6498 | #else | ||
| 6499 | /* you lose, not yet implemented TODO */ | ||
| 6500 | #endif | ||
| 6432 | #endif | 6501 | #endif |
| 6433 | } | 6502 | } |
| 6503 | |||
| 6434 | #endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */ | 6504 | #endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */ |
| 6435 | 6505 | ||
| 6436 | /* Transform image IMG on frame F so that it looks disabled. */ | 6506 | /* Transform image IMG on frame F so that it looks disabled. */ |
| @@ -6474,7 +6544,7 @@ image_disable_image (struct frame *f, struct image *img) | |||
| 6474 | #ifndef HAVE_NTGUI | 6544 | #ifndef HAVE_NTGUI |
| 6475 | #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ | 6545 | #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ |
| 6476 | 6546 | ||
| 6477 | #if !defined USE_CAIRO && !defined HAVE_HAIKU | 6547 | #if !defined USE_CAIRO && !defined HAVE_HAIKU && !defined HAVE_ANDROID |
| 6478 | #define CrossForeground(f) BLACK_PIX_DEFAULT (f) | 6548 | #define CrossForeground(f) BLACK_PIX_DEFAULT (f) |
| 6479 | #define MaskForeground(f) WHITE_PIX_DEFAULT (f) | 6549 | #define MaskForeground(f) WHITE_PIX_DEFAULT (f) |
| 6480 | #else /* USE_CAIRO || HAVE_HAIKU */ | 6550 | #else /* USE_CAIRO || HAVE_HAIKU */ |
| @@ -6482,7 +6552,7 @@ image_disable_image (struct frame *f, struct image *img) | |||
| 6482 | #define MaskForeground(f) PIX_MASK_DRAW | 6552 | #define MaskForeground(f) PIX_MASK_DRAW |
| 6483 | #endif /* USE_CAIRO || HAVE_HAIKU */ | 6553 | #endif /* USE_CAIRO || HAVE_HAIKU */ |
| 6484 | 6554 | ||
| 6485 | #if !defined USE_CAIRO && !defined HAVE_HAIKU | 6555 | #if !defined USE_CAIRO && !defined HAVE_HAIKU && !defined HAVE_ANDROID |
| 6486 | image_sync_to_pixmaps (f, img); | 6556 | image_sync_to_pixmaps (f, img); |
| 6487 | #endif /* !USE_CAIRO && !HAVE_HAIKU */ | 6557 | #endif /* !USE_CAIRO && !HAVE_HAIKU */ |
| 6488 | image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height, | 6558 | image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height, |
| @@ -9099,7 +9169,7 @@ gif_load (struct frame *f, struct image *img) | |||
| 9099 | `image-cache-size'. */ | 9169 | `image-cache-size'. */ |
| 9100 | struct stat st; | 9170 | struct stat st; |
| 9101 | FILE *fp = fopen (SSDATA (encoded_file), "rb"); | 9171 | FILE *fp = fopen (SSDATA (encoded_file), "rb"); |
| 9102 | if (fstat (fileno (fp), &st) == 0) | 9172 | if (sys_fstat (fileno (fp), &st) == 0) |
| 9103 | byte_size = st.st_size; | 9173 | byte_size = st.st_size; |
| 9104 | fclose (fp); | 9174 | fclose (fp); |
| 9105 | } | 9175 | } |
diff --git a/src/lisp.h b/src/lisp.h index be511a0eb9c..1f1d47f2a95 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -30,6 +30,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 30 | #include <inttypes.h> | 30 | #include <inttypes.h> |
| 31 | #include <limits.h> | 31 | #include <limits.h> |
| 32 | 32 | ||
| 33 | #ifdef HAVE_SYS_STAT_H | ||
| 34 | #include <sys/stat.h> | ||
| 35 | #endif | ||
| 36 | |||
| 33 | #include <attribute.h> | 37 | #include <attribute.h> |
| 34 | #include <intprops.h> | 38 | #include <intprops.h> |
| 35 | #include <verify.h> | 39 | #include <verify.h> |
| @@ -4726,6 +4730,7 @@ extern void syms_of_marker (void); | |||
| 4726 | 4730 | ||
| 4727 | /* Defined in fileio.c. */ | 4731 | /* Defined in fileio.c. */ |
| 4728 | 4732 | ||
| 4733 | extern Lisp_Object file_name_directory (Lisp_Object); | ||
| 4729 | extern char *splice_dir_file (char *, char const *, char const *) | 4734 | extern char *splice_dir_file (char *, char const *, char const *) |
| 4730 | ATTRIBUTE_RETURNS_NONNULL; | 4735 | ATTRIBUTE_RETURNS_NONNULL; |
| 4731 | extern bool file_name_absolute_p (const char *); | 4736 | extern bool file_name_absolute_p (const char *); |
| @@ -5063,7 +5068,12 @@ extern void init_random (void); | |||
| 5063 | extern void emacs_backtrace (int); | 5068 | extern void emacs_backtrace (int); |
| 5064 | extern AVOID emacs_abort (void) NO_INLINE; | 5069 | extern AVOID emacs_abort (void) NO_INLINE; |
| 5065 | extern int emacs_fstatat (int, char const *, void *, int); | 5070 | extern int emacs_fstatat (int, char const *, void *, int); |
| 5071 | #ifdef HAVE_SYS_STAT_H | ||
| 5072 | extern int sys_fstat (int, struct stat *); | ||
| 5073 | #endif | ||
| 5074 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 5066 | extern int emacs_openat (int, char const *, int, int); | 5075 | extern int emacs_openat (int, char const *, int, int); |
| 5076 | #endif | ||
| 5067 | extern int emacs_open (const char *, int, int); | 5077 | extern int emacs_open (const char *, int, int); |
| 5068 | extern int emacs_open_noquit (const char *, int, int); | 5078 | extern int emacs_open_noquit (const char *, int, int); |
| 5069 | extern int emacs_pipe (int[2]); | 5079 | extern int emacs_pipe (int[2]); |
| @@ -5101,7 +5111,9 @@ extern Lisp_Object directory_files_internal (Lisp_Object, Lisp_Object, | |||
| 5101 | bool, Lisp_Object, Lisp_Object); | 5111 | bool, Lisp_Object, Lisp_Object); |
| 5102 | 5112 | ||
| 5103 | /* Defined in term.c. */ | 5113 | /* Defined in term.c. */ |
| 5114 | #ifndef HAVE_ANDROID | ||
| 5104 | extern int *char_ins_del_vector; | 5115 | extern int *char_ins_del_vector; |
| 5116 | #endif | ||
| 5105 | extern void syms_of_term (void); | 5117 | extern void syms_of_term (void); |
| 5106 | extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); | 5118 | extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); |
| 5107 | 5119 | ||
diff --git a/src/lread.c b/src/lread.c index d838a18de5a..eb029f01623 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1047,7 +1047,7 @@ safe_to_load_version (Lisp_Object file, int fd) | |||
| 1047 | 1047 | ||
| 1048 | /* If the file is not regular, then we cannot safely seek it. | 1048 | /* If the file is not regular, then we cannot safely seek it. |
| 1049 | Assume that it is not safe to load as a compiled file. */ | 1049 | Assume that it is not safe to load as a compiled file. */ |
| 1050 | if (fstat (fd, &st) == 0 && !S_ISREG (st.st_mode)) | 1050 | if (sys_fstat (fd, &st) == 0 && !S_ISREG (st.st_mode)) |
| 1051 | return 0; | 1051 | return 0; |
| 1052 | 1052 | ||
| 1053 | /* Read the first few bytes from the file, and look for a line | 1053 | /* Read the first few bytes from the file, and look for a line |
| @@ -1676,7 +1676,7 @@ maybe_swap_for_eln1 (Lisp_Object src_name, Lisp_Object eln_name, | |||
| 1676 | 1676 | ||
| 1677 | if (eln_fd > 0) | 1677 | if (eln_fd > 0) |
| 1678 | { | 1678 | { |
| 1679 | if (fstat (eln_fd, &eln_st) || S_ISDIR (eln_st.st_mode)) | 1679 | if (sys_fstat (eln_fd, &eln_st) || S_ISDIR (eln_st.st_mode)) |
| 1680 | emacs_close (eln_fd); | 1680 | emacs_close (eln_fd); |
| 1681 | else | 1681 | else |
| 1682 | { | 1682 | { |
| @@ -1998,7 +1998,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, | |||
| 1998 | } | 1998 | } |
| 1999 | else | 1999 | else |
| 2000 | { | 2000 | { |
| 2001 | int err = (fstat (fd, &st) != 0 ? errno | 2001 | int err = (sys_fstat (fd, &st) != 0 ? errno |
| 2002 | : S_ISDIR (st.st_mode) ? EISDIR : 0); | 2002 | : S_ISDIR (st.st_mode) ? EISDIR : 0); |
| 2003 | if (err) | 2003 | if (err) |
| 2004 | { | 2004 | { |
diff --git a/src/pdumper.c b/src/pdumper.c index e1c55d07ac3..87c652da52f 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -5620,7 +5620,7 @@ pdumper_load (const char *dump_filename, char *argv0) | |||
| 5620 | } | 5620 | } |
| 5621 | 5621 | ||
| 5622 | err = PDUMPER_LOAD_FILE_NOT_FOUND; | 5622 | err = PDUMPER_LOAD_FILE_NOT_FOUND; |
| 5623 | if (fstat (dump_fd, &stat) < 0) | 5623 | if (sys_fstat (dump_fd, &stat) < 0) |
| 5624 | goto out; | 5624 | goto out; |
| 5625 | 5625 | ||
| 5626 | err = PDUMPER_LOAD_BAD_FILE_TYPE; | 5626 | err = PDUMPER_LOAD_BAD_FILE_TYPE; |
diff --git a/src/process.c b/src/process.c index 5144c5d6c92..de1b07a81cc 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -119,6 +119,10 @@ static struct rlimit nofile_limit; | |||
| 119 | #include "gnutls.h" | 119 | #include "gnutls.h" |
| 120 | #endif | 120 | #endif |
| 121 | 121 | ||
| 122 | #ifdef HAVE_ANDROID | ||
| 123 | #include "android.h" | ||
| 124 | #endif | ||
| 125 | |||
| 122 | #ifdef HAVE_WINDOW_SYSTEM | 126 | #ifdef HAVE_WINDOW_SYSTEM |
| 123 | #include TERM_HEADER | 127 | #include TERM_HEADER |
| 124 | #endif /* HAVE_WINDOW_SYSTEM */ | 128 | #endif /* HAVE_WINDOW_SYSTEM */ |
| @@ -5679,7 +5683,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5679 | timeout = short_timeout; | 5683 | timeout = short_timeout; |
| 5680 | #endif | 5684 | #endif |
| 5681 | 5685 | ||
| 5682 | /* Non-macOS HAVE_GLIB builds call thread_select in xgselect.c. */ | 5686 | /* Android doesn't support threads and requires using a |
| 5687 | replacement for pselect in android.c to poll for | ||
| 5688 | events. */ | ||
| 5689 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 5690 | nfds = android_select (max_desc + 1, | ||
| 5691 | &Available, (check_write ? &Writeok : 0), | ||
| 5692 | NULL, &timeout, NULL); | ||
| 5693 | #else | ||
| 5694 | |||
| 5695 | /* Non-macOS HAVE_GLIB builds call thread_select in | ||
| 5696 | xgselect.c. */ | ||
| 5683 | #if defined HAVE_GLIB && !defined HAVE_NS | 5697 | #if defined HAVE_GLIB && !defined HAVE_NS |
| 5684 | nfds = xg_select (max_desc + 1, | 5698 | nfds = xg_select (max_desc + 1, |
| 5685 | &Available, (check_write ? &Writeok : 0), | 5699 | &Available, (check_write ? &Writeok : 0), |
| @@ -5695,6 +5709,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5695 | (check_write ? &Writeok : 0), | 5709 | (check_write ? &Writeok : 0), |
| 5696 | NULL, &timeout, NULL); | 5710 | NULL, &timeout, NULL); |
| 5697 | #endif /* !HAVE_GLIB */ | 5711 | #endif /* !HAVE_GLIB */ |
| 5712 | #endif /* HAVE_ANDROID && !ANDROID_STUBIFY */ | ||
| 5698 | 5713 | ||
| 5699 | #ifdef HAVE_GNUTLS | 5714 | #ifdef HAVE_GNUTLS |
| 5700 | /* Merge tls_available into Available. */ | 5715 | /* Merge tls_available into Available. */ |
diff --git a/src/scroll.c b/src/scroll.c index c643730965d..6d4e0d062b9 100644 --- a/src/scroll.c +++ b/src/scroll.c | |||
| @@ -21,6 +21,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 21 | 21 | ||
| 22 | #include <config.h> | 22 | #include <config.h> |
| 23 | 23 | ||
| 24 | /* The entire file is defined out under Android, where there is no | ||
| 25 | text terminal support of any kind. */ | ||
| 26 | |||
| 27 | #ifndef HAVE_ANDROID | ||
| 28 | |||
| 24 | #include "lisp.h" | 29 | #include "lisp.h" |
| 25 | #include "termchar.h" | 30 | #include "termchar.h" |
| 26 | #include "dispextern.h" | 31 | #include "dispextern.h" |
| @@ -984,3 +989,5 @@ do_line_insertion_deletion_costs (struct frame *frame, | |||
| 984 | FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame), | 989 | FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame), |
| 985 | coefficient); | 990 | coefficient); |
| 986 | } | 991 | } |
| 992 | |||
| 993 | #endif | ||
diff --git a/src/sysdep.c b/src/sysdep.c index 8402ffe308c..808c4af85f3 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -134,6 +134,10 @@ int _cdecl _spawnlp (int, const char *, const char *, ...); | |||
| 134 | # include <sys/socket.h> | 134 | # include <sys/socket.h> |
| 135 | #endif | 135 | #endif |
| 136 | 136 | ||
| 137 | #ifdef HAVE_ANDROID | ||
| 138 | #include "android.h" | ||
| 139 | #endif | ||
| 140 | |||
| 137 | /* Declare here, including term.h is problematic on some systems. */ | 141 | /* Declare here, including term.h is problematic on some systems. */ |
| 138 | extern void tputs (const char *, int, int (*)(int)); | 142 | extern void tputs (const char *, int, int (*)(int)); |
| 139 | 143 | ||
| @@ -790,6 +794,7 @@ init_sigio (int fd) | |||
| 790 | #endif | 794 | #endif |
| 791 | } | 795 | } |
| 792 | 796 | ||
| 797 | #ifndef HAVE_ANDROID | ||
| 793 | #ifndef DOS_NT | 798 | #ifndef DOS_NT |
| 794 | #ifdef F_SETOWN | 799 | #ifdef F_SETOWN |
| 795 | static void | 800 | static void |
| @@ -801,6 +806,7 @@ reset_sigio (int fd) | |||
| 801 | } | 806 | } |
| 802 | #endif /* F_SETOWN */ | 807 | #endif /* F_SETOWN */ |
| 803 | #endif | 808 | #endif |
| 809 | #endif | ||
| 804 | 810 | ||
| 805 | void | 811 | void |
| 806 | request_sigio (void) | 812 | request_sigio (void) |
| @@ -972,6 +978,8 @@ narrow_foreground_group (int fd) | |||
| 972 | tcsetpgrp_without_stopping (fd, getpid ()); | 978 | tcsetpgrp_without_stopping (fd, getpid ()); |
| 973 | } | 979 | } |
| 974 | 980 | ||
| 981 | #ifndef HAVE_ANDROID | ||
| 982 | |||
| 975 | /* Set the tty to our original foreground group. */ | 983 | /* Set the tty to our original foreground group. */ |
| 976 | static void | 984 | static void |
| 977 | widen_foreground_group (int fd) | 985 | widen_foreground_group (int fd) |
| @@ -979,6 +987,9 @@ widen_foreground_group (int fd) | |||
| 979 | if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0) | 987 | if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0) |
| 980 | tcsetpgrp_without_stopping (fd, inherited_pgroup); | 988 | tcsetpgrp_without_stopping (fd, inherited_pgroup); |
| 981 | } | 989 | } |
| 990 | |||
| 991 | #endif | ||
| 992 | |||
| 982 | 993 | ||
| 983 | /* Getting and setting emacs_tty structures. */ | 994 | /* Getting and setting emacs_tty structures. */ |
| 984 | 995 | ||
| @@ -1496,6 +1507,8 @@ reset_sys_modes (struct tty_display_info *tty_out) | |||
| 1496 | fflush (stdout); | 1507 | fflush (stdout); |
| 1497 | return; | 1508 | return; |
| 1498 | } | 1509 | } |
| 1510 | |||
| 1511 | #ifndef HAVE_ANDROID | ||
| 1499 | if (!tty_out->term_initted) | 1512 | if (!tty_out->term_initted) |
| 1500 | return; | 1513 | return; |
| 1501 | 1514 | ||
| @@ -1552,6 +1565,7 @@ reset_sys_modes (struct tty_display_info *tty_out) | |||
| 1552 | #endif | 1565 | #endif |
| 1553 | 1566 | ||
| 1554 | widen_foreground_group (fileno (tty_out->input)); | 1567 | widen_foreground_group (fileno (tty_out->input)); |
| 1568 | #endif | ||
| 1555 | } | 1569 | } |
| 1556 | 1570 | ||
| 1557 | #ifdef HAVE_PTYS | 1571 | #ifdef HAVE_PTYS |
| @@ -1802,7 +1816,11 @@ handle_arith_signal (int sig) | |||
| 1802 | xsignal0 (Qarith_error); | 1816 | xsignal0 (Qarith_error); |
| 1803 | } | 1817 | } |
| 1804 | 1818 | ||
| 1805 | #if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT | 1819 | /* This does not work on Android and interferes with the system |
| 1820 | tombstone generation. */ | ||
| 1821 | |||
| 1822 | #if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT \ | ||
| 1823 | && (!defined HAVE_ANDROID || defined ANDROID_STUBIFY) | ||
| 1806 | 1824 | ||
| 1807 | /* Alternate stack used by SIGSEGV handler below. */ | 1825 | /* Alternate stack used by SIGSEGV handler below. */ |
| 1808 | 1826 | ||
| @@ -1914,12 +1932,16 @@ init_sigsegv (void) | |||
| 1914 | 1932 | ||
| 1915 | #else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ | 1933 | #else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ |
| 1916 | 1934 | ||
| 1935 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 1936 | |||
| 1917 | static bool | 1937 | static bool |
| 1918 | init_sigsegv (void) | 1938 | init_sigsegv (void) |
| 1919 | { | 1939 | { |
| 1920 | return 0; | 1940 | return 0; |
| 1921 | } | 1941 | } |
| 1922 | 1942 | ||
| 1943 | #endif | ||
| 1944 | |||
| 1923 | #endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ | 1945 | #endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ |
| 1924 | 1946 | ||
| 1925 | static void | 1947 | static void |
| @@ -2020,12 +2042,17 @@ init_signals (void) | |||
| 2020 | sigaction (SIGFPE, &action, 0); | 2042 | sigaction (SIGFPE, &action, 0); |
| 2021 | } | 2043 | } |
| 2022 | 2044 | ||
| 2045 | /* SIGUSR1 and SIGUSR2 are used internally by the android_select | ||
| 2046 | function. */ | ||
| 2047 | #if !defined HAVE_ANDROID | ||
| 2023 | #ifdef SIGUSR1 | 2048 | #ifdef SIGUSR1 |
| 2024 | add_user_signal (SIGUSR1, "sigusr1"); | 2049 | add_user_signal (SIGUSR1, "sigusr1"); |
| 2025 | #endif | 2050 | #endif |
| 2026 | #ifdef SIGUSR2 | 2051 | #ifdef SIGUSR2 |
| 2027 | add_user_signal (SIGUSR2, "sigusr2"); | 2052 | add_user_signal (SIGUSR2, "sigusr2"); |
| 2028 | #endif | 2053 | #endif |
| 2054 | #endif | ||
| 2055 | |||
| 2029 | sigaction (SIGABRT, &thread_fatal_action, 0); | 2056 | sigaction (SIGABRT, &thread_fatal_action, 0); |
| 2030 | #ifdef SIGPRE | 2057 | #ifdef SIGPRE |
| 2031 | sigaction (SIGPRE, &thread_fatal_action, 0); | 2058 | sigaction (SIGPRE, &thread_fatal_action, 0); |
| @@ -2051,8 +2078,10 @@ init_signals (void) | |||
| 2051 | #ifdef SIGBUS | 2078 | #ifdef SIGBUS |
| 2052 | sigaction (SIGBUS, &thread_fatal_action, 0); | 2079 | sigaction (SIGBUS, &thread_fatal_action, 0); |
| 2053 | #endif | 2080 | #endif |
| 2081 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 2054 | if (!init_sigsegv ()) | 2082 | if (!init_sigsegv ()) |
| 2055 | sigaction (SIGSEGV, &thread_fatal_action, 0); | 2083 | sigaction (SIGSEGV, &thread_fatal_action, 0); |
| 2084 | #endif | ||
| 2056 | #ifdef SIGSYS | 2085 | #ifdef SIGSYS |
| 2057 | sigaction (SIGSYS, &thread_fatal_action, 0); | 2086 | sigaction (SIGSYS, &thread_fatal_action, 0); |
| 2058 | #endif | 2087 | #endif |
| @@ -2328,11 +2357,20 @@ int | |||
| 2328 | emacs_fstatat (int dirfd, char const *filename, void *st, int flags) | 2357 | emacs_fstatat (int dirfd, char const *filename, void *st, int flags) |
| 2329 | { | 2358 | { |
| 2330 | int r; | 2359 | int r; |
| 2331 | while ((r = fstatat (dirfd, filename, st, flags)) != 0 && errno == EINTR) | 2360 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2361 | while ((r = fstatat (dirfd, filename, st, flags)) != 0 | ||
| 2362 | && errno == EINTR) | ||
| 2363 | maybe_quit (); | ||
| 2364 | #else | ||
| 2365 | while ((r = android_fstatat (dirfd, filename, st, flags)) != 0 | ||
| 2366 | && errno == EINTR) | ||
| 2332 | maybe_quit (); | 2367 | maybe_quit (); |
| 2368 | #endif | ||
| 2333 | return r; | 2369 | return r; |
| 2334 | } | 2370 | } |
| 2335 | 2371 | ||
| 2372 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2373 | |||
| 2336 | static int | 2374 | static int |
| 2337 | sys_openat (int dirfd, char const *file, int oflags, int mode) | 2375 | sys_openat (int dirfd, char const *file, int oflags, int mode) |
| 2338 | { | 2376 | { |
| @@ -2347,6 +2385,18 @@ sys_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2347 | #endif | 2385 | #endif |
| 2348 | } | 2386 | } |
| 2349 | 2387 | ||
| 2388 | #endif | ||
| 2389 | |||
| 2390 | int | ||
| 2391 | sys_fstat (int fd, struct stat *statb) | ||
| 2392 | { | ||
| 2393 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2394 | return fstat (fd, statb); | ||
| 2395 | #else | ||
| 2396 | return android_fstat (fd, statb); | ||
| 2397 | #endif | ||
| 2398 | } | ||
| 2399 | |||
| 2350 | /* Assuming the directory DIRFD, open FILE for Emacs use, | 2400 | /* Assuming the directory DIRFD, open FILE for Emacs use, |
| 2351 | using open flags OFLAGS and mode MODE. | 2401 | using open flags OFLAGS and mode MODE. |
| 2352 | Use binary I/O on systems that care about text vs binary I/O. | 2402 | Use binary I/O on systems that care about text vs binary I/O. |
| @@ -2355,6 +2405,8 @@ sys_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2355 | Do not fail merely because the open was interrupted by a signal. | 2405 | Do not fail merely because the open was interrupted by a signal. |
| 2356 | Allow the user to quit. */ | 2406 | Allow the user to quit. */ |
| 2357 | 2407 | ||
| 2408 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2409 | |||
| 2358 | int | 2410 | int |
| 2359 | emacs_openat (int dirfd, char const *file, int oflags, int mode) | 2411 | emacs_openat (int dirfd, char const *file, int oflags, int mode) |
| 2360 | { | 2412 | { |
| @@ -2367,10 +2419,23 @@ emacs_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2367 | return fd; | 2419 | return fd; |
| 2368 | } | 2420 | } |
| 2369 | 2421 | ||
| 2422 | #endif | ||
| 2423 | |||
| 2370 | int | 2424 | int |
| 2371 | emacs_open (char const *file, int oflags, int mode) | 2425 | emacs_open (char const *file, int oflags, int mode) |
| 2372 | { | 2426 | { |
| 2427 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2428 | int fd; | ||
| 2429 | #endif | ||
| 2430 | |||
| 2431 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2373 | return emacs_openat (AT_FDCWD, file, oflags, mode); | 2432 | return emacs_openat (AT_FDCWD, file, oflags, mode); |
| 2433 | #else | ||
| 2434 | while ((fd = android_open (file, oflags, mode)) < 0 && errno == EINTR) | ||
| 2435 | maybe_quit (); | ||
| 2436 | |||
| 2437 | return fd; | ||
| 2438 | #endif | ||
| 2374 | } | 2439 | } |
| 2375 | 2440 | ||
| 2376 | /* Same as above, but doesn't allow the user to quit. */ | 2441 | /* Same as above, but doesn't allow the user to quit. */ |
| @@ -2382,9 +2447,15 @@ emacs_open_noquit (char const *file, int oflags, int mode) | |||
| 2382 | if (! (oflags & O_TEXT)) | 2447 | if (! (oflags & O_TEXT)) |
| 2383 | oflags |= O_BINARY; | 2448 | oflags |= O_BINARY; |
| 2384 | oflags |= O_CLOEXEC; | 2449 | oflags |= O_CLOEXEC; |
| 2450 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2385 | do | 2451 | do |
| 2386 | fd = open (file, oflags, mode); | 2452 | fd = open (file, oflags, mode); |
| 2387 | while (fd < 0 && errno == EINTR); | 2453 | while (fd < 0 && errno == EINTR); |
| 2454 | #else | ||
| 2455 | do | ||
| 2456 | fd = android_open (file, oflags, mode); | ||
| 2457 | while (fd < 0 && errno == EINTR); | ||
| 2458 | #endif | ||
| 2388 | return fd; | 2459 | return fd; |
| 2389 | } | 2460 | } |
| 2390 | 2461 | ||
| @@ -2434,6 +2505,8 @@ emacs_pipe (int fd[2]) | |||
| 2434 | For the background behind this mess, please see Austin Group defect 529 | 2505 | For the background behind this mess, please see Austin Group defect 529 |
| 2435 | <https://austingroupbugs.net/view.php?id=529>. */ | 2506 | <https://austingroupbugs.net/view.php?id=529>. */ |
| 2436 | 2507 | ||
| 2508 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2509 | |||
| 2437 | #ifndef POSIX_CLOSE_RESTART | 2510 | #ifndef POSIX_CLOSE_RESTART |
| 2438 | # define POSIX_CLOSE_RESTART 1 | 2511 | # define POSIX_CLOSE_RESTART 1 |
| 2439 | static int | 2512 | static int |
| @@ -2460,6 +2533,8 @@ posix_close (int fd, int flag) | |||
| 2460 | } | 2533 | } |
| 2461 | #endif | 2534 | #endif |
| 2462 | 2535 | ||
| 2536 | #endif | ||
| 2537 | |||
| 2463 | /* Close FD, retrying if interrupted. If successful, return 0; | 2538 | /* Close FD, retrying if interrupted. If successful, return 0; |
| 2464 | otherwise, return -1 and set errno to a non-EINTR value. Consider | 2539 | otherwise, return -1 and set errno to a non-EINTR value. Consider |
| 2465 | an EINPROGRESS error to be successful, as that's merely a signal | 2540 | an EINPROGRESS error to be successful, as that's merely a signal |
| @@ -2472,9 +2547,17 @@ posix_close (int fd, int flag) | |||
| 2472 | int | 2547 | int |
| 2473 | emacs_close (int fd) | 2548 | emacs_close (int fd) |
| 2474 | { | 2549 | { |
| 2550 | int r; | ||
| 2551 | |||
| 2475 | while (1) | 2552 | while (1) |
| 2476 | { | 2553 | { |
| 2477 | int r = posix_close (fd, POSIX_CLOSE_RESTART); | 2554 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2555 | r = posix_close (fd, POSIX_CLOSE_RESTART); | ||
| 2556 | #else | ||
| 2557 | r = android_close (fd) == 0 || errno == EINTR ? 0 : -1; | ||
| 2558 | #define POSIX_CLOSE_RESTART 1 | ||
| 2559 | #endif | ||
| 2560 | |||
| 2478 | if (r == 0) | 2561 | if (r == 0) |
| 2479 | return r; | 2562 | return r; |
| 2480 | if (!POSIX_CLOSE_RESTART || errno != EINTR) | 2563 | if (!POSIX_CLOSE_RESTART || errno != EINTR) |
| @@ -2729,6 +2812,15 @@ errwrite (void const *buf, ptrdiff_t nbuf) | |||
| 2729 | void | 2812 | void |
| 2730 | close_output_streams (void) | 2813 | close_output_streams (void) |
| 2731 | { | 2814 | { |
| 2815 | /* Android comes with some kind of ``file descriptor sanitizer'' | ||
| 2816 | that aborts when stdout or stderr is closed. */ | ||
| 2817 | |||
| 2818 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2819 | fflush (stderr); | ||
| 2820 | fflush (stdout); | ||
| 2821 | return; | ||
| 2822 | #endif | ||
| 2823 | |||
| 2732 | if (close_stream (stdout) != 0) | 2824 | if (close_stream (stdout) != 0) |
| 2733 | { | 2825 | { |
| 2734 | emacs_perror ("Write error to standard output"); | 2826 | emacs_perror ("Write error to standard output"); |
diff --git a/src/term.c b/src/term.c index f8104e0304e..05c54accdee 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -62,6 +62,8 @@ static int been_here = -1; | |||
| 62 | #include "w32term.h" | 62 | #include "w32term.h" |
| 63 | #endif | 63 | #endif |
| 64 | 64 | ||
| 65 | #ifndef HAVE_ANDROID | ||
| 66 | |||
| 65 | static void tty_set_scroll_region (struct frame *f, int start, int stop); | 67 | static void tty_set_scroll_region (struct frame *f, int start, int stop); |
| 66 | static void turn_on_face (struct frame *, int face_id); | 68 | static void turn_on_face (struct frame *, int face_id); |
| 67 | static void turn_off_face (struct frame *, int face_id); | 69 | static void turn_off_face (struct frame *, int face_id); |
| @@ -73,11 +75,15 @@ static void clear_tty_hooks (struct terminal *terminal); | |||
| 73 | static void set_tty_hooks (struct terminal *terminal); | 75 | static void set_tty_hooks (struct terminal *terminal); |
| 74 | static void dissociate_if_controlling_tty (int fd); | 76 | static void dissociate_if_controlling_tty (int fd); |
| 75 | static void delete_tty (struct terminal *); | 77 | static void delete_tty (struct terminal *); |
| 78 | |||
| 79 | #endif | ||
| 80 | |||
| 76 | static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *, | 81 | static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *, |
| 77 | ...) | 82 | ...) |
| 78 | ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5); | 83 | ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5); |
| 79 | static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); | 84 | static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); |
| 80 | 85 | ||
| 86 | #ifndef HAVE_ANDROID | ||
| 81 | 87 | ||
| 82 | #define OUTPUT(tty, a) \ | 88 | #define OUTPUT(tty, a) \ |
| 83 | emacs_tputs ((tty), a, \ | 89 | emacs_tputs ((tty), a, \ |
| @@ -95,6 +101,8 @@ static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); | |||
| 95 | 101 | ||
| 96 | #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0) | 102 | #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0) |
| 97 | 103 | ||
| 104 | #endif | ||
| 105 | |||
| 98 | /* Display space properties. */ | 106 | /* Display space properties. */ |
| 99 | 107 | ||
| 100 | /* Chain of all tty device parameters. */ | 108 | /* Chain of all tty device parameters. */ |
| @@ -117,10 +125,14 @@ enum no_color_bit | |||
| 117 | 125 | ||
| 118 | /* internal state */ | 126 | /* internal state */ |
| 119 | 127 | ||
| 128 | #ifndef HAVE_ANDROID | ||
| 129 | |||
| 120 | /* The largest frame width in any call to calculate_costs. */ | 130 | /* The largest frame width in any call to calculate_costs. */ |
| 121 | 131 | ||
| 122 | static int max_frame_cols; | 132 | static int max_frame_cols; |
| 123 | 133 | ||
| 134 | #endif | ||
| 135 | |||
| 124 | 136 | ||
| 125 | 137 | ||
| 126 | #ifdef HAVE_GPM | 138 | #ifdef HAVE_GPM |
| @@ -133,6 +145,8 @@ struct tty_display_info *gpm_tty = NULL; | |||
| 133 | static int last_mouse_x, last_mouse_y; | 145 | static int last_mouse_x, last_mouse_y; |
| 134 | #endif /* HAVE_GPM */ | 146 | #endif /* HAVE_GPM */ |
| 135 | 147 | ||
| 148 | #ifndef HAVE_ANDROID | ||
| 149 | |||
| 136 | /* Ring the bell on a tty. */ | 150 | /* Ring the bell on a tty. */ |
| 137 | 151 | ||
| 138 | static void | 152 | static void |
| @@ -718,7 +732,20 @@ encode_terminal_code (struct glyph *src, int src_len, | |||
| 718 | return (encode_terminal_dst); | 732 | return (encode_terminal_dst); |
| 719 | } | 733 | } |
| 720 | 734 | ||
| 735 | #else /* !HAVE_ANDROID */ | ||
| 736 | |||
| 737 | unsigned char * | ||
| 738 | encode_terminal_code (struct glyph *src, int src_len, | ||
| 739 | struct coding_system *coding) | ||
| 740 | { | ||
| 741 | /* Text terminals are simply not supported on Android. */ | ||
| 742 | coding->produced = 0; | ||
| 743 | return NULL; | ||
| 744 | } | ||
| 745 | |||
| 746 | #endif /* HAVE_ANDROID */ | ||
| 721 | 747 | ||
| 748 | #ifndef HAVE_ANDROID | ||
| 722 | 749 | ||
| 723 | /* An implementation of write_glyphs for termcap frames. */ | 750 | /* An implementation of write_glyphs for termcap frames. */ |
| 724 | 751 | ||
| @@ -1046,8 +1073,10 @@ int | |||
| 1046 | string_cost (const char *str) | 1073 | string_cost (const char *str) |
| 1047 | { | 1074 | { |
| 1048 | cost = 0; | 1075 | cost = 0; |
| 1076 | #ifndef HAVE_ANDROID | ||
| 1049 | if (str) | 1077 | if (str) |
| 1050 | tputs (str, 0, evalcost); | 1078 | tputs (str, 0, evalcost); |
| 1079 | #endif | ||
| 1051 | return cost; | 1080 | return cost; |
| 1052 | } | 1081 | } |
| 1053 | 1082 | ||
| @@ -1058,8 +1087,10 @@ static int | |||
| 1058 | string_cost_one_line (const char *str) | 1087 | string_cost_one_line (const char *str) |
| 1059 | { | 1088 | { |
| 1060 | cost = 0; | 1089 | cost = 0; |
| 1090 | #ifndef HAVE_ANDROID | ||
| 1061 | if (str) | 1091 | if (str) |
| 1062 | tputs (str, 1, evalcost); | 1092 | tputs (str, 1, evalcost); |
| 1093 | #endif | ||
| 1063 | return cost; | 1094 | return cost; |
| 1064 | } | 1095 | } |
| 1065 | 1096 | ||
| @@ -1070,11 +1101,13 @@ int | |||
| 1070 | per_line_cost (const char *str) | 1101 | per_line_cost (const char *str) |
| 1071 | { | 1102 | { |
| 1072 | cost = 0; | 1103 | cost = 0; |
| 1104 | #ifndef HAVE_ANDROID | ||
| 1073 | if (str) | 1105 | if (str) |
| 1074 | tputs (str, 0, evalcost); | 1106 | tputs (str, 0, evalcost); |
| 1075 | cost = - cost; | 1107 | cost = - cost; |
| 1076 | if (str) | 1108 | if (str) |
| 1077 | tputs (str, 10, evalcost); | 1109 | tputs (str, 10, evalcost); |
| 1110 | #endif | ||
| 1078 | return cost; | 1111 | return cost; |
| 1079 | } | 1112 | } |
| 1080 | 1113 | ||
| @@ -1147,11 +1180,14 @@ calculate_ins_del_char_costs (struct frame *f) | |||
| 1147 | *p++ = (ins_startup_cost += ins_cost_per_char); | 1180 | *p++ = (ins_startup_cost += ins_cost_per_char); |
| 1148 | } | 1181 | } |
| 1149 | 1182 | ||
| 1183 | #endif | ||
| 1184 | |||
| 1150 | void | 1185 | void |
| 1151 | calculate_costs (struct frame *frame) | 1186 | calculate_costs (struct frame *frame) |
| 1152 | { | 1187 | { |
| 1153 | FRAME_COST_BAUD_RATE (frame) = baud_rate; | 1188 | FRAME_COST_BAUD_RATE (frame) = baud_rate; |
| 1154 | 1189 | ||
| 1190 | #ifndef HAVE_ANDROID | ||
| 1155 | if (FRAME_TERMCAP_P (frame)) | 1191 | if (FRAME_TERMCAP_P (frame)) |
| 1156 | { | 1192 | { |
| 1157 | struct tty_display_info *tty = FRAME_TTY (frame); | 1193 | struct tty_display_info *tty = FRAME_TTY (frame); |
| @@ -1206,13 +1242,15 @@ calculate_costs (struct frame *frame) | |||
| 1206 | 1242 | ||
| 1207 | cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */ | 1243 | cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */ |
| 1208 | } | 1244 | } |
| 1245 | #endif | ||
| 1209 | } | 1246 | } |
| 1210 | 1247 | ||
| 1211 | struct fkey_table { | 1248 | struct fkey_table |
| 1249 | { | ||
| 1212 | const char *cap, *name; | 1250 | const char *cap, *name; |
| 1213 | }; | 1251 | }; |
| 1214 | 1252 | ||
| 1215 | #ifndef DOS_NT | 1253 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 1216 | /* Termcap capability names that correspond directly to X keysyms. | 1254 | /* Termcap capability names that correspond directly to X keysyms. |
| 1217 | Some of these (marked "terminfo") aren't supplied by old-style | 1255 | Some of these (marked "terminfo") aren't supplied by old-style |
| 1218 | (Berkeley) termcap entries. They're listed in X keysym order; | 1256 | (Berkeley) termcap entries. They're listed in X keysym order; |
| @@ -1443,6 +1481,9 @@ term_get_fkeys_1 (void) | |||
| 1443 | #endif /* not DOS_NT */ | 1481 | #endif /* not DOS_NT */ |
| 1444 | 1482 | ||
| 1445 | 1483 | ||
| 1484 | |||
| 1485 | #ifndef HAVE_ANDROID | ||
| 1486 | |||
| 1446 | /*********************************************************************** | 1487 | /*********************************************************************** |
| 1447 | Character Display Information | 1488 | Character Display Information |
| 1448 | ***********************************************************************/ | 1489 | ***********************************************************************/ |
| @@ -1519,14 +1560,17 @@ append_glyph (struct it *it) | |||
| 1519 | } | 1560 | } |
| 1520 | } | 1561 | } |
| 1521 | 1562 | ||
| 1563 | #endif | ||
| 1564 | |||
| 1522 | /* For external use. */ | 1565 | /* For external use. */ |
| 1523 | void | 1566 | void |
| 1524 | tty_append_glyph (struct it *it) | 1567 | tty_append_glyph (struct it *it) |
| 1525 | { | 1568 | { |
| 1569 | #ifndef HAVE_ANDROID | ||
| 1526 | append_glyph (it); | 1570 | append_glyph (it); |
| 1571 | #endif | ||
| 1527 | } | 1572 | } |
| 1528 | 1573 | ||
| 1529 | |||
| 1530 | /* Produce glyphs for the display element described by IT. *IT | 1574 | /* Produce glyphs for the display element described by IT. *IT |
| 1531 | specifies what we want to produce a glyph for (character, image, ...), | 1575 | specifies what we want to produce a glyph for (character, image, ...), |
| 1532 | and where in the glyph matrix we currently are (glyph row and hpos). | 1576 | and where in the glyph matrix we currently are (glyph row and hpos). |
| @@ -1549,6 +1593,7 @@ tty_append_glyph (struct it *it) | |||
| 1549 | void | 1593 | void |
| 1550 | produce_glyphs (struct it *it) | 1594 | produce_glyphs (struct it *it) |
| 1551 | { | 1595 | { |
| 1596 | #ifndef HAVE_ANDROID | ||
| 1552 | /* If a hook is installed, let it do the work. */ | 1597 | /* If a hook is installed, let it do the work. */ |
| 1553 | 1598 | ||
| 1554 | /* Nothing but characters are supported on terminal frames. */ | 1599 | /* Nothing but characters are supported on terminal frames. */ |
| @@ -1661,8 +1706,11 @@ produce_glyphs (struct it *it) | |||
| 1661 | it->current_x += it->pixel_width; | 1706 | it->current_x += it->pixel_width; |
| 1662 | it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0; | 1707 | it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0; |
| 1663 | it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1; | 1708 | it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1; |
| 1709 | #endif | ||
| 1664 | } | 1710 | } |
| 1665 | 1711 | ||
| 1712 | #ifndef HAVE_ANDROID | ||
| 1713 | |||
| 1666 | /* Append glyphs to IT's glyph_row for the composition IT->cmp_id. | 1714 | /* Append glyphs to IT's glyph_row for the composition IT->cmp_id. |
| 1667 | Called from produce_composite_glyph for terminal frames if | 1715 | Called from produce_composite_glyph for terminal frames if |
| 1668 | IT->glyph_row != NULL. IT->face_id contains the character's | 1716 | IT->glyph_row != NULL. IT->face_id contains the character's |
| @@ -2020,6 +2068,7 @@ turn_off_face (struct frame *f, int face_id) | |||
| 2020 | OUTPUT1_IF (tty, tty->TS_orig_pair); | 2068 | OUTPUT1_IF (tty, tty->TS_orig_pair); |
| 2021 | } | 2069 | } |
| 2022 | 2070 | ||
| 2071 | #endif /* !HAVE_ANDROID */ | ||
| 2023 | 2072 | ||
| 2024 | /* Return true if the terminal on frame F supports all of the | 2073 | /* Return true if the terminal on frame F supports all of the |
| 2025 | capabilities in CAPS simultaneously. */ | 2074 | capabilities in CAPS simultaneously. */ |
| @@ -2027,8 +2076,9 @@ turn_off_face (struct frame *f, int face_id) | |||
| 2027 | bool | 2076 | bool |
| 2028 | tty_capable_p (struct tty_display_info *tty, unsigned int caps) | 2077 | tty_capable_p (struct tty_display_info *tty, unsigned int caps) |
| 2029 | { | 2078 | { |
| 2079 | #ifndef HAVE_ANDROID | ||
| 2030 | #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ | 2080 | #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ |
| 2031 | if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \ | 2081 | if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P (tty, NC_bit))) \ |
| 2032 | return 0; | 2082 | return 0; |
| 2033 | 2083 | ||
| 2034 | TTY_CAPABLE_P_TRY (tty, | 2084 | TTY_CAPABLE_P_TRY (tty, |
| @@ -2048,6 +2098,9 @@ tty_capable_p (struct tty_display_info *tty, unsigned int caps) | |||
| 2048 | 2098 | ||
| 2049 | /* We can do it! */ | 2099 | /* We can do it! */ |
| 2050 | return 1; | 2100 | return 1; |
| 2101 | #else | ||
| 2102 | return false; | ||
| 2103 | #endif | ||
| 2051 | } | 2104 | } |
| 2052 | 2105 | ||
| 2053 | /* Return non-zero if the terminal is capable to display colors. */ | 2106 | /* Return non-zero if the terminal is capable to display colors. */ |
| @@ -2081,7 +2134,7 @@ TERMINAL does not refer to a text terminal. */) | |||
| 2081 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); | 2134 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); |
| 2082 | } | 2135 | } |
| 2083 | 2136 | ||
| 2084 | #ifndef DOS_NT | 2137 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 2085 | 2138 | ||
| 2086 | /* Declare here rather than in the function, as in the rest of Emacs, | 2139 | /* Declare here rather than in the function, as in the rest of Emacs, |
| 2087 | to work around an HPUX compiler bug (?). See | 2140 | to work around an HPUX compiler bug (?). See |
| @@ -2186,7 +2239,7 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f) | |||
| 2186 | } | 2239 | } |
| 2187 | } | 2240 | } |
| 2188 | 2241 | ||
| 2189 | #endif /* !DOS_NT */ | 2242 | #endif /* !DOS_NT && !HAVE_ANDROID */ |
| 2190 | 2243 | ||
| 2191 | char * | 2244 | char * |
| 2192 | tty_type_name (Lisp_Object terminal) | 2245 | tty_type_name (Lisp_Object terminal) |
| @@ -2278,6 +2331,7 @@ suspended. | |||
| 2278 | A suspended tty may be resumed by calling `resume-tty' on it. */) | 2331 | A suspended tty may be resumed by calling `resume-tty' on it. */) |
| 2279 | (Lisp_Object tty) | 2332 | (Lisp_Object tty) |
| 2280 | { | 2333 | { |
| 2334 | #ifndef HAVE_ANDROID | ||
| 2281 | struct terminal *t = decode_tty_terminal (tty); | 2335 | struct terminal *t = decode_tty_terminal (tty); |
| 2282 | FILE *f; | 2336 | FILE *f; |
| 2283 | 2337 | ||
| @@ -2314,6 +2368,10 @@ A suspended tty may be resumed by calling `resume-tty' on it. */) | |||
| 2314 | 2368 | ||
| 2315 | /* Clear display hooks to prevent further output. */ | 2369 | /* Clear display hooks to prevent further output. */ |
| 2316 | clear_tty_hooks (t); | 2370 | clear_tty_hooks (t); |
| 2371 | #else | ||
| 2372 | /* This will always signal on Android. */ | ||
| 2373 | decode_tty_terminal (tty); | ||
| 2374 | #endif | ||
| 2317 | 2375 | ||
| 2318 | return Qnil; | 2376 | return Qnil; |
| 2319 | } | 2377 | } |
| @@ -2337,9 +2395,12 @@ TTY may be a terminal object, a frame, or nil (meaning the selected | |||
| 2337 | frame's terminal). */) | 2395 | frame's terminal). */) |
| 2338 | (Lisp_Object tty) | 2396 | (Lisp_Object tty) |
| 2339 | { | 2397 | { |
| 2340 | struct terminal *t = decode_tty_terminal (tty); | 2398 | #ifndef HAVE_ANDROID |
| 2399 | struct terminal *t; | ||
| 2341 | int fd; | 2400 | int fd; |
| 2342 | 2401 | ||
| 2402 | t = decode_tty_terminal (tty); | ||
| 2403 | |||
| 2343 | if (!t) | 2404 | if (!t) |
| 2344 | error ("Attempt to resume a non-text terminal device"); | 2405 | error ("Attempt to resume a non-text terminal device"); |
| 2345 | 2406 | ||
| @@ -2396,10 +2457,15 @@ frame's terminal). */) | |||
| 2396 | } | 2457 | } |
| 2397 | 2458 | ||
| 2398 | set_tty_hooks (t); | 2459 | set_tty_hooks (t); |
| 2460 | #else | ||
| 2461 | decode_tty_terminal (tty); | ||
| 2462 | #endif | ||
| 2399 | 2463 | ||
| 2400 | return Qnil; | 2464 | return Qnil; |
| 2401 | } | 2465 | } |
| 2402 | 2466 | ||
| 2467 | #ifndef HAVE_ANDROID | ||
| 2468 | |||
| 2403 | DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size, | 2469 | DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size, |
| 2404 | Stty__set_output_buffer_size, 1, 2, 0, doc: | 2470 | Stty__set_output_buffer_size, 1, 2, 0, doc: |
| 2405 | /* Set the output buffer size for a TTY. | 2471 | /* Set the output buffer size for a TTY. |
| @@ -2438,12 +2504,14 @@ A value of zero means TTY uses the system's default value. */) | |||
| 2438 | error ("Not a tty terminal"); | 2504 | error ("Not a tty terminal"); |
| 2439 | } | 2505 | } |
| 2440 | 2506 | ||
| 2507 | #endif | ||
| 2508 | |||
| 2441 | 2509 | ||
| 2442 | /*********************************************************************** | 2510 | /*********************************************************************** |
| 2443 | Mouse | 2511 | Mouse |
| 2444 | ***********************************************************************/ | 2512 | ***********************************************************************/ |
| 2445 | 2513 | ||
| 2446 | #ifndef DOS_NT | 2514 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 2447 | 2515 | ||
| 2448 | /* Implementation of draw_row_with_mouse_face for TTY/GPM and macOS. */ | 2516 | /* Implementation of draw_row_with_mouse_face for TTY/GPM and macOS. */ |
| 2449 | void | 2517 | void |
| @@ -2713,7 +2781,7 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, | |||
| 2713 | Menus | 2781 | Menus |
| 2714 | ***********************************************************************/ | 2782 | ***********************************************************************/ |
| 2715 | 2783 | ||
| 2716 | #if !defined (MSDOS) | 2784 | #if !defined (MSDOS) && !defined HAVE_ANDROID |
| 2717 | 2785 | ||
| 2718 | /* TTY menu implementation and main ideas are borrowed from msdos.c. | 2786 | /* TTY menu implementation and main ideas are borrowed from msdos.c. |
| 2719 | 2787 | ||
| @@ -3813,10 +3881,12 @@ tty_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 3813 | return SAFE_FREE_UNBIND_TO (specpdl_count, entry); | 3881 | return SAFE_FREE_UNBIND_TO (specpdl_count, entry); |
| 3814 | } | 3882 | } |
| 3815 | 3883 | ||
| 3816 | #endif /* !MSDOS */ | 3884 | #endif /* !MSDOS && !defined HAVE_ANDROID */ |
| 3817 | 3885 | ||
| 3818 | 3886 | ||
| 3819 | #ifndef MSDOS | 3887 | |
| 3888 | #if !defined MSDOS && !defined HAVE_ANDROID | ||
| 3889 | |||
| 3820 | /*********************************************************************** | 3890 | /*********************************************************************** |
| 3821 | Initialization | 3891 | Initialization |
| 3822 | ***********************************************************************/ | 3892 | ***********************************************************************/ |
| @@ -3846,7 +3916,7 @@ tty_free_frame_resources (struct frame *f) | |||
| 3846 | xfree (f->output_data.tty); | 3916 | xfree (f->output_data.tty); |
| 3847 | } | 3917 | } |
| 3848 | 3918 | ||
| 3849 | #else /* MSDOS */ | 3919 | #elif defined MSDOS |
| 3850 | 3920 | ||
| 3851 | /* Delete frame F's face cache. */ | 3921 | /* Delete frame F's face cache. */ |
| 3852 | 3922 | ||
| @@ -3856,8 +3926,13 @@ tty_free_frame_resources (struct frame *f) | |||
| 3856 | eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); | 3926 | eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); |
| 3857 | free_frame_faces (f); | 3927 | free_frame_faces (f); |
| 3858 | } | 3928 | } |
| 3859 | #endif /* MSDOS */ | 3929 | |
| 3930 | #endif | ||
| 3931 | |||
| 3860 | 3932 | ||
| 3933 | |||
| 3934 | #ifndef HAVE_ANDROID | ||
| 3935 | |||
| 3861 | /* Reset the hooks in TERMINAL. */ | 3936 | /* Reset the hooks in TERMINAL. */ |
| 3862 | 3937 | ||
| 3863 | static void | 3938 | static void |
| @@ -3952,6 +4027,8 @@ dissociate_if_controlling_tty (int fd) | |||
| 3952 | } | 4027 | } |
| 3953 | } | 4028 | } |
| 3954 | 4029 | ||
| 4030 | #endif /* !HAVE_ANDROID */ | ||
| 4031 | |||
| 3955 | /* Create a termcap display on the tty device with the given name and | 4032 | /* Create a termcap display on the tty device with the given name and |
| 3956 | type. | 4033 | type. |
| 3957 | 4034 | ||
| @@ -3961,11 +4038,23 @@ dissociate_if_controlling_tty (int fd) | |||
| 3961 | 4038 | ||
| 3962 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". | 4039 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". |
| 3963 | 4040 | ||
| 3964 | If MUST_SUCCEED is true, then all errors are fatal. */ | 4041 | If MUST_SUCCEED is true, then all errors are fatal. This function |
| 4042 | always signals on Android, where text terminals are prohibited by | ||
| 4043 | system policy (and the required libraries are usually not | ||
| 4044 | available.) */ | ||
| 4045 | |||
| 4046 | #ifdef HAVE_ANDROID | ||
| 4047 | _Noreturn | ||
| 4048 | #endif | ||
| 3965 | 4049 | ||
| 3966 | struct terminal * | 4050 | struct terminal * |
| 3967 | init_tty (const char *name, const char *terminal_type, bool must_succeed) | 4051 | init_tty (const char *name, const char *terminal_type, bool must_succeed) |
| 3968 | { | 4052 | { |
| 4053 | #ifdef HAVE_ANDROID | ||
| 4054 | maybe_fatal (must_succeed, 0, "Text terminals are not supported" | ||
| 4055 | " under Android", "Text terminals are not supported" | ||
| 4056 | " under Android"); | ||
| 4057 | #else | ||
| 3969 | struct tty_display_info *tty = NULL; | 4058 | struct tty_display_info *tty = NULL; |
| 3970 | struct terminal *terminal = NULL; | 4059 | struct terminal *terminal = NULL; |
| 3971 | #ifndef DOS_NT | 4060 | #ifndef DOS_NT |
| @@ -4447,6 +4536,7 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ | |||
| 4447 | init_sys_modes (tty); | 4536 | init_sys_modes (tty); |
| 4448 | 4537 | ||
| 4449 | return terminal; | 4538 | return terminal; |
| 4539 | #endif /* !HAVE_ANDROID */ | ||
| 4450 | } | 4540 | } |
| 4451 | 4541 | ||
| 4452 | 4542 | ||
| @@ -4471,8 +4561,13 @@ maybe_fatal (bool must_succeed, struct terminal *terminal, | |||
| 4471 | { | 4561 | { |
| 4472 | va_list ap; | 4562 | va_list ap; |
| 4473 | va_start (ap, str2); | 4563 | va_start (ap, str2); |
| 4564 | |||
| 4565 | #ifndef HAVE_ANDROID | ||
| 4474 | if (terminal) | 4566 | if (terminal) |
| 4475 | delete_tty (terminal); | 4567 | delete_tty (terminal); |
| 4568 | #else | ||
| 4569 | eassert (terminal == NULL); | ||
| 4570 | #endif | ||
| 4476 | 4571 | ||
| 4477 | if (must_succeed) | 4572 | if (must_succeed) |
| 4478 | vfatal (str2, ap); | 4573 | vfatal (str2, ap); |
| @@ -4490,6 +4585,8 @@ fatal (const char *str, ...) | |||
| 4490 | 4585 | ||
| 4491 | 4586 | ||
| 4492 | 4587 | ||
| 4588 | #ifndef HAVE_ANDROID | ||
| 4589 | |||
| 4493 | /* Delete the given tty terminal, closing all frames on it. */ | 4590 | /* Delete the given tty terminal, closing all frames on it. */ |
| 4494 | 4591 | ||
| 4495 | static void | 4592 | static void |
| @@ -4547,6 +4644,8 @@ delete_tty (struct terminal *terminal) | |||
| 4547 | xfree (tty); | 4644 | xfree (tty); |
| 4548 | } | 4645 | } |
| 4549 | 4646 | ||
| 4647 | #endif | ||
| 4648 | |||
| 4550 | void | 4649 | void |
| 4551 | syms_of_term (void) | 4650 | syms_of_term (void) |
| 4552 | { | 4651 | { |
| @@ -4594,21 +4693,25 @@ trigger redisplay. */); | |||
| 4594 | defsubr (&Stty_top_frame); | 4693 | defsubr (&Stty_top_frame); |
| 4595 | defsubr (&Ssuspend_tty); | 4694 | defsubr (&Ssuspend_tty); |
| 4596 | defsubr (&Sresume_tty); | 4695 | defsubr (&Sresume_tty); |
| 4696 | #ifndef HAVE_ANDROID | ||
| 4597 | defsubr (&Stty__set_output_buffer_size); | 4697 | defsubr (&Stty__set_output_buffer_size); |
| 4598 | defsubr (&Stty__output_buffer_size); | 4698 | defsubr (&Stty__output_buffer_size); |
| 4699 | #endif /* !HAVE_ANDROID */ | ||
| 4599 | #ifdef HAVE_GPM | 4700 | #ifdef HAVE_GPM |
| 4600 | defsubr (&Sgpm_mouse_start); | 4701 | defsubr (&Sgpm_mouse_start); |
| 4601 | defsubr (&Sgpm_mouse_stop); | 4702 | defsubr (&Sgpm_mouse_stop); |
| 4602 | #endif /* HAVE_GPM */ | 4703 | #endif /* HAVE_GPM */ |
| 4603 | 4704 | ||
| 4604 | #ifndef DOS_NT | 4705 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 4605 | default_orig_pair = NULL; | 4706 | default_orig_pair = NULL; |
| 4606 | default_set_foreground = NULL; | 4707 | default_set_foreground = NULL; |
| 4607 | default_set_background = NULL; | 4708 | default_set_background = NULL; |
| 4608 | #endif /* !DOS_NT */ | 4709 | #endif /* !DOS_NT && !HAVE_ANDROID */ |
| 4609 | 4710 | ||
| 4711 | #ifndef HAVE_ANDROID | ||
| 4610 | encode_terminal_src = NULL; | 4712 | encode_terminal_src = NULL; |
| 4611 | encode_terminal_dst = NULL; | 4713 | encode_terminal_dst = NULL; |
| 4714 | #endif | ||
| 4612 | 4715 | ||
| 4613 | DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings"); | 4716 | DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings"); |
| 4614 | DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings"); | 4717 | DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings"); |
diff --git a/src/termhooks.h b/src/termhooks.h index c5f1e286e92..ea2a1cc3301 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -63,7 +63,8 @@ enum output_method | |||
| 63 | output_w32, | 63 | output_w32, |
| 64 | output_ns, | 64 | output_ns, |
| 65 | output_pgtk, | 65 | output_pgtk, |
| 66 | output_haiku | 66 | output_haiku, |
| 67 | output_android, | ||
| 67 | }; | 68 | }; |
| 68 | 69 | ||
| 69 | /* Input queue declarations and hooks. */ | 70 | /* Input queue declarations and hooks. */ |
| @@ -516,12 +517,13 @@ struct terminal | |||
| 516 | /* Device-type dependent data shared amongst all frames on this terminal. */ | 517 | /* Device-type dependent data shared amongst all frames on this terminal. */ |
| 517 | union display_info | 518 | union display_info |
| 518 | { | 519 | { |
| 519 | struct tty_display_info *tty; /* termchar.h */ | 520 | struct tty_display_info *tty; /* termchar.h */ |
| 520 | struct x_display_info *x; /* xterm.h */ | 521 | struct x_display_info *x; /* xterm.h */ |
| 521 | struct w32_display_info *w32; /* w32term.h */ | 522 | struct w32_display_info *w32; /* w32term.h */ |
| 522 | struct ns_display_info *ns; /* nsterm.h */ | 523 | struct ns_display_info *ns; /* nsterm.h */ |
| 523 | struct pgtk_display_info *pgtk; /* pgtkterm.h */ | 524 | struct pgtk_display_info *pgtk; /* pgtkterm.h */ |
| 524 | struct haiku_display_info *haiku; /* haikuterm.h */ | 525 | struct haiku_display_info *haiku; /* haikuterm.h */ |
| 526 | struct android_display_info *android; /* androidterm.h */ | ||
| 525 | } display_info; | 527 | } display_info; |
| 526 | 528 | ||
| 527 | 529 | ||
| @@ -595,7 +597,8 @@ struct terminal | |||
| 595 | BGCOLOR. */ | 597 | BGCOLOR. */ |
| 596 | void (*query_frame_background_color) (struct frame *f, Emacs_Color *bgcolor); | 598 | void (*query_frame_background_color) (struct frame *f, Emacs_Color *bgcolor); |
| 597 | 599 | ||
| 598 | #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) || defined (HAVE_PGTK) | 600 | #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) || defined (HAVE_PGTK) \ |
| 601 | || defined (HAVE_ANDROID) | ||
| 599 | /* On frame F, translate pixel colors to RGB values for the NCOLORS | 602 | /* On frame F, translate pixel colors to RGB values for the NCOLORS |
| 600 | colors in COLORS. Use cached information, if available. */ | 603 | colors in COLORS. Use cached information, if available. */ |
| 601 | 604 | ||
| @@ -930,6 +933,9 @@ extern struct terminal *terminal_list; | |||
| 930 | #elif defined (HAVE_HAIKU) | 933 | #elif defined (HAVE_HAIKU) |
| 931 | #define TERMINAL_FONT_CACHE(t) \ | 934 | #define TERMINAL_FONT_CACHE(t) \ |
| 932 | (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil) | 935 | (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil) |
| 936 | #elif defined (HAVE_ANDROID) | ||
| 937 | #define TERMINAL_FONT_CACHE(t) \ | ||
| 938 | (t->type == output_android ? t->display_info.android->name_list_element : Qnil) | ||
| 933 | #endif | 939 | #endif |
| 934 | 940 | ||
| 935 | extern struct terminal *decode_live_terminal (Lisp_Object); | 941 | extern struct terminal *decode_live_terminal (Lisp_Object); |
diff --git a/src/terminal.c b/src/terminal.c index d366e9d2438..a0fe0fe5d3d 100644 --- a/src/terminal.c +++ b/src/terminal.c | |||
| @@ -451,6 +451,8 @@ return values. */) | |||
| 451 | return Qpgtk; | 451 | return Qpgtk; |
| 452 | case output_haiku: | 452 | case output_haiku: |
| 453 | return Qhaiku; | 453 | return Qhaiku; |
| 454 | case output_android: | ||
| 455 | return Qandroid; | ||
| 454 | default: | 456 | default: |
| 455 | emacs_abort (); | 457 | emacs_abort (); |
| 456 | } | 458 | } |
diff --git a/src/verbose.mk.in b/src/verbose.mk.in index 4ec7788442d..8d89c88c27a 100644 --- a/src/verbose.mk.in +++ b/src/verbose.mk.in | |||
| @@ -32,6 +32,10 @@ AM_V_GEN = | |||
| 32 | AM_V_GLOBALS = | 32 | AM_V_GLOBALS = |
| 33 | AM_V_NO_PD = | 33 | AM_V_NO_PD = |
| 34 | AM_V_RC = | 34 | AM_V_RC = |
| 35 | AM_V_JAVAC = | ||
| 36 | AM_V_DX = | ||
| 37 | AM_V_AAPT = | ||
| 38 | AM_V_ZIPALIGN = | ||
| 35 | else | 39 | else |
| 36 | 40 | ||
| 37 | # Whether $(info ...) works. This is to work around a bug in GNU Make | 41 | # Whether $(info ...) works. This is to work around a bug in GNU Make |
| @@ -76,4 +80,8 @@ AM_V_GEN = @$(info $ GEN $@) | |||
| 76 | AM_V_GLOBALS = @$(info $ GEN globals.h) | 80 | AM_V_GLOBALS = @$(info $ GEN globals.h) |
| 77 | AM_V_NO_PD = --no-print-directory | 81 | AM_V_NO_PD = --no-print-directory |
| 78 | AM_V_RC = @$(info $ RC $@) | 82 | AM_V_RC = @$(info $ RC $@) |
| 83 | |||
| 84 | # These are used for the Android port. | ||
| 85 | AM_V_JAVAC = @$(info $ JAVAC $@) | ||
| 86 | AM_V_DX = @$(info $ DX $@) | ||
| 79 | endif | 87 | endif |
diff --git a/src/xdisp.c b/src/xdisp.c index e8df230ef89..cc4c60f02da 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -16415,7 +16415,7 @@ redisplay_internal (void) | |||
| 16415 | display area, displaying a different frame means redisplay | 16415 | display area, displaying a different frame means redisplay |
| 16416 | the whole thing. */ | 16416 | the whole thing. */ |
| 16417 | SET_FRAME_GARBAGED (sf); | 16417 | SET_FRAME_GARBAGED (sf); |
| 16418 | #ifndef DOS_NT | 16418 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 16419 | set_tty_color_mode (FRAME_TTY (sf), sf); | 16419 | set_tty_color_mode (FRAME_TTY (sf), sf); |
| 16420 | #endif | 16420 | #endif |
| 16421 | FRAME_TTY (sf)->previous_frame = sf; | 16421 | FRAME_TTY (sf)->previous_frame = sf; |
| @@ -26320,7 +26320,7 @@ display_menu_bar (struct window *w) | |||
| 26320 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); | 26320 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); |
| 26321 | it.first_visible_x = 0; | 26321 | it.first_visible_x = 0; |
| 26322 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); | 26322 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); |
| 26323 | #elif defined (HAVE_X_WINDOWS) /* X without toolkit. */ | 26323 | #elif defined (HAVE_X_WINDOWS) || defined (HAVE_ANDROID) |
| 26324 | struct window *menu_window = NULL; | 26324 | struct window *menu_window = NULL; |
| 26325 | struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); | 26325 | struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); |
| 26326 | 26326 | ||
| @@ -26390,7 +26390,11 @@ display_menu_bar (struct window *w) | |||
| 26390 | it.glyph_row->truncated_on_left_p = false; | 26390 | it.glyph_row->truncated_on_left_p = false; |
| 26391 | it.glyph_row->truncated_on_right_p = false; | 26391 | it.glyph_row->truncated_on_right_p = false; |
| 26392 | 26392 | ||
| 26393 | #if defined (HAVE_X_WINDOWS) && !defined (USE_X_TOOLKIT) && !defined (USE_GTK) | 26393 | /* This will break the moment someone tries to add another window |
| 26394 | system that uses the no toolkit menu bar. Oh well. At least | ||
| 26395 | there will be an error, meaning he will correct the ifdef inside | ||
| 26396 | which `face' is defined. */ | ||
| 26397 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR | ||
| 26394 | /* Make a 3D menu bar have a shadow at its right end. */ | 26398 | /* Make a 3D menu bar have a shadow at its right end. */ |
| 26395 | extend_face_to_end_of_line (&it); | 26399 | extend_face_to_end_of_line (&it); |
| 26396 | if (face->box != FACE_NO_BOX) | 26400 | if (face->box != FACE_NO_BOX) |
| @@ -26431,6 +26435,11 @@ display_menu_bar (struct window *w) | |||
| 26431 | #endif | 26435 | #endif |
| 26432 | } | 26436 | } |
| 26433 | 26437 | ||
| 26438 | /* This code is never used on Android where there are only GUI and | ||
| 26439 | initial frames. */ | ||
| 26440 | |||
| 26441 | #ifndef HAVE_ANDROID | ||
| 26442 | |||
| 26434 | /* Deep copy of a glyph row, including the glyphs. */ | 26443 | /* Deep copy of a glyph row, including the glyphs. */ |
| 26435 | static void | 26444 | static void |
| 26436 | deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) | 26445 | deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) |
| @@ -26551,6 +26560,9 @@ display_tty_menu_item (const char *item_text, int width, int face_id, | |||
| 26551 | row->full_width_p = saved_width; | 26560 | row->full_width_p = saved_width; |
| 26552 | row->reversed_p = saved_reversed; | 26561 | row->reversed_p = saved_reversed; |
| 26553 | } | 26562 | } |
| 26563 | |||
| 26564 | #endif | ||
| 26565 | |||
| 26554 | 26566 | ||
| 26555 | /*********************************************************************** | 26567 | /*********************************************************************** |
| 26556 | Mode Line | 26568 | Mode Line |
| @@ -33432,7 +33444,9 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row, | |||
| 33432 | } | 33444 | } |
| 33433 | #endif | 33445 | #endif |
| 33434 | 33446 | ||
| 33447 | #ifndef HAVE_ANDROID | ||
| 33435 | tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); | 33448 | tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); |
| 33449 | #endif | ||
| 33436 | } | 33450 | } |
| 33437 | 33451 | ||
| 33438 | /* Display the active region described by mouse_face_* according to DRAW. */ | 33452 | /* Display the active region described by mouse_face_* according to DRAW. */ |
| @@ -36104,14 +36118,10 @@ expose_frame (struct frame *f, int x, int y, int w, int h) | |||
| 36104 | |= expose_window (XWINDOW (f->tool_bar_window), &r); | 36118 | |= expose_window (XWINDOW (f->tool_bar_window), &r); |
| 36105 | #endif | 36119 | #endif |
| 36106 | 36120 | ||
| 36107 | #ifdef HAVE_X_WINDOWS | 36121 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 36108 | #ifndef MSDOS | ||
| 36109 | #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | ||
| 36110 | if (WINDOWP (f->menu_bar_window)) | 36122 | if (WINDOWP (f->menu_bar_window)) |
| 36111 | mouse_face_overwritten_p | 36123 | mouse_face_overwritten_p |
| 36112 | |= expose_window (XWINDOW (f->menu_bar_window), &r); | 36124 | |= expose_window (XWINDOW (f->menu_bar_window), &r); |
| 36113 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ | ||
| 36114 | #endif | ||
| 36115 | #endif | 36125 | #endif |
| 36116 | 36126 | ||
| 36117 | /* Some window managers support a focus-follows-mouse style with | 36127 | /* Some window managers support a focus-follows-mouse style with |
diff --git a/src/xfaces.c b/src/xfaces.c index 663386dc25b..0f85a753393 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -254,6 +254,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 254 | #ifdef HAVE_HAIKU | 254 | #ifdef HAVE_HAIKU |
| 255 | #define GCGraphicsExposures 0 | 255 | #define GCGraphicsExposures 0 |
| 256 | #endif /* HAVE_HAIKU */ | 256 | #endif /* HAVE_HAIKU */ |
| 257 | |||
| 258 | #ifdef HAVE_ANDROID | ||
| 259 | #define GCGraphicsExposures 0 | ||
| 260 | #endif /* HAVE_ANDROID */ | ||
| 257 | #endif /* HAVE_WINDOW_SYSTEM */ | 261 | #endif /* HAVE_WINDOW_SYSTEM */ |
| 258 | 262 | ||
| 259 | #include "buffer.h" | 263 | #include "buffer.h" |
| @@ -607,6 +611,39 @@ x_free_gc (struct frame *f, Emacs_GC *gc) | |||
| 607 | } | 611 | } |
| 608 | #endif /* HAVE_NS */ | 612 | #endif /* HAVE_NS */ |
| 609 | 613 | ||
| 614 | #ifdef HAVE_ANDROID | ||
| 615 | |||
| 616 | /* Android real GCs. */ | ||
| 617 | |||
| 618 | static struct android_gc * | ||
| 619 | x_create_gc (struct frame *f, unsigned long value_mask, | ||
| 620 | Emacs_GC *xgcv) | ||
| 621 | { | ||
| 622 | struct android_gc_values gcv; | ||
| 623 | unsigned long mask; | ||
| 624 | |||
| 625 | gcv.foreground = xgcv->foreground; | ||
| 626 | gcv.background = xgcv->background; | ||
| 627 | |||
| 628 | mask = 0; | ||
| 629 | |||
| 630 | if (value_mask & GCForeground) | ||
| 631 | mask |= ANDROID_GC_FOREGROUND; | ||
| 632 | |||
| 633 | if (value_mask & GCBackground) | ||
| 634 | mask |= ANDROID_GC_BACKGROUND; | ||
| 635 | |||
| 636 | return android_create_gc (mask, &gcv); | ||
| 637 | } | ||
| 638 | |||
| 639 | static void | ||
| 640 | x_free_gc (struct frame *f, struct android_gc *gc) | ||
| 641 | { | ||
| 642 | android_free_gc (gc); | ||
| 643 | } | ||
| 644 | |||
| 645 | #endif | ||
| 646 | |||
| 610 | /*********************************************************************** | 647 | /*********************************************************************** |
| 611 | Frames and faces | 648 | Frames and faces |
| 612 | ***********************************************************************/ | 649 | ***********************************************************************/ |
| @@ -6951,19 +6988,21 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) | |||
| 6951 | int num; | 6988 | int num; |
| 6952 | 6989 | ||
| 6953 | while (fgets (buf, sizeof (buf), fp) != NULL) | 6990 | while (fgets (buf, sizeof (buf), fp) != NULL) |
| 6954 | if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3) | 6991 | { |
| 6955 | { | 6992 | if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3) |
| 6993 | { | ||
| 6956 | #ifdef HAVE_NTGUI | 6994 | #ifdef HAVE_NTGUI |
| 6957 | int color = RGB (red, green, blue); | 6995 | int color = RGB (red, green, blue); |
| 6958 | #else | 6996 | #else |
| 6959 | int color = (red << 16) | (green << 8) | blue; | 6997 | int color = (red << 16) | (green << 8) | blue; |
| 6960 | #endif | 6998 | #endif |
| 6961 | char *name = buf + num; | 6999 | char *name = buf + num; |
| 6962 | ptrdiff_t len = strlen (name); | 7000 | ptrdiff_t len = strlen (name); |
| 6963 | len -= 0 < len && name[len - 1] == '\n'; | 7001 | len -= 0 < len && name[len - 1] == '\n'; |
| 6964 | cmap = Fcons (Fcons (make_string (name, len), make_fixnum (color)), | 7002 | cmap = Fcons (Fcons (make_string (name, len), make_fixnum (color)), |
| 6965 | cmap); | 7003 | cmap); |
| 6966 | } | 7004 | } |
| 7005 | } | ||
| 6967 | fclose (fp); | 7006 | fclose (fp); |
| 6968 | } | 7007 | } |
| 6969 | unblock_input (); | 7008 | unblock_input (); |
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 | |||
| 20 | top_srcdir = @top_srcdir@ | ||
| 21 | top_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 | |||
| 41 | LIB_SRCDIR = $(realpath $(top_srcdir)/lib) | ||
| 42 | LIB_TOP_SRCDIR = $(realpath $(top_srcdir)) | ||
| 43 | |||
| 44 | SRC_SRCDIR = $(realpath $(top_srcdir)/src) | ||
| 45 | SRC_TOP_SRCDIR = $(realpath $(top_srcdir)) | ||
| 46 | |||
| 47 | LIB_SRC_SRCDIR = $(realpath $(top_srcdir)/lib-src) | ||
| 48 | LIB_SRC_TOP_SRCDIR = $(realpath $(top_src)) | ||
| 49 | |||
| 50 | # This is a list of binaries to build and install in lib-src. | ||
| 51 | |||
| 52 | LIBSRC_BINARIES = lib-src/etags lib-src/ctags lib-src/emacsclient \ | ||
| 53 | lib-src/ebrowse lib-src/hexl lib-src/movemail | ||
| 54 | |||
| 55 | CLEAN_SUBDIRS=lib src lib-src | ||
| 56 | |||
| 57 | .PHONY: all | ||
| 58 | all: 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. | ||
| 64 | config.status: | ||
| 65 | touch config.status | ||
| 66 | |||
| 67 | src/verbose.mk: verbose.mk.android | ||
| 68 | mkdir -p src | ||
| 69 | cp -f verbose.mk.android src/verbose.mk | ||
| 70 | |||
| 71 | UGLY_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 | |||
| 93 | PRE_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 | ||
| 98 | lib/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 | |||
| 130 | src/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 | ||
| 150 | src/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 | |||
| 171 | lib-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 | ||
| 206 | clean: | ||
| 207 | rm -rf $(CLEAN_SUBDIRS) *.bak sys | ||
| 208 | |||
| 209 | maintainer-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 @@ | |||
| 1 | This directory holds Makefiles and other required assets to build an | ||
| 2 | Emacs binary independently for another toolchain, which is currently | ||
| 3 | required when building for Android. | ||
| 4 | |||
| 5 | The files here are extremely ugly, and contain rules that cannot be | ||
| 6 | interrupted without leaving the build tree in an unsafe state. At | ||
| 7 | some 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 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #define nl_langinfo(ignore) "ASCII" | ||