aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2022-12-31 18:04:18 +0800
committerPo Lu2022-12-31 18:04:18 +0800
commitcfbc8a5dbcd362b69b37b4e6832ae4a31834364c (patch)
treece003d03c4ae98f4e1d02186d78e5ae6e0d36e55 /java
parent785095c416f9bae43d2947849282b814e2c7942e (diff)
downloademacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.tar.gz
emacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.zip
Bring up the Android operating system and its window system
* .dir-locals.el (c-mode): Add ANDROID_EXPORT noise macro. * .gitignore: Add new files to ignore. * Makefile.in: Adjust for Android. * admin/merge-gnulib: Add new warning. * configure.ac: Detect Android. Run cross-configuration for Android when appropriate. * etc/DEBUG: Document how to debug Emacs on Android. * java/AndroidManifest.xml: * java/Makefile.in: * java/README: * java/debug.sh: * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): * java/org/gnu/emacs/EmacsApplication.java (EmacsApplication): * java/org/gnu/emacs/EmacsCopyArea.java (EmacsCopyArea): * java/org/gnu/emacs/EmacsDrawLine.java (EmacsDrawLine): * java/org/gnu/emacs/EmacsDrawPoint.java (EmacsDrawPoint): * java/org/gnu/emacs/EmacsDrawRectangle.java (EmacsDrawRectangle): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (EmacsFillPolygon): * java/org/gnu/emacs/EmacsFillRectangle.java (EmacsFillRectangle): * java/org/gnu/emacs/EmacsFontDriver.java (EmacsFontDriver): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsHandleObject.java (EmacsHandleObject): * java/org/gnu/emacs/EmacsNative.java (EmacsNative): * java/org/gnu/emacs/EmacsPaintQueue.java (EmacsPaintQueue): * java/org/gnu/emacs/EmacsPaintReq.java (EmacsPaintReq): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (EmacsSdk7FontDriver): * java/org/gnu/emacs/EmacsService.java (class Holder<T>) (EmacsService): * java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView): * java/org/gnu/emacs/EmacsThread.java (EmacsThread): * java/org/gnu/emacs/EmacsView.java (EmacsView): * java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): New files and classes. * lib-src/Makefile.in (srcdir): * lib/Makefile.in (VPATH): (HAVE_NATIVE_COMP): (libgnu_a_SOURCES): (DEPFLAGS): Configure correctly for cross-compiling. * lib/faccessat.c: * lib/fpending.c (__fpending): * lib/open.c: * lib/unistd.c (_GL_UNISTD_INLINE): Temporary adjustments to gnulib. * lisp/frame.el (display-graphic-p): (display-screens): (display-pixel-height): (display-pixel-width): (display-mm-height): (display-mm-width): (display-backing-store): (display-save-under): (display-planes): (display-color-cells): (display-visual-class): Adjust for new window system `android'. * lisp/image/wallpaper.el (x-open-connection): Add declaration. * lisp/loadup.el (featurep): Load up files for Android. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Adjust faces for android. * lisp/term/android-win.el: New file. * src/Makefile.in: Add new targets emacs.so and android-emacs, then adjust for cross compilation. * src/alloc.c (cleanup_vector): Clean up Android font entities as well. (garbage_collect): Mark androidterm. * src/android-emacs.c (main): * src/android.c (ANDROID_THROW, enum android_fd_table_entry_flags) (struct android_emacs_service, struct android_emacs_pixmap) (struct android_graphics_point, struct android_event_container) (struct android_event_queue, android_run_select_thread) (android_handle_sigusr1, android_init_events, android_pending) (android_next_event, android_write_event, android_select) (android_run_debug_thread, android_user_full_name) (android_get_asset_name, android_fstat, android_fstatat) (android_file_access_p, android_hack_asset_fd, android_open) (android_close, JNICALL, android_init_emacs_service) (android_init_emacs_pixmap, android_init_graphics_point) (MAX_HANDLE, struct android_handle_entry, android_alloc_id) (android_destroy_handle, android_resolve_handle) (android_resolve_handle2, android_change_window_attributes) (android_create_window, android_set_window_background) (android_destroy_window, android_init_android_rect_class) (android_init_emacs_gc_class, android_create_gc, android_free_gc) (android_change_gc, android_set_clip_rectangles) (android_reparent_window, android_lookup_method) (android_clear_window, android_map_window, android_unmap_window) (android_resize_window, android_move_window, android_swap_buffers) (android_get_gc_values, android_set_foreground) (android_fill_rectangle, android_create_pixmap_from_bitmap_data) (android_set_clip_mask, android_set_fill_style, android_copy_area) (android_free_pixmap, android_set_background, android_fill_polygon) (android_draw_rectangle, android_draw_point, android_draw_line) (android_create_pixmap, android_set_ts_origin, android_clear_area): * src/android.h (ANDROID_EXPORT): * src/androidfns.c (android_display_info_for_name) (check_android_display_info, check_x_display_info, gamma_correct) (android_defined_color, android_decode_color) (android_implicitly_set_name, android_explicitly_set_name) (android_set_tool_bar_lines, android_change_tool_bar_height) (android_set_tab_bar_lines, android_change_tab_bar_height) (android_set_scroll_bar_default_height) (android_set_scroll_bar_default_width, android_icon_verify) (android_icon, android_make_gc, android_free_gcs) (unwind_create_frame, do_unwind_create_frame) (android_default_font_parameter, android_create_frame_window) (Fx_create_frame, Fxw_color_defined_p, Fxw_color_values) (Fxw_display_color_p, Fx_display_grayscale_p) (Fx_display_pixel_width, Fx_display_pixel_height) (Fx_display_planes, Fx_display_color_cells, Fx_display_screens) (Fx_display_mm_width, Fx_display_mm_height) (Fx_display_backing_store, Fx_display_visual_class) (Fx_display_monitor_attributes_list, Fx_frame_geometry) (Fx_frame_list_z_order, Fx_frame_restack) (Fx_mouse_absolute_pixel_position) (Fx_set_mouse_absolute_pixel_position, Fandroid_get_connection) (Fx_display_list, Fx_show_tip, Fx_hide_tip) (android_set_background_color, android_set_border_color) (android_set_cursor_color, android_set_cursor_type) (android_set_foreground_color) (android_set_child_frame_border_width) (android_set_internal_border_width, android_set_menu_bar_lines) (android_set_mouse_color, android_set_title, android_set_alpha) (android_frame_parm_handlers, syms_of_androidfns): * src/androidfont.c (struct android_emacs_font_driver) (struct android_emacs_font_spec, struct android_emacs_font_metrics) (struct android_emacs_font_object, struct android_integer) (struct androidfont_info, struct androidfont_entity) (android_init_font_driver, android_init_font_spec) (android_init_font_metrics, android_init_integer) (android_init_font_object, androidfont_get_cache) (androidfont_from_lisp, androidfont_from_java, androidfont_list) (androidfont_match, androidfont_draw, androidfont_open_font) (androidfont_close_font, androidfont_has_char) (androidfont_encode_char, androidfont_text_extents) (androidfont_list_family, androidfont_driver) (syms_of_androidfont_for_pdumper, syms_of_androidfont) (init_androidfont, android_finalize_font_entity): * src/androidgui.h (_ANDROID_GUI_H_, struct android_rectangle) (struct android_point, enum android_gc_function) (enum android_gc_value_mask, enum android_fill_style) (enum android_window_value_mask) (struct android_set_window_attributes, struct android_gc_values) (struct android_gc, enum android_swap_action, enum android_shape) (enum android_coord_mode, struct android_swap_info) (NativeRectangle, struct android_any_event) (struct android_key_event, struct android_configure_event) (union android_event): * src/androidterm.c (android_window_to_frame, android_clear_frame) (android_ring_bell, android_toggle_invisible_pointer) (android_update_begin, android_update_end, show_back_buffer) (android_flush_dirty_back_buffer_on, handle_one_android_event) (android_read_socket, android_frame_up_to_date) (android_buffer_flipping_unblocked_hook) (android_query_frame_background_color, android_parse_color) (android_alloc_nearest_color, android_query_colors) (android_mouse_position, android_get_focus_frame) (android_focus_frame, android_frame_rehighlight) (android_frame_raise_lower, android_make_frame_visible) (android_make_frame_invisible) (android_make_frame_visible_invisible, android_fullscreen_hook) (android_iconify_frame, android_set_window_size_1) (android_set_window_size, android_set_offset, android_set_alpha) (android_new_font, android_bitmap_icon, android_free_pixmap_hook) (android_free_frame_resources, android_delete_frame) (android_delete_terminal, android_scroll_run) (android_after_update_window_line, android_flip_and_flush) (android_clear_rectangle, android_reset_clip_rectangles) (android_clip_to_row, android_draw_fringe_bitmap) (android_set_cursor_gc, android_set_mouse_face_gc) (android_set_mode_line_face_gc, android_set_glyph_string_gc) (android_set_glyph_string_clipping) (android_set_glyph_string_clipping_exactly) (android_compute_glyph_string_overhangs) (android_clear_glyph_string_rect) (android_draw_glyph_string_background, android_fill_triangle) (android_make_point, android_inside_rect_p, android_clear_point) (android_draw_relief_rect, android_draw_box_rect) (HIGHLIGHT_COLOR_DARK_BOOST_LIMIT, android_setup_relief_color) (android_setup_relief_colors, android_draw_glyph_string_box) (android_draw_glyph_string_bg_rect, android_draw_image_relief) (android_draw_image_foreground, android_draw_image_foreground_1) (android_draw_image_glyph_string) (android_draw_stretch_glyph_string, android_draw_underwave) (android_draw_glyph_string_foreground) (android_draw_composite_glyph_string_foreground) (android_draw_glyphless_glyph_string_foreground) (android_draw_glyph_string, android_define_frame_cursor) (android_clear_frame_area, android_clear_under_internal_border) (android_draw_hollow_cursor, android_draw_bar_cursor) (android_draw_window_cursor, android_draw_vertical_window_border) (android_draw_window_divider, android_redisplay_interface) (frame_set_mouse_pixel_position, get_keysym_name) (android_create_terminal, android_term_init, syms_of_androidterm) (mark_androidterm): * src/androidterm.h (_ANDROID_TERM_H_, struct android_display_info) (struct android_output, FRAME_ANDROID_OUTPUT, XSCROLL_BAR): New files. * src/dired.c (file_attributes): Do not use openat on Android. * src/dispextern.h (No_Cursor): Define appropriately on Android. (struct glyph_string, struct face): Make gc field of type struct android_gc on Android. * src/dispnew.c (clear_current_matrices, clear_desired_matrices) (adjust_frame_glyphs_for_window_redisplay, free_glyphs) (update_frame, scrolling, char_ins_del_cost, update_frame_line) (init_display_interactive): Disable text terminal support completely on Android. Fix non-toolkit menus for non-X systems. * src/editfns.c (Fuser_full_name): Call android_user_full_name. * src/emacs.c (android_emacs_init): Make main this on Android. Prohibit argv sorting from exceeding end of argv. * src/epaths.in: Add path definitions for Android. * src/fileio.c (file_access_p): Call android_file_access_p. (file_name_directory): Avoid using openat on Android. (Fcopy_file): Adjust to call sys_fstat instead. (file_directory_p): (Finsert_file_contents): (write_region): Likewise. * src/filelock.c: * src/fns.c (Flocale_info): Pacify warning on Android. * src/font.c (font_make_entity_android): New function. * src/font.h: * src/frame.c (Fframep): (Fwindow_system): Handle new window system `android'. Update doc strings. (Fmake_terminal_frame): Disable on Android. (gui_display_get_resource): Disable get_string_resource_hook on Android. (syms_of_frame): New defsym `android'. * src/frame.h (GCALIGNED_STRUCT): Add new output data for Android. (ENUM_BF): Expand enumerator size. (FRAME_ANDROID_P, FRAME_WINDOW_P, MOUSE_HL_INFO): Add definitions for Android. * src/image.c (GET_PIXEL): (image_create_bitmap_from_file): (image_create_x_image_and_pixmap_1): (image_get_x_image): (slurp_file): (lookup_rgb_color): (image_to_emacs_colors): (image_from_emacs_colors): (image_pixmap_draw_cross): (image_disable_image): (MaskForeground): (gif_load): Add stubs for Android. * src/lisp.h: * src/lread.c (safe_to_load_version, maybe_swap_for_eln1, openp): * src/pdumper.c (pdumper_load): Call sys_fstat instead of fstat. * src/process.c (wait_reading_process_output): Use android_select instead of pselect. * src/scroll.c: Disable on Android. * src/sysdep.c (widen_foreground_group, reset_sys_modes) (init_signals, emacs_fstatat, sys_fstat): New function. (emacs_open, emacs_open_noquit, emacs_close): Implement differently on Android. (close_output_streams): Disable what is not required on Android. * src/term.c (OUTPUT1_IF, encode_terminal_code, string_cost) (string_cost_one_line, per_line_cost, calculate_costs) (struct fkey_table, tty_append_glyph, produce_glyphs) (tty_capable_p, Fsuspend_tty, Fresume_tty, device, init_tty) (maybe_fatal, syms_of_term): Disable text terminal support on Android. * src/termhooks.h (enum output_method): Add android output method. (GCALIGNED_STRUCT, TERMINAL_FONT_CACHE): Define for Android. * src/terminal.c (Fterminal_live_p): Implement for Android. * src/verbose.mk.in (AM_V_GLOBALS): Add JAVAC and DX. * src/xdisp.c (redisplay_internal): Disable text terminals on Android. (display_menu_bar): (display_tty_menu_item): (draw_row_with_mouse_face): (expose_frame): Make the non toolkit menu bar work on Android. * src/xfaces.c (GCGraphicsExposures): (x_create_gc): (x_free_gc): (Fx_load_color_file): Define for Android. * xcompile/Makefile.in (top_srcdir): (top_builddir): * xcompile/README: * xcompile/langinfo.h (nl_langinfo): New files.
Diffstat (limited to 'java')
-rw-r--r--java/AndroidManifest.xml54
-rw-r--r--java/Makefile.in150
-rw-r--r--java/README6
-rwxr-xr-xjava/debug.sh242
-rw-r--r--java/emacs.keystorebin0 -> 2776 bytes
-rw-r--r--java/org/gnu/emacs/EmacsActivity.java146
-rw-r--r--java/org/gnu/emacs/EmacsApplication.java27
-rw-r--r--java/org/gnu/emacs/EmacsCopyArea.java131
-rw-r--r--java/org/gnu/emacs/EmacsDrawLine.java137
-rw-r--r--java/org/gnu/emacs/EmacsDrawPoint.java30
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java127
-rw-r--r--java/org/gnu/emacs/EmacsDrawable.java33
-rw-r--r--java/org/gnu/emacs/EmacsFillPolygon.java150
-rw-r--r--java/org/gnu/emacs/EmacsFillRectangle.java129
-rw-r--r--java/org/gnu/emacs/EmacsFontDriver.java150
-rw-r--r--java/org/gnu/emacs/EmacsGC.java116
-rw-r--r--java/org/gnu/emacs/EmacsHandleObject.java62
-rw-r--r--java/org/gnu/emacs/EmacsNative.java72
-rw-r--r--java/org/gnu/emacs/EmacsPaintQueue.java138
-rw-r--r--java/org/gnu/emacs/EmacsPaintReq.java33
-rw-r--r--java/org/gnu/emacs/EmacsPixmap.java102
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java460
-rw-r--r--java/org/gnu/emacs/EmacsService.java384
-rw-r--r--java/org/gnu/emacs/EmacsSurfaceView.java83
-rw-r--r--java/org/gnu/emacs/EmacsThread.java44
-rw-r--r--java/org/gnu/emacs/EmacsView.java211
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java336
27 files changed, 3553 insertions, 0 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
new file mode 100644
index 00000000000..75aa5bdf409
--- /dev/null
+++ b/java/AndroidManifest.xml
@@ -0,0 +1,54 @@
1<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 package="org.gnu.emacs" android:installLocation="auto">
3
4 <!-- Paste in every permission in existence so Emacs can do
5 anything. -->
6
7 <uses-permission android:name="android.permission.READ_CONTACTS" />
8 <uses-permission android:name="android.permission.WRITE_CONTACTS" />
9 <uses-permission android:name="android.permission.VIBRATE" />
10 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
11 <uses-permission android:name="android.permission.INTERNET" />
12 <uses-permission android:name="android.permission.SET_WALLPAPER" />
13 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
14 <uses-permission android:name="android.permission.SEND_SMS" />
15 <uses-permission android:name="android.permission.RECEIVE_SMS" />
16 <uses-permission android:name="android.permission.RECEIVE_MMS"/>
17 <uses-permission android:name="android.permission.WRITE_SMS"/>
18 <uses-permission android:name="android.permission.READ_SMS"/>
19 <uses-permission android:name="android.permission.NFC" />
20 <uses-permission android:name="android.permission.TRANSMIT_IR" />
21 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
22 <uses-permission android:name="android.permission.WAKE_LOCK"/>
23 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
24 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
25 <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
26 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
27 <uses-permission android:name="android.permission.RECORD_AUDIO" />
28 <uses-permission android:name="android.permission.CAMERA" />
29
30 <uses-sdk android:minSdkVersion="7"
31 android:targetSdkVersion="28"/>
32
33 <application android:name="org.gnu.emacs.EmacsApplication"
34 android:label="GNU Emacs"
35 android:hardwareAccelerated="true"
36 android:supportsRtl="true"
37 android:theme="@android:style/Theme"
38 android:debuggable="true"
39 android:extractNativeLibs="true">
40 <activity android:name="org.gnu.emacs.EmacsActivity">
41 <intent-filter>
42 <action android:name="android.intent.action.MAIN" />
43 <category android:name="android.intent.category.DEFAULT" />
44 <category android:name="android.intent.category.LAUNCHER" />
45 </intent-filter>
46 </activity>
47
48 <service android:name="org.gnu.emacs.EmacsService"
49 android:directBootAware="false"
50 android:enabled="true"
51 android:exported="false"
52 android:label="GNU Emacs service"/>
53 </application>
54</manifest>
diff --git a/java/Makefile.in b/java/Makefile.in
new file mode 100644
index 00000000000..e9fcc625cb2
--- /dev/null
+++ b/java/Makefile.in
@@ -0,0 +1,150 @@
1### @configure_input@
2
3# Copyright (C) 2023 Free Software Foundation, Inc.
4
5# This file is part of GNU Emacs.
6
7# GNU Emacs is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11
12# GNU Emacs is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16
17# You should have received a copy of the GNU General Public License
18# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20top_builddir = @top_builddir@
21
22-include ${top_builddir}/src/verbose.mk
23
24SHELL = @SHELL@
25JAVAC = @JAVAC@
26AAPT = @AAPT@
27DX = @DX@
28ZIPALIGN = @ZIPALIGN@
29JARSIGNER = @JARSIGNER@
30ANDROID_JAR = @ANDROID_JAR@
31ANDROID_ABI = @ANDROID_ABI@
32
33WARN_JAVAFLAGS = -Xlint:deprecation
34JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
35 $(WARN_JAVAFLAGS)
36
37SIGN_EMACS = -keystore emacs.keystore -storepass emacs1
38
39JAVA_FILES = $(shell find . -type f -name *.java)
40CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
41
42# How this stuff works.
43
44# emacs.apk depends on emacs.apk-in, which is simply a ZIP archive
45# containing the following files:
46# lib/$(ANDROID_ABI)/libemacs.so
47# lib/$(ANDROID_ABI)/libandroid-emacs.so
48# lib/$(ANDROID_ABI)/libctags.so
49# lib/$(ANDROID_ABI)/libhexl.so
50# lib/$(ANDROID_ABI)/libmovemail.so
51# lib/$(ANDROID_ABI)/librcs2log.so
52# lib/$(ANDROID_ABI)/libebrowse.so
53# assets/info/
54# assets/etc/
55# assets/lisp/
56
57.PHONY: emacs.apk-in all
58all: emacs.apk
59
60# Binaries to cross-compile.
61CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \
62 ../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
63 ../xcompile/lib-src/ebrowse
64
65# Libraries to cross-compile.
66CROSS_LIBS = ../xcompile/src/libemacs.so
67
68.PHONY: $(CROSS_BINS) $(CROSS_LIBS)
69
70../xcompile/src/android-emacs ../xcompile/src/libemacs.so:
71 make -C ../xcompile src/$(notdir $@)
72
73../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
74../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
75 make -C ../xcompile lib-src/$(notdir $@)
76
77emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
78# Make the working directory for this stuff
79 rm -rf install_temp
80 mkdir -p install_temp/lib/$(ANDROID_ABI)
81 mkdir -p install_temp/assets/etc
82 mkdir -p install_temp/assets/lisp
83 mkdir -p install_temp/assets/info
84# Install architecture independents to assets/etc and assets/lisp
85 cp -r $(top_builddir)/lisp install_temp/assets
86 cp -r $(top_builddir)/etc install_temp/assets
87# Remove undesirable files from those directories.
88 for subdir in `find install_temp -type d -print`; do \
89 chmod a+rx $${subdir} ; \
90 rm -rf $${subdir}/.gitignore ; \
91 rm -rf $${subdir}/.DS_Store ; \
92 rm -rf $${subdir}/#* ; \
93 rm -rf $${subdir}/.#* ; \
94 rm -rf $${subdir}/*~ ; \
95 rm -rf $${subdir}/*.orig ; \
96 rm -rf $${subdir}/ChangeLog* ; \
97 rm -rf $${subdir}/[mM]akefile*[.-]in ; \
98 rm -rf $${subdir}/Makefile; \
99 done
100# Install architecture dependents to lib/$(ANDROID_ABI). This
101# perculiar naming scheme is required to make Android preserve these
102# binaries upon installation.
103 for file in $(CROSS_BINS); do \
104 if [ -x $$file ]; then \
105 filename=`basename $$file`; \
106 cp -f $$file install_temp/lib/$(ANDROID_ABI)/lib$${filename}.so; \
107 fi \
108 done
109 for file in $(CROSS_LIBS); do \
110 if [ -x $$file ]; then \
111 cp -f $$file install_temp/lib/$(ANDROID_ABI); \
112 fi \
113 done
114# Package everything.
115 $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml
116 pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
117 pushd install_temp; $(AAPT) add ../$@ `find assets -type f`; popd
118 rm -rf install_temp
119
120.SUFFIXES: .java .class
121.java.class &:
122 $(AM_V_JAVAC) $(JAVAC) $(JAVAFLAGS) $<
123
124# N.B. that find must be called all over again in case javac generated
125# nested classes.
126
127classes.dex: $(CLASS_FILES)
128 $(AM_V_DX) $(DX) --classpath $(ANDROID_JAR) \
129 $(subst $$,\$$,$(shell find . -type f -name *.class))
130
131# When emacs.keystore expires, regenerate it with:
132#
133# keytool -genkey -v -keystore emacs.keystore -alias "Emacs keystore" \
134# -keyalg RSA -sigalg SHA1withRSA -keysize 2048 -validity 100000
135
136.PHONY: clean maintainer-clean
137
138emacs.apk: classes.dex emacs.apk-in emacs.keystore
139 cp -f emacs.apk-in $@.unaligned
140 $(AAPT) add $@.unaligned classes.dex
141 $(JARSIGNER) $(SIGN_EMACS) $@.unaligned "Emacs keystore"
142 $(ZIPALIGN) -f 4 $@.unaligned $@
143 rm -f $@.unaligned
144
145clean:
146 rm -f emacs.apk emacs.apk-in *.dex *.unaligned *.class
147 rm -rf install-temp
148 find . -name '*.class' -delete
149
150maintainer-clean: clean
diff --git a/java/README b/java/README
new file mode 100644
index 00000000000..50c2332ce95
--- /dev/null
+++ b/java/README
@@ -0,0 +1,6 @@
1This directory holds the Java sources of the port of GNU Emacs to
2Android-like systems.
3
4Please keep the Java code indented with tabs and formatted according
5to the rules for C code in the GNU coding standards. Always use
6C-style comments.
diff --git a/java/debug.sh b/java/debug.sh
new file mode 100755
index 00000000000..dd710dc31af
--- /dev/null
+++ b/java/debug.sh
@@ -0,0 +1,242 @@
1#!/bin/bash
2### Run Emacs under GDB or JDB on Android.
3
4## Copyright (C) 2023 Free Software Foundation, Inc.
5
6## This file is part of GNU Emacs.
7
8## GNU Emacs is free software: you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation, either version 3 of the License, or
11## (at your option) any later version.
12
13## GNU Emacs is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16## GNU General Public License for more details.
17
18## You should have received a copy of the GNU General Public License
19## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
20
21set -m
22oldpwd=`pwd`
23cd `dirname $0`
24
25devices=`adb devices | grep device | awk -- '/device\y/ { print $1 }' -`
26device=
27progname=$0
28package=org.gnu.emacs
29activity=org.gnu.emacs.EmacsActivity
30gdb_port=5039
31jdb_port=64013
32jdb=no
33
34while [ $# -gt 0 ]; do
35 case "$1" in
36 ## This option specifies the serial number of a device to use.
37 "--device" )
38 device="$2"
39 if [ -z device ]; then
40 echo "You must specify an argument to --device"
41 exit 1
42 fi
43 ;;
44 "--help" )
45 echo "Usage: $progname [options] -- [gdb options]"
46 echo ""
47 echo " --device DEVICE run Emacs on the specified device"
48 echo " --port PORT run the GDB server on a specific port"
49 echo " --jdb-port PORT run the JDB server on a specific port"
50 echo " --jdb run JDB instead of GDB"
51 echo " --help print this message"
52 echo ""
53 echo "Available devices:"
54 for device in $devices; do
55 echo " " $device
56 done
57 echo ""
58 exit 0
59 ;;
60 "--jdb" )
61 jdb=yes
62 ;;
63 "--port" )
64 gdb_port=$1
65 ;;
66 "--" )
67 shift
68 gdbargs=$@
69 break;
70 ;;
71 * )
72 echo "$progname: Unrecognized argument $1"
73 exit 1
74 ;;
75 esac
76 shift
77done
78
79if [ -z $devices ]; then
80 echo "No devices are available."
81 exit 1
82fi
83
84if [ -z $device ]; then
85 device=$devices
86fi
87
88if [ `wc -w <<< "$devices"` -gt 1 ] && [ -z device ]; then
89 echo "Multiple devices are available. Please pick one using"
90 echo "--device and try again."
91fi
92
93echo "Looking for $package on device $device"
94
95# Find the application data directory
96app_data_dir=`adb -s $device shell run-as $package sh -c 'pwd 2> /dev/null'`
97
98if [ -z $app_data_dir ]; then
99 echo "The data directory for the package $package was not found."
100 echo "Is it installed?"
101fi
102
103echo "Found application data directory at $app_data_dir..."
104
105# Find which PIDs are associated with org.gnu.emacs
106package_uid=`adb -s $device shell run-as $package id -u`
107
108if [ -z $package_uid ]; then
109 echo "Failed to obtain UID of packages named $package"
110 exit 1
111fi
112
113# First, run ps -u $package_uid -o PID,CMD to fetch the list of
114# process IDs.
115package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
116
117# Next, remove lines matching "ps" itself.
118package_pids=`awk -- '{
119 if (!match ($0, /(PID|ps)/))
120 print $1
121}' <<< $package_pids`
122
123# Finally, kill each existing process.
124for pid in $package_pids; do
125 echo "Killing existing process $pid..."
126 adb -s $device shell run-as $package kill -9 $pid &> /dev/null
127done
128
129# Now run the main activity. This must be done as the adb user and
130# not as the package user.
131echo "Starting activity $activity and attaching debugger"
132
133# Exit if the activity could not be started.
134adb -s $device shell am start -D "$package/$activity"
135if [ ! $? ]; then
136 exit 1;
137fi
138
139# Now look for processes matching the package again.
140package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
141
142# Next, remove lines matching "ps" itself.
143package_pids=`awk -- '{
144 if (!match ($0, /(PID|ps)/))
145 print $1
146}' <<< $package_pids`
147
148pid=$package_pids
149num_pids=`wc -w <<< "$package_pids"`
150
151if [ $num_pids -gt 1 ]; then
152 echo "More than one process was started:"
153 echo ""
154 adb -s $device shell run-as $package ps -u $package_uid | awk -- '{
155 if (!match ($0, /ps/))
156 print $0
157 }'
158 echo ""
159 printf "Which one do you want to attach to? "
160 read pid
161elif [ -z $package_pids ]; then
162 echo "No processes were found to attach to."
163 exit 1
164fi
165
166# Start JDB to make the wait dialog disappear.
167echo "Attaching JDB to unblock the application."
168adb -s $device forward --remove-all
169adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
170
171if [ ! $? ]; then
172 echo "Failed to forward jdwp:$pid to $jdb_port!"
173 echo "Perhaps you need to specify a different port with --port?"
174 exit 1;
175fi
176
177jdb_command="jdb -connect \
178 com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
179
180if [ $jdb = "yes" ]; then
181 # Just start JDB and then exit
182 $jdb_command
183 exit 1
184fi
185
186exec 4<> /tmp/file-descriptor-stamp
187
188# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
189$jdb_command <&4 >&4 &
190
191character=
192# Next, wait until the prompt is found.
193while read -n1 -u 4 character; do
194 if [ "$character" = ">" ]; then
195 echo "JDB attached successfully"
196 break;
197 fi
198done
199
200# Now start gdbserver on the device asynchronously.
201
202echo "Attaching gdbserver to $pid on $device..."
203exec 5<> /tmp/file-descriptor-stamp
204adb -s $device shell run-as $package /system/bin/gdbserver --once \
205 "+debug.$package_uid.socket" --attach $pid >&5 &
206
207# Wait until gdbserver successfully runs.
208line=
209while read -u 5 line; do
210 case "$line" in
211 *Attached* )
212 break;
213 ;;
214 *error* | *Error* | failed )
215 echo $line
216 exit 1
217 ;;
218 * )
219 ;;
220 esac
221done
222
223# Send EOF to JDB to make it go away. This will also cause Android to
224# allow Emacs to continue executing.
225echo "Making JDB go away..."
226echo "exit" >&4
227read -u 4 line
228echo "JDB has gone away with $line"
229
230# Forward the gdb server port here.
231adb -s $device forward "tcp:$gdb_port" \
232 "localfilesystem:$app_data_dir/debug.$package_uid.socket"
233if [ ! $? ]; then
234 echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
235 echo "to $gdb_port! Perhaps you need to specify a different port"
236 echo "with --port?"
237 exit 1;
238fi
239
240# Finally, start gdb with any extra arguments needed.
241cd "$oldpwd"
242gdb --eval-command "" --eval-command "target remote localhost:$gdb_port" $gdbargs
diff --git a/java/emacs.keystore b/java/emacs.keystore
new file mode 100644
index 00000000000..76d80b6db65
--- /dev/null
+++ b/java/emacs.keystore
Binary files differ
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java
new file mode 100644
index 00000000000..cacd5f13e60
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -0,0 +1,146 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalStateException;
23import java.util.List;
24import java.util.ArrayList;
25
26import android.app.Activity;
27import android.content.Context;
28import android.content.Intent;
29import android.os.Bundle;
30import android.util.Log;
31import android.widget.FrameLayout;
32import android.widget.FrameLayout.LayoutParams;
33
34public class EmacsActivity extends Activity
35{
36 public static final String TAG = "EmacsActivity";
37
38 /* List of all activities that do not have an associated
39 EmacsWindow. */
40 public static List<EmacsActivity> availableActivities;
41
42 /* The currently attached EmacsWindow, or null if none. */
43 private EmacsWindow window;
44
45 /* The frame layout associated with the activity. */
46 private FrameLayout layout;
47
48 static
49 {
50 /* Set up the list of available activities. */
51 availableActivities = new ArrayList<EmacsActivity> ();
52 };
53
54 public void
55 attachChild (EmacsWindow child)
56 {
57 if (window != null)
58 throw new IllegalStateException ("trying to attach window when one"
59 + " already exists");
60
61 /* Record and attach the view. */
62 window = child;
63 layout.addView (window.view);
64
65 /* Remove the objects from the lists of what is available. */
66 EmacsService.availableChildren.remove (child);
67 availableActivities.remove (this);
68
69 /* Now set child->activity. */
70 child.setActivity (this);
71 }
72
73 /* Make this activity available for future windows to attach
74 again. */
75
76 public void
77 makeAvailable ()
78 {
79 window = null;
80
81 for (EmacsWindow iterWindow
82 : EmacsService.availableChildren)
83 {
84 synchronized (iterWindow)
85 {
86 if (!iterWindow.isDestroyed ())
87 attachChild (iterWindow);
88
89 return;
90 }
91 }
92
93 availableActivities.add (this);
94 }
95
96 @Override
97 public void
98 onCreate (Bundle savedInstanceState)
99 {
100 FrameLayout.LayoutParams params;
101
102 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
103 LayoutParams.MATCH_PARENT);
104
105 /* Make the frame layout. */
106 layout = new FrameLayout (this);
107 layout.setLayoutParams (params);
108
109 /* Set it as the content view. */
110 setContentView (layout);
111
112 /* Make the activity available before starting the
113 service. */
114 makeAvailable ();
115
116 if (EmacsService.SERVICE == null)
117 /* Start the Emacs service now. */
118 startService (new Intent (this, EmacsService.class));
119
120 super.onCreate (savedInstanceState);
121 }
122
123 @Override
124 public void
125 onStop ()
126 {
127 /* The activity is no longer visible. If there is a window
128 attached, detach it. */
129
130 if (window != null)
131 {
132 layout.removeView (window.view);
133
134 /* Notice that the window is already available too. But do
135 not call noticeAvailableChild; that might assign it to some
136 other activity, which behaves badly. */
137 EmacsService.availableChildren.add (window);
138 window = null;
139 }
140
141 /* Finally, remove this activity from the list of available
142 activities. */
143 availableActivities.remove (this);
144 super.onStop ();
145 }
146};
diff --git a/java/org/gnu/emacs/EmacsApplication.java b/java/org/gnu/emacs/EmacsApplication.java
new file mode 100644
index 00000000000..125da05cfd4
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsApplication.java
@@ -0,0 +1,27 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.app.Application;
23
24public class EmacsApplication extends Application
25{
26 /* This class currently does nothing. */
27};
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java
new file mode 100644
index 00000000000..f34d1ecde01
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsCopyArea.java
@@ -0,0 +1,131 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30public class EmacsCopyArea implements EmacsPaintReq
31{
32 private int src_x, src_y, dest_x, dest_y, width, height;
33 private EmacsDrawable destination, source;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu;
36
37 static
38 {
39 xorAlu = new PorterDuffXfermode (Mode.XOR);
40 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
41 };
42
43 public
44 EmacsCopyArea (EmacsDrawable destination, EmacsDrawable source,
45 int src_x, int src_y, int width, int height,
46 int dest_x, int dest_y, EmacsGC immutableGC)
47 {
48 this.destination = destination;
49 this.source = source;
50 this.src_x = src_x;
51 this.src_y = src_y;
52 this.width = width;
53 this.height = height;
54 this.dest_x = dest_x;
55 this.dest_y = dest_y;
56 this.immutableGC = immutableGC;
57 }
58
59 @Override
60 public Rect
61 getRect ()
62 {
63 return new Rect (dest_x, dest_y, dest_x + width,
64 dest_y + height);
65 }
66
67 @Override
68 public EmacsDrawable
69 getDrawable ()
70 {
71 return destination;
72 }
73
74 @Override
75 public EmacsGC
76 getGC ()
77 {
78 return immutableGC;
79 }
80
81 @Override
82 public void
83 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
84 {
85 int alu;
86 Bitmap bitmap;
87 Paint maskPaint;
88 Canvas maskCanvas;
89 Bitmap maskBitmap;
90 Rect rect, srcRect;
91
92 /* TODO implement stippling. */
93 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
94 return;
95
96 alu = immutableGC.function;
97 rect = getRect ();
98 bitmap = source.getBitmap ();
99
100 if (alu == EmacsGC.GC_COPY)
101 paint.setXfermode (null);
102 else
103 paint.setXfermode (xorAlu);
104
105 if (immutableGC.clip_mask == null)
106 canvas.drawBitmap (bitmap, new Rect (src_x, src_y,
107 src_x + width,
108 src_y + height),
109 rect, paint);
110 else
111 {
112 maskPaint = new Paint ();
113 srcRect = new Rect (0, 0, rect.width (),
114 rect.height ());
115 maskBitmap
116 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
117 true);
118
119 if (maskBitmap == null)
120 return;
121
122 maskPaint.setXfermode (srcInAlu);
123 maskCanvas = new Canvas (maskBitmap);
124 maskCanvas.drawBitmap (bitmap, new Rect (src_x, src_y,
125 src_x + width,
126 src_y + height),
127 srcRect, maskPaint);
128 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
129 }
130 }
131}
diff --git a/java/org/gnu/emacs/EmacsDrawLine.java b/java/org/gnu/emacs/EmacsDrawLine.java
new file mode 100644
index 00000000000..6389031bbfa
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -0,0 +1,137 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Math;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.PorterDuff.Mode;
28import android.graphics.PorterDuffXfermode;
29import android.graphics.Rect;
30import android.graphics.Xfermode;
31
32public class EmacsDrawLine implements EmacsPaintReq
33{
34 private int x, y, x2, y2;
35 private EmacsDrawable drawable;
36 private EmacsGC immutableGC;
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR);
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
43 };
44
45 public
46 EmacsDrawLine (EmacsDrawable drawable, int x, int y,
47 int x2, int y2, EmacsGC immutableGC)
48 {
49 this.drawable = drawable;
50 this.x = x;
51 this.y = y;
52 this.x2 = x2;
53 this.y2 = y2;
54 this.immutableGC = immutableGC;
55 }
56
57 @Override
58 public Rect
59 getRect ()
60 {
61 return new Rect (Math.min (x, x2 + 1),
62 Math.min (y, y2 + 1),
63 Math.max (x2 + 1, x),
64 Math.max (y2 + 1, y));
65 }
66
67 @Override
68 public EmacsDrawable
69 getDrawable ()
70 {
71 return drawable;
72 }
73
74 @Override
75 public EmacsGC
76 getGC ()
77 {
78 return immutableGC;
79 }
80
81 @Override
82 public void
83 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
84 {
85 int alu;
86 Paint maskPaint;
87 Canvas maskCanvas;
88 Bitmap maskBitmap;
89 Rect rect, srcRect;
90 int width, height;
91
92 /* TODO implement stippling. */
93 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
94 return;
95
96 alu = immutableGC.function;
97 rect = getRect ();
98 width = rect.width ();
99 height = rect.height ();
100
101 paint.setStyle (Paint.Style.STROKE);
102
103 if (alu == EmacsGC.GC_COPY)
104 paint.setXfermode (null);
105 else
106 paint.setXfermode (xorAlu);
107
108 if (immutableGC.clip_mask == null)
109 {
110 paint.setColor (immutableGC.foreground | 0xff000000);
111 canvas.drawLine ((float) x, (float) y,
112 (float) x2, (float) y2,
113 paint);
114 }
115 else
116 {
117 maskPaint = new Paint ();
118 maskBitmap
119 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
120 true);
121
122 if (maskBitmap == null)
123 return;
124
125 maskPaint.setXfermode (srcInAlu);
126 maskPaint.setColor (immutableGC.foreground | 0xff000000);
127 maskCanvas = new Canvas (maskBitmap);
128 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
129 maskBitmap.getHeight ());
130 maskCanvas.drawLine (0.0f, 0.0f, (float) Math.abs (x - x2),
131 (float) Math.abs (y - y2), maskPaint);
132 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
133 }
134
135 paint.setXfermode (null);
136 }
137}
diff --git a/java/org/gnu/emacs/EmacsDrawPoint.java b/java/org/gnu/emacs/EmacsDrawPoint.java
new file mode 100644
index 00000000000..772757ff424
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawPoint.java
@@ -0,0 +1,30 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22public class EmacsDrawPoint extends EmacsDrawRectangle
23{
24 public
25 EmacsDrawPoint (EmacsDrawable drawable, int x, int y,
26 EmacsGC immutableGC)
27 {
28 super (drawable, x, y, 1, 1, immutableGC);
29 }
30}
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
new file mode 100644
index 00000000000..462bf7c85b5
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -0,0 +1,127 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30public class EmacsDrawRectangle implements EmacsPaintReq
31{
32 private int x, y, width, height;
33 private EmacsDrawable drawable;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu;
36
37 static
38 {
39 xorAlu = new PorterDuffXfermode (Mode.XOR);
40 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
41 };
42
43 public
44 EmacsDrawRectangle (EmacsDrawable drawable, int x, int y,
45 int width, int height,
46 EmacsGC immutableGC)
47 {
48 this.drawable = drawable;
49 this.x = x;
50 this.y = y;
51 this.width = width;
52 this.height = height;
53 this.immutableGC = immutableGC;
54 }
55
56 @Override
57 public Rect
58 getRect ()
59 {
60 return new Rect (x, y, x + width, y + height);
61 }
62
63 @Override
64 public EmacsDrawable
65 getDrawable ()
66 {
67 return drawable;
68 }
69
70 @Override
71 public EmacsGC
72 getGC ()
73 {
74 return immutableGC;
75 }
76
77 @Override
78 public void
79 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
80 {
81 int alu;
82 Paint maskPaint;
83 Canvas maskCanvas;
84 Bitmap maskBitmap;
85 Rect rect, srcRect;
86
87 /* TODO implement stippling. */
88 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
89 return;
90
91 alu = immutableGC.function;
92 rect = getRect ();
93
94 paint.setStyle (Paint.Style.STROKE);
95
96 if (alu == EmacsGC.GC_COPY)
97 paint.setXfermode (null);
98 else
99 paint.setXfermode (xorAlu);
100
101 if (immutableGC.clip_mask == null)
102 {
103 paint.setColor (immutableGC.foreground | 0xff000000);
104 canvas.drawRect (rect, paint);
105 }
106 else
107 {
108 maskPaint = new Paint ();
109 maskBitmap
110 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
111 true);
112
113 if (maskBitmap == null)
114 return;
115
116 maskPaint.setXfermode (srcInAlu);
117 maskPaint.setColor (immutableGC.foreground | 0xff000000);
118 maskCanvas = new Canvas (maskBitmap);
119 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
120 maskBitmap.getHeight ());
121 maskCanvas.drawRect (srcRect, maskPaint);
122 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
123 }
124
125 paint.setXfermode (null);
126 }
127}
diff --git a/java/org/gnu/emacs/EmacsDrawable.java b/java/org/gnu/emacs/EmacsDrawable.java
new file mode 100644
index 00000000000..19062137213
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawable.java
@@ -0,0 +1,33 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Rect;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25
26public interface EmacsDrawable
27{
28 public Canvas lockCanvas ();
29 public void unlockCanvas ();
30 public void damageRect (Rect damageRect);
31 public Bitmap getBitmap ();
32 public boolean isDestroyed ();
33};
diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java
new file mode 100644
index 00000000000..3198c7f07c4
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFillPolygon.java
@@ -0,0 +1,150 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Math;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Path;
28import android.graphics.Point;
29import android.graphics.PorterDuff.Mode;
30import android.graphics.PorterDuffXfermode;
31import android.graphics.Rect;
32import android.graphics.RectF;
33import android.graphics.Xfermode;
34
35public class EmacsFillPolygon implements EmacsPaintReq
36{
37 private EmacsDrawable drawable;
38 private EmacsGC immutableGC;
39 private Path path;
40
41 private static Xfermode xorAlu, srcInAlu;
42
43 static
44 {
45 xorAlu = new PorterDuffXfermode (Mode.XOR);
46 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
47 };
48
49 public
50 EmacsFillPolygon (EmacsDrawable drawable, Point points[],
51 EmacsGC immutableGC)
52 {
53 int i;
54
55 this.drawable = drawable;
56 this.immutableGC = immutableGC;
57
58 /* Build the path from the given array of points. */
59 path = new Path ();
60
61 if (points.length >= 1)
62 {
63 path.moveTo (points[0].x, points[0].y);
64
65 for (i = 1; i < points.length; ++i)
66 path.lineTo (points[i].x, points[i].y);
67
68 path.close ();
69 }
70 }
71
72 @Override
73 public Rect
74 getRect ()
75 {
76 RectF rect;
77
78 rect = new RectF (0, 0, 0, 0);
79 path.computeBounds (rect, true);
80
81 return new Rect ((int) Math.floor (rect.left),
82 (int) Math.floor (rect.top),
83 (int) Math.ceil (rect.right),
84 (int) Math.ceil (rect.bottom));
85 }
86
87 @Override
88 public EmacsDrawable
89 getDrawable ()
90 {
91 return drawable;
92 }
93
94 @Override
95 public EmacsGC
96 getGC ()
97 {
98 return immutableGC;
99 }
100
101 @Override
102 public void
103 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
104 {
105 int alu;
106 Paint maskPaint;
107 Canvas maskCanvas;
108 Bitmap maskBitmap;
109 Rect rect;
110
111 /* TODO implement stippling. */
112 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
113 return;
114
115 alu = immutableGC.function;
116 rect = getRect ();
117
118 if (alu == EmacsGC.GC_COPY)
119 paint.setXfermode (null);
120 else
121 paint.setXfermode (xorAlu);
122
123 paint.setStyle (Paint.Style.FILL);
124
125 if (immutableGC.clip_mask == null)
126 {
127 paint.setColor (immutableGC.foreground | 0xff000000);
128 canvas.drawPath (path, paint);
129 }
130 else
131 {
132 maskPaint = new Paint ();
133 maskBitmap = immutableGC.clip_mask.bitmap;
134 maskBitmap = maskBitmap.copy (Bitmap.Config.ARGB_8888,
135 true);
136
137 if (maskBitmap == null)
138 return;
139
140 maskPaint.setXfermode (srcInAlu);
141 maskPaint.setColor (immutableGC.foreground | 0xff000000);
142 maskCanvas = new Canvas (maskBitmap);
143 path.offset (-rect.left, -rect.top, null);
144 maskCanvas.drawPath (path, maskPaint);
145 canvas.drawBitmap (maskBitmap, new Rect (0, 0, rect.width (),
146 rect.height ()),
147 rect, paint);
148 }
149 }
150}
diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java
new file mode 100644
index 00000000000..7246c13de7f
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFillRectangle.java
@@ -0,0 +1,129 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30import android.util.Log;
31
32public class EmacsFillRectangle implements EmacsPaintReq
33{
34 private int x, y, width, height;
35 private EmacsDrawable drawable;
36 private EmacsGC immutableGC;
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR);
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
43 };
44
45 public
46 EmacsFillRectangle (EmacsDrawable drawable, int x, int y,
47 int width, int height,
48 EmacsGC immutableGC)
49 {
50 this.drawable = drawable;
51 this.x = x;
52 this.y = y;
53 this.width = width;
54 this.height = height;
55 this.immutableGC = immutableGC;
56 }
57
58 @Override
59 public Rect
60 getRect ()
61 {
62 return new Rect (x, y, x + width, y + height);
63 }
64
65 @Override
66 public EmacsDrawable
67 getDrawable ()
68 {
69 return drawable;
70 }
71
72 @Override
73 public EmacsGC
74 getGC ()
75 {
76 return immutableGC;
77 }
78
79 @Override
80 public void
81 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
82 {
83 int alu;
84 Paint maskPaint;
85 Canvas maskCanvas;
86 Bitmap maskBitmap;
87 Rect rect, srcRect;
88
89 /* TODO implement stippling. */
90 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
91 return;
92
93 alu = immutableGC.function;
94 rect = getRect ();
95
96 paint.setStyle (Paint.Style.FILL);
97
98 if (alu == EmacsGC.GC_COPY)
99 paint.setXfermode (null);
100 else
101 paint.setXfermode (xorAlu);
102
103 if (immutableGC.clip_mask == null)
104 {
105 paint.setColor (immutableGC.foreground | 0xff000000);
106 canvas.drawRect (rect, paint);
107 }
108 else
109 {
110 maskPaint = new Paint ();
111 maskBitmap
112 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
113 true);
114
115 if (maskBitmap == null)
116 return;
117
118 maskPaint.setXfermode (srcInAlu);
119 maskPaint.setColor (immutableGC.foreground | 0xff000000);
120 maskCanvas = new Canvas (maskBitmap);
121 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
122 maskBitmap.getHeight ());
123 maskCanvas.drawRect (srcRect, maskPaint);
124 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
125 }
126
127 paint.setXfermode (null);
128 }
129}
diff --git a/java/org/gnu/emacs/EmacsFontDriver.java b/java/org/gnu/emacs/EmacsFontDriver.java
new file mode 100644
index 00000000000..f419e71059d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFontDriver.java
@@ -0,0 +1,150 @@
1/* Font backend for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.List;
23
24public abstract class EmacsFontDriver
25{
26 /* Font weights. */
27 public static final int THIN = 0;
28 public static final int ULTRA_LIGHT = 40;
29 public static final int LIGHT = 50;
30 public static final int SEMI_LIGHT = 55;
31 public static final int REGULAR = 80;
32 public static final int MEDIUM = 100;
33 public static final int SEMI_BOLD = 180;
34 public static final int BOLD = 200;
35 public static final int EXTRA_BOLD = 205;
36 public static final int BLACK = 210;
37 public static final int ULTRA_HEAVY = 250;
38
39 /* Font slants. */
40 public static final int REVERSE_OBLIQUE = 0;
41 public static final int REVERSE_ITALIC = 10;
42 public static final int NORMAL = 100;
43 public static final int ITALIC = 200;
44 public static final int OBLIQUE = 210;
45
46 /* Font widths. */
47 public static final int ULTRA_CONDENSED = 50;
48 public static final int EXTRA_CONDENSED = 63;
49 public static final int CONDENSED = 75;
50 public static final int SEMI_CONDENSED = 87;
51 public static final int UNSPECIFIED = 100;
52 public static final int SEMI_EXPANDED = 113;
53 public static final int EXPANDED = 125;
54 public static final int EXTRA_EXPANDED = 150;
55 public static final int ULTRA_EXPANDED = 200;
56
57 /* Font spacings. */
58 public static final int PROPORTIONAL = 0;
59 public static final int DUAL = 90;
60 public static final int MONO = 100;
61 public static final int CHARCELL = 110;
62
63 public class FontSpec
64 {
65 /* The fields below mean the same as they do in enum
66 font_property_index in font.h. */
67
68 public String foundry;
69 public String family;
70 public String adstyle;
71 public String registry;
72 public Integer width;
73 public Integer weight;
74 public Integer slant;
75 public Integer size;
76 public Integer spacing;
77 public Integer avgwidth;
78
79 @Override
80 public String
81 toString ()
82 {
83 return ("foundry: " + foundry
84 + " family: " + family
85 + " adstyle: " + adstyle
86 + " registry: " + registry
87 + " width: " + width
88 + " weight: " + weight
89 + " slant: " + slant
90 + " spacing: " + spacing
91 + " avgwidth: " + avgwidth);
92 }
93 };
94
95 public class FontMetrics
96 {
97 public short lbearing;
98 public short rbearing;
99 public short width;
100 public short ascent;
101 public short descent;
102 }
103
104 public class FontEntity extends FontSpec
105 {
106 /* No extra fields here. */
107 };
108
109 public abstract class FontObject extends FontSpec
110 {
111 public int minWidth;
112 public int maxWidth;
113 public int pixelSize;
114 public int height;
115 public int spaceWidth;
116 public int averageWidth;
117 public int ascent;
118 public int descent;
119 public int underlineThickness;
120 public int underlinePosition;
121 public int baselineOffset;
122 public int relativeCompose;
123 public int defaultAscent;
124 public int encodingCharset;
125 public int repertoryCharset;
126
127 public
128 FontObject ()
129 {
130 encodingCharset = -1;
131 repertoryCharset = -1;
132 }
133 };
134
135 /* These mean the same as they do in struct font_driver. */
136 public abstract FontEntity[] list (FontSpec fontSpec);
137 public abstract FontEntity match (FontSpec fontSpec);
138 public abstract String[] listFamilies ();
139 public abstract FontObject openFont (FontEntity fontEntity, int pixelSize);
140 public abstract int hasChar (FontSpec font, char charCode);
141 public abstract void textExtents (FontObject font, int code[],
142 FontMetrics fontMetrics[]);
143 public abstract int encodeChar (FontObject fontObject, char charCode);
144
145 public static EmacsFontDriver
146 createFontDriver ()
147 {
148 return new EmacsSdk7FontDriver ();
149 }
150};
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
new file mode 100644
index 00000000000..0becb04519d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -0,0 +1,116 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Rect;
23
24/* X like graphics context structures. Keep the enums in synch with
25 androidgui.h! */
26
27public class EmacsGC extends EmacsHandleObject
28{
29 public static final int GC_COPY = 0;
30 public static final int GC_XOR = 1;
31
32 public static final int GC_FILL_SOLID = 0;
33 public static final int GC_FILL_OPAQUE_STIPPLED = 1;
34
35 public int function, fill_style;
36 public int foreground, background;
37 public int clip_x_origin, clip_y_origin;
38 public int ts_origin_x, ts_origin_y;
39 public Rect clip_rects[];
40 public EmacsPixmap clip_mask, stipple;
41 private boolean dirty;
42 private EmacsGC immutableGC;
43
44 /* The following fields are only set on immutable GCs. */
45
46 public
47 EmacsGC (short handle)
48 {
49 /* For historical reasons the C code has an extra layer of
50 indirection above this GC handle. struct android_gc is the GC
51 used by Emacs code, while android_gcontext is the type of the
52 handle. */
53 super (handle);
54
55 fill_style = GC_FILL_SOLID;
56 function = GC_COPY;
57 foreground = 0;
58 background = 0xffffffff;
59 }
60
61 public
62 EmacsGC (EmacsGC source)
63 {
64 super ((short) 0);
65
66 int i;
67
68 function = source.function;
69 fill_style = source.fill_style;
70 foreground = source.foreground;
71 background = source.background;
72 clip_x_origin = source.clip_x_origin;
73 clip_y_origin = source.clip_y_origin;
74 clip_rects = source.clip_rects;
75 clip_mask = source.clip_mask;
76 stipple = source.stipple;
77 ts_origin_x = source.ts_origin_x;
78 ts_origin_y = source.ts_origin_y;
79
80 /* Offset all the clip rects by ts_origin_x and ts_origin_y. */
81
82 if ((ts_origin_x != 0 || ts_origin_y != 0)
83 && clip_rects != null)
84 {
85 clip_rects = new Rect[clip_rects.length];
86
87 for (i = 0; i < clip_rects.length; ++i)
88 {
89 clip_rects[i] = new Rect (source.clip_rects[i]);
90 clip_rects[i].offset (ts_origin_x,
91 ts_origin_y);
92 }
93 }
94 }
95
96 /* Mark this GC as dirty. This means immutableGC will return a new
97 copy of this GC the next time it is called. */
98
99 public void
100 markDirty ()
101 {
102 dirty = true;
103 }
104
105 public EmacsGC
106 immutableGC ()
107 {
108 if (immutableGC == null || dirty)
109 {
110 immutableGC = new EmacsGC (this);
111 dirty = false;
112 }
113
114 return immutableGC;
115 };
116};
diff --git a/java/org/gnu/emacs/EmacsHandleObject.java b/java/org/gnu/emacs/EmacsHandleObject.java
new file mode 100644
index 00000000000..a57a3bbdfa9
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsHandleObject.java
@@ -0,0 +1,62 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.List;
23import java.util.ArrayList;
24import java.lang.Object;
25import java.lang.IllegalStateException;
26
27/* This defines something that is a so-called ``handle''. Handles
28 must be created by C code, and will remain existing until
29 destroyHandle is called. C code then refers to the handle by a
30 number which maps into the Java object representing the handle.
31
32 All handle operations must be done from the Emacs thread. */
33
34public abstract class EmacsHandleObject
35{
36 /* Whether or not this handle has been destroyed. */
37 volatile boolean destroyed;
38
39 /* The handle associated with this object. */
40 public short handle;
41
42 public
43 EmacsHandleObject (short handle)
44 {
45 this.handle = handle;
46 }
47
48 public void
49 destroyHandle () throws IllegalStateException
50 {
51 synchronized (this)
52 {
53 destroyed = true;
54 }
55 }
56
57 public boolean
58 isDestroyed ()
59 {
60 return destroyed;
61 }
62};
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
new file mode 100644
index 00000000000..6550e6fa2a1
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -0,0 +1,72 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.System;
23
24import android.content.res.AssetManager;
25
26public class EmacsNative
27{
28 /* Set certain parameters before initializing Emacs. This proves
29 that libemacs.so is being loaded from Java code.
30
31 assetManager must be the asset manager associated with the
32 context that is loading Emacs. It is saved and remains for the
33 remainder the lifetime of the Emacs process.
34
35 filesDir must be the package's data storage location for the
36 current Android user.
37
38 libDir must be the package's data storage location for native
39 libraries. It is used as PATH.
40
41 emacsService must be the emacsService singleton. */
42 public static native void setEmacsParams (AssetManager assetManager,
43 String filesDir,
44 String libDir,
45 EmacsService emacsService);
46
47 /* Initialize Emacs with the argument array ARGV. Each argument
48 must contain a NULL terminated string, or else the behavior is
49 undefined. */
50 public static native void initEmacs (String argv[]);
51
52 /* Abort and generate a native core dump. */
53 public static native void emacsAbort ();
54
55 /* Send an ANDROID_CONFIGURE_NOTIFY event. */
56 public static native void sendConfigureNotify (short window, long time,
57 int x, int y, int width,
58 int height);
59
60 /* Send an ANDROID_KEY_PRESS event. */
61 public static native void sendKeyPress (short window, long time, int state,
62 int keyCode);
63
64 /* Send an ANDROID_KEY_RELEASE event. */
65 public static native void sendKeyRelease (short window, long time, int state,
66 int keyRelease);
67
68 static
69 {
70 System.loadLibrary ("emacs");
71 };
72};
diff --git a/java/org/gnu/emacs/EmacsPaintQueue.java b/java/org/gnu/emacs/EmacsPaintQueue.java
new file mode 100644
index 00000000000..5af5868d3b9
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPaintQueue.java
@@ -0,0 +1,138 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.LinkedList;
23import java.util.List;
24
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Rect;
28
29public class EmacsPaintQueue
30{
31 /* Queue of paint operations. This is modified from the Emacs
32 thread, and entire paint queues are periodically flushed to the
33 application thread where it is executed. */
34 private List<EmacsPaintReq> paintOperations;
35
36 /* Number of operations in this queue. */
37 public int numRequests;
38
39 public
40 EmacsPaintQueue ()
41 {
42 paintOperations = new LinkedList<EmacsPaintReq> ();
43 }
44
45 public void
46 run ()
47 {
48 EmacsDrawable drawable, last;
49 Canvas canvas;
50 EmacsGC gc, lastGC;
51 int i;
52 Paint paint;
53 Rect rect, offsetRect, copyRect;
54
55 canvas = null;
56 last = null;
57 gc = null;
58 paint = new Paint ();
59
60 for (EmacsPaintReq req : paintOperations)
61 {
62 drawable = req.getDrawable ();
63
64 synchronized (req)
65 {
66 /* Ignore graphics requests for drawables that have been
67 destroyed. */
68 if (drawable.isDestroyed ())
69 continue;
70 }
71
72 canvas = drawable.lockCanvas ();
73
74 if (canvas == null)
75 /* No canvas is currently available. */
76 continue;
77
78 lastGC = gc;
79 gc = req.getGC ();
80 rect = req.getRect ();
81
82 if (gc.clip_rects == null)
83 {
84 /* No clipping is applied. Just draw and continue. */
85 canvas.save ();
86 req.paintTo (canvas, paint, gc);
87 canvas.restore ();
88 drawable.damageRect (rect);
89 continue;
90 }
91
92 if (gc.clip_rects != null && gc.clip_rects.length > 0)
93 {
94 canvas.save ();
95
96 if (gc.clip_rects.length == 1)
97 {
98 /* There is only a single clip rect, which is simple
99 enough. */
100 canvas.clipRect (gc.clip_rects[0]);
101 req.paintTo (canvas, paint, gc);
102 }
103 else
104 {
105 /* There are multiple clip rects. Android doesn't let
106 programs use RegionOp.UNION on the clip rectangle,
107 so Emacs must iterate over each intersection and
108 paint it manually. This seems inefficient but
109 thankfully Emacs never seems to use more than one
110 clip rect. */
111
112 for (i = 0; i < gc.clip_rects.length; ++i)
113 {
114 copyRect = new Rect (gc.clip_rects[i]);
115
116 if (copyRect.intersect (rect))
117 {
118 canvas.save ();
119 canvas.clipRect (copyRect);
120 req.paintTo (canvas, paint, gc);
121 canvas.restore ();
122 }
123 }
124 }
125
126 drawable.damageRect (rect);
127 canvas.restore ();
128 }
129 }
130 }
131
132 public void
133 appendPaintOperation (EmacsPaintReq req)
134 {
135 paintOperations.add (req);
136 numRequests++;
137 }
138};
diff --git a/java/org/gnu/emacs/EmacsPaintReq.java b/java/org/gnu/emacs/EmacsPaintReq.java
new file mode 100644
index 00000000000..5b14b005093
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPaintReq.java
@@ -0,0 +1,33 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Canvas;
23import android.graphics.Paint;
24import android.graphics.Rect;
25
26public interface EmacsPaintReq
27{
28 public EmacsDrawable getDrawable ();
29 public EmacsGC getGC ();
30 public void paintTo (Canvas canvas, Paint paint,
31 EmacsGC immutableGC);
32 public Rect getRect ();
33};
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java
new file mode 100644
index 00000000000..ccd5f1e0043
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPixmap.java
@@ -0,0 +1,102 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalArgumentException;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Rect;
27
28/* Drawable backed by bitmap. */
29
30public class EmacsPixmap extends EmacsHandleObject
31 implements EmacsDrawable
32{
33 /* The depth of the bitmap. This is not actually used, just defined
34 in order to be consistent with X. */
35 public int depth, width, height;
36
37 /* The bitmap itself. */
38 public Bitmap bitmap;
39
40 /* The canvas used to draw to BITMAP. */
41 public Canvas canvas;
42
43 public
44 EmacsPixmap (short handle, int colors[], int width,
45 int height, int depth)
46 {
47 super (handle);
48
49 if (depth != 1 && depth != 24)
50 throw new IllegalArgumentException ("Invalid depth specified"
51 + " for pixmap: " + depth);
52
53 switch (depth)
54 {
55 case 1:
56 bitmap = Bitmap.createBitmap (colors, width, height,
57 Bitmap.Config.ALPHA_8);
58 break;
59
60 case 24:
61 bitmap = Bitmap.createBitmap (colors, width, height,
62 Bitmap.Config.ARGB_8888);
63 bitmap.setHasAlpha (false);
64 break;
65 }
66
67 this.width = width;
68 this.height = height;
69 this.depth = depth;
70 }
71
72 @Override
73 public Canvas
74 lockCanvas ()
75 {
76 if (canvas == null)
77 canvas = new Canvas (bitmap);
78
79 return canvas;
80 }
81
82 @Override
83 public void
84 unlockCanvas ()
85 {
86
87 }
88
89 @Override
90 public void
91 damageRect (Rect damageRect)
92 {
93
94 }
95
96 @Override
97 public Bitmap
98 getBitmap ()
99 {
100 return bitmap;
101 }
102};
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
new file mode 100644
index 00000000000..5a8cdbfc75b
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -0,0 +1,460 @@
1/* Font backend for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.io.File;
23import java.io.IOException;
24
25import java.util.LinkedList;
26import java.util.List;
27
28import android.graphics.Paint;
29import android.graphics.Rect;
30import android.graphics.Typeface;
31
32import android.util.Log;
33
34public class EmacsSdk7FontDriver extends EmacsFontDriver
35{
36 private static final String TOFU_STRING = "\uDB3F\uDFFD";
37 private static final String EM_STRING = "m";
38 private static final String TAG = "EmacsSdk7FontDriver";
39
40 private class Sdk7Typeface
41 {
42 /* The typeface and paint. */
43 public Typeface typeface;
44 public Paint typefacePaint;
45 public String familyName;
46 public int slant, width, weight, spacing;
47
48 public
49 Sdk7Typeface (String fileName, Typeface typeface)
50 {
51 String style, testString;
52 int index, measured, i;
53 float[] widths;
54
55 slant = NORMAL;
56 weight = REGULAR;
57 width = UNSPECIFIED;
58 spacing = PROPORTIONAL;
59
60 typefacePaint = new Paint ();
61 typefacePaint.setTypeface (typeface);
62
63 /* For the calls to measureText below. */
64 typefacePaint.setTextSize (10.0f);
65
66 /* Parse the file name into some useful data. First, strip off
67 the extension. */
68 fileName = fileName.split ("\\.", 2)[0];
69
70 /* Next, split the file name by dashes. Everything before the
71 last dash is part of the family name. */
72 index = fileName.lastIndexOf ("-");
73
74 if (index > 0)
75 {
76 style = fileName.substring (index + 1, fileName.length ());
77 familyName = fileName.substring (0, index);
78
79 /* Look for something describing the weight. */
80 if (style.contains ("Thin"))
81 weight = THIN;
82 else if (style.contains ("UltraLight"))
83 weight = ULTRA_LIGHT;
84 else if (style.contains ("SemiLight"))
85 weight = SEMI_LIGHT;
86 else if (style.contains ("Light"))
87 weight = LIGHT;
88 else if (style.contains ("Medium"))
89 weight = MEDIUM;
90 else if (style.contains ("SemiBold"))
91 weight = SEMI_BOLD;
92 else if (style.contains ("ExtraBold"))
93 weight = EXTRA_BOLD;
94 else if (style.contains ("Bold"))
95 weight = BOLD;
96 else if (style.contains ("Black"))
97 weight = BLACK;
98 else if (style.contains ("UltraHeavy"))
99 weight = ULTRA_HEAVY;
100
101 /* And the slant. */
102 if (style.contains ("ReverseOblique"))
103 slant = OBLIQUE;
104 else if (style.contains ("ReverseItalic"))
105 slant = REVERSE_ITALIC;
106 else if (style.contains ("Italic"))
107 slant = ITALIC;
108 else if (style.contains ("Oblique"))
109 slant = OBLIQUE;
110
111 /* Finally, the width. */
112 if (style.contains ("UltraCondensed"))
113 width = ULTRA_CONDENSED;
114 else if (style.contains ("ExtraCondensed"))
115 width = EXTRA_CONDENSED;
116 else if (style.contains ("SemiCondensed"))
117 width = SEMI_CONDENSED;
118 else if (style.contains ("Condensed"))
119 width = CONDENSED;
120 else if (style.contains ("SemiExpanded"))
121 width = SEMI_EXPANDED;
122 else if (style.contains ("ExtraExpanded"))
123 width = EXTRA_EXPANDED;
124 else if (style.contains ("UltraExpanded"))
125 width = ULTRA_EXPANDED;
126 else if (style.contains ("Expanded"))
127 width = EXPANDED;
128
129 /* Guess the spacing information. */
130 testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
131 widths = new float[testString.length ()];
132
133 measured = typefacePaint.getTextWidths (testString,
134 0, testString.length (),
135 widths);
136 spacing = MONO;
137 for (i = 0; i < measured; ++i)
138 {
139 if (i != 0 && widths[i - 1] != widths[i])
140 /* This isn't a monospace font. */
141 spacing = PROPORTIONAL;
142 }
143 }
144 else
145 familyName = fileName;
146
147 Log.d (TAG, "Initialized new typeface " + familyName);
148 }
149
150 @Override
151 public String
152 toString ()
153 {
154 return ("Sdk7Typeface ("
155 + String.valueOf (familyName) + ", "
156 + String.valueOf (slant) + ", "
157 + String.valueOf (width) + ", "
158 + String.valueOf (weight) + ", "
159 + String.valueOf (spacing) + ")");
160 }
161 };
162
163 private class Sdk7FontEntity extends FontEntity
164 {
165 /* The typeface. */
166 public Sdk7Typeface typeface;
167
168 public
169 Sdk7FontEntity (Sdk7Typeface typeface)
170 {
171 float width;
172
173 foundry = "Google";
174 family = typeface.familyName;
175 adstyle = null;
176 weight = typeface.weight;
177 slant = typeface.slant;
178 spacing = typeface.spacing;
179 width = typeface.width;
180
181 this.typeface = typeface;
182 }
183 };
184
185 private class Sdk7FontObject extends FontObject
186 {
187 /* The typeface. */
188 public Sdk7Typeface typeface;
189
190 /* The text size. */
191 public int pixelSize;
192
193 public
194 Sdk7FontObject (Sdk7Typeface typeface, int pixelSize)
195 {
196 float totalWidth;
197 String testWidth, testString;
198
199 this.typeface = typeface;
200 this.pixelSize = pixelSize;
201
202 family = typeface.familyName;
203 adstyle = null;
204 weight = typeface.weight;
205 slant = typeface.slant;
206 spacing = typeface.spacing;
207 width = typeface.width;
208
209 /* Compute the ascent and descent. */
210 typeface.typefacePaint.setTextSize (pixelSize);
211 ascent
212 = Math.round (-typeface.typefacePaint.ascent ());
213 descent
214 = Math.round (typeface.typefacePaint.descent ());
215
216 /* Compute the average width. */
217 testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
218 totalWidth = typeface.typefacePaint.measureText (testString);
219
220 if (totalWidth > 0)
221 avgwidth = Math.round (totalWidth
222 / testString.length ());
223
224 /* Android doesn't expose the font average width and height
225 information, so this will have to do. */
226 minWidth = maxWidth = avgwidth;
227
228 /* This is different from avgwidth in the font spec! */
229 averageWidth = avgwidth;
230
231 /* Set the space width. */
232 totalWidth = typeface.typefacePaint.measureText (" ");
233 spaceWidth = Math.round (totalWidth);
234
235 /* Set the height and default ascent. */
236 height = ascent + descent;
237 defaultAscent = ascent;
238 }
239 };
240
241 private String[] fontFamilyList;
242 private Sdk7Typeface[] typefaceList;
243 private Sdk7Typeface fallbackTypeface;
244
245 public
246 EmacsSdk7FontDriver ()
247 {
248 int i;
249 File systemFontsDirectory, fontFile;
250 Typeface typeface;
251
252 systemFontsDirectory = new File ("/system/fonts");
253
254 fontFamilyList = systemFontsDirectory.list ();
255 typefaceList = new Sdk7Typeface[fontFamilyList.length];
256
257 /* It would be nice to avoid opening each and every font upon
258 startup. But that doesn't seem to be possible on
259 Android. */
260
261 for (i = 0; i < fontFamilyList.length; ++i)
262 {
263 fontFile = new File (systemFontsDirectory,
264 fontFamilyList[i]);
265 typeface = Typeface.createFromFile (fontFile);
266 typefaceList[i] = new Sdk7Typeface (fontFile.getName (),
267 typeface);
268 }
269
270 fallbackTypeface = new Sdk7Typeface ("monospace",
271 Typeface.MONOSPACE);
272 }
273
274 private boolean
275 checkMatch (Sdk7Typeface typeface, FontSpec fontSpec)
276 {
277 if (fontSpec.family != null
278 && !fontSpec.family.equals (typeface.familyName))
279 return false;
280
281
282 if (fontSpec.adstyle != null
283 && !fontSpec.adstyle.isEmpty ())
284 /* return false; */;
285
286 if (fontSpec.slant != null
287 && !fontSpec.weight.equals (typeface.weight))
288 return false;
289
290 if (fontSpec.spacing != null
291 && !fontSpec.spacing.equals (typeface.spacing))
292 return false;
293
294 if (fontSpec.weight != null
295 && !fontSpec.weight.equals (typeface.weight))
296 return false;
297
298 if (fontSpec.width != null
299 && !fontSpec.width.equals (typeface.width))
300 return false;
301
302 return true;
303 }
304
305 @Override
306 public FontEntity[]
307 list (FontSpec fontSpec)
308 {
309 LinkedList<FontEntity> list;
310 int i;
311
312 list = new LinkedList<FontEntity> ();
313
314 Log.d (TAG, ("Looking for fonts matching font spec: "
315 + fontSpec.toString ()));
316
317 for (i = 0; i < typefaceList.length; ++i)
318 {
319 if (checkMatch (typefaceList[i], fontSpec))
320 list.add (new Sdk7FontEntity (typefaceList[i]));
321 }
322
323 Log.d (TAG, "Found font entities: " + list.toString ());
324
325 return (FontEntity[]) list.toArray (new FontEntity[0]);
326 }
327
328 @Override
329 public FontEntity
330 match (FontSpec fontSpec)
331 {
332 FontEntity[] entities;
333 int i;
334
335 entities = this.list (fontSpec);
336
337 if (entities.length == 0)
338 return new Sdk7FontEntity (fallbackTypeface);
339
340 return entities[0];
341 }
342
343 @Override
344 public String[]
345 listFamilies ()
346 {
347 return fontFamilyList;
348 }
349
350 @Override
351 public FontObject
352 openFont (FontEntity fontEntity, int pixelSize)
353 {
354 return new Sdk7FontObject (((Sdk7FontEntity) fontEntity).typeface,
355 pixelSize);
356 }
357
358 @Override
359 public int
360 hasChar (FontSpec font, char charCode)
361 {
362 float missingGlyphWidth, emGlyphWidth, width;
363 Rect rect1, rect2;
364 Paint paint;
365 Sdk7FontObject fontObject;
366
367 if (font instanceof Sdk7FontObject)
368 {
369 fontObject = (Sdk7FontObject) font;
370 paint = fontObject.typeface.typefacePaint;
371 }
372 else
373 paint = ((Sdk7FontEntity) font).typeface.typefacePaint;
374
375 paint.setTextSize (10);
376
377 if (Character.isWhitespace (charCode))
378 return 1;
379
380 missingGlyphWidth = paint.measureText (TOFU_STRING);
381 emGlyphWidth = paint.measureText (EM_STRING);
382 width = paint.measureText ("" + charCode);
383
384 if (width == 0f)
385 return 0;
386
387 if (width != missingGlyphWidth)
388 return 1;
389
390 rect1 = new Rect ();
391 rect2 = new Rect ();
392
393 paint.getTextBounds (TOFU_STRING, 0, TOFU_STRING.length (),
394 rect1);
395 paint.getTextBounds ("" + charCode, 0, 1, rect2);
396 return rect1.equals (rect2) ? 1 : 0;
397 }
398
399 private void
400 textExtents1 (Sdk7FontObject font, int code, FontMetrics metrics,
401 Paint paint, Rect bounds)
402 {
403 char[] text;
404 float[] width;
405
406 text = new char[1];
407 text[0] = (char) code;
408
409 paint.getTextBounds (text, 0, 1, bounds);
410 width = new float[1];
411 paint.getTextWidths (text, 0, 1, width);
412
413 /* bounds is the bounding box of the glyph corresponding to CODE.
414 Translate these into XCharStruct values.
415
416 The origin is at 0, 0, and lbearing is the distance counting
417 rightwards from the origin to the left most pixel in the glyph
418 raster. rbearing is the distance between the origin and the
419 rightmost pixel in the glyph raster. ascent is the distance
420 counting upwards between the the topmost pixel in the glyph
421 raster. descent is the distance (once again counting
422 downwards) between the origin and the bottommost pixel in the
423 glyph raster.
424
425 width is the distance between the origin and the origin of any
426 character to the right. */
427
428 metrics.lbearing = (short) bounds.left;
429 metrics.rbearing = (short) bounds.right;
430 metrics.ascent = (short) -bounds.top;
431 metrics.descent = (short) bounds.bottom;
432 metrics.width = (short) Math.round (width[0]);
433 }
434
435 @Override
436 public void
437 textExtents (FontObject font, int code[], FontMetrics fontMetrics[])
438 {
439 int i;
440 Paint paintCache;
441 Rect boundsCache;
442 Sdk7FontObject fontObject;
443
444 fontObject = (Sdk7FontObject) font;
445 paintCache = fontObject.typeface.typefacePaint;
446 paintCache.setTextSize (fontObject.pixelSize);
447 boundsCache = new Rect ();
448
449 for (i = 0; i < code.length; ++i)
450 textExtents1 ((Sdk7FontObject) font, code[i], fontMetrics[i],
451 paintCache, boundsCache);
452 }
453
454 @Override
455 public int
456 encodeChar (FontObject fontObject, char charCode)
457 {
458 return charCode;
459 }
460};
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
new file mode 100644
index 00000000000..311226e6f7e
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -0,0 +1,384 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Runnable;
23import java.io.IOException;
24import java.util.List;
25import java.util.ArrayList;
26
27import android.graphics.Canvas;
28import android.graphics.Bitmap;
29import android.graphics.Point;
30
31import android.annotation.TargetApi;
32import android.app.Service;
33import android.content.Context;
34import android.content.Intent;
35import android.content.res.AssetManager;
36import android.os.Build;
37import android.os.Looper;
38import android.os.IBinder;
39import android.os.Handler;
40import android.util.Log;
41
42class Holder<T>
43{
44 T thing;
45};
46
47/* EmacsService is the service that starts the thread running Emacs
48 and handles requests by that Emacs instance. */
49
50public class EmacsService extends Service
51{
52 public static final String TAG = "EmacsService";
53 public static final int MAX_PENDING_REQUESTS = 256;
54 public static volatile EmacsService SERVICE;
55
56 private EmacsThread thread;
57 private Handler handler;
58 private EmacsPaintQueue paintQueue;
59
60 /* List of all EmacsWindows that are available to attach to an
61 activity. */
62 public static List<EmacsWindow> availableChildren;
63
64 static
65 {
66 availableChildren = new ArrayList<EmacsWindow> ();
67 };
68
69 @Override
70 public int
71 onStartCommand (Intent intent, int flags, int startId)
72 {
73 return START_NOT_STICKY;
74 }
75
76 @Override
77 public IBinder
78 onBind (Intent intent)
79 {
80 return null;
81 }
82
83 @TargetApi (Build.VERSION_CODES.GINGERBREAD)
84 String
85 getLibraryDirectory ()
86 {
87 int apiLevel;
88 Context context;
89
90 context = getApplicationContext ();
91 apiLevel = android.os.Build.VERSION.SDK_INT;
92
93 if (apiLevel >= Build.VERSION_CODES.GINGERBREAD)
94 return context.getApplicationInfo().nativeLibraryDir;
95 else if (apiLevel >= Build.VERSION_CODES.DONUT)
96 return context.getApplicationInfo().dataDir + "/lib";
97
98 return "/data/data/" + context.getPackageName() + "/lib";
99 }
100
101 @Override
102 public void
103 onCreate ()
104 {
105 AssetManager manager;
106 Context app_context;
107 String filesDir, libDir;
108
109 SERVICE = this;
110 handler = new Handler (Looper.getMainLooper ());
111 manager = getAssets ();
112 app_context = getApplicationContext ();
113
114 try
115 {
116 /* Configure Emacs with the asset manager and other necessary
117 parameters. */
118 filesDir = app_context.getFilesDir ().getCanonicalPath ();
119 libDir = getLibraryDirectory ();
120
121 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
122 + " and libDir = " + libDir);
123
124 EmacsNative.setEmacsParams (manager, filesDir, libDir,
125 this);
126
127 /* Start the thread that runs Emacs. */
128 thread = new EmacsThread (this);
129 thread.start ();
130 }
131 catch (IOException exception)
132 {
133 EmacsNative.emacsAbort ();
134 return;
135 }
136 }
137
138
139
140 /* Functions from here on must only be called from the Emacs
141 thread. */
142
143 void
144 runOnUiThread (Runnable runnable)
145 {
146 handler.post (runnable);
147 }
148
149 EmacsView
150 getEmacsView (final EmacsWindow window)
151 {
152 Runnable runnable;
153 final Holder<EmacsView> view;
154
155 view = new Holder<EmacsView> ();
156
157 runnable = new Runnable () {
158 public void
159 run ()
160 {
161 synchronized (this)
162 {
163 view.thing = new EmacsView (window);
164 notify ();
165 }
166 }
167 };
168
169 synchronized (runnable)
170 {
171 runOnUiThread (runnable);
172
173 try
174 {
175 runnable.wait ();
176 }
177 catch (InterruptedException e)
178 {
179 EmacsNative.emacsAbort ();
180 }
181 }
182
183 return view.thing;
184 }
185
186 /* Notice that a child of the root window named WINDOW is now
187 available for attachment to a specific activity. */
188
189 public void
190 noticeAvailableChild (final EmacsWindow window)
191 {
192 Log.d (TAG, "A new child is available: " + window);
193
194 handler.post (new Runnable () {
195 public void
196 run ()
197 {
198 for (EmacsActivity activity
199 : EmacsActivity.availableActivities)
200 {
201 /* TODO: check if the activity matches. */
202 activity.attachChild (window);
203 break;
204 }
205
206 /* Nope, wait for an activity to become available. */
207 availableChildren.add (window);
208 }
209 });
210 }
211
212 /* Notice that a child of the root window named WINDOW has been
213 destroyed. */
214
215 public void
216 noticeChildDestroyed (final EmacsWindow child)
217 {
218 handler.post (new Runnable () {
219 @Override
220 public void
221 run ()
222 {
223 availableChildren.remove (child);
224 }
225 });
226 }
227
228 /* X drawing operations. These are quite primitive operations. The
229 drawing queue is kept on the Emacs thread, but is periodically
230 flushed to the application thread, upon buffers swaps and once it
231 gets too big. */
232
233
234
235 private void
236 ensurePaintQueue ()
237 {
238 if (paintQueue == null)
239 paintQueue = new EmacsPaintQueue ();
240 }
241
242 public void
243 flushPaintQueue ()
244 {
245 final EmacsPaintQueue queue;
246
247 if (paintQueue == null)
248 return;
249
250 if (paintQueue.numRequests < 1)
251 /* No requests to flush. */
252 return;
253
254 queue = paintQueue;
255
256 handler.post (new Runnable () {
257 @Override
258 public void
259 run ()
260 {
261 queue.run ();
262 }
263 });
264
265 /* Clear the paint queue. */
266 paintQueue = null;
267 }
268
269 private void
270 checkFlush ()
271 {
272 if (paintQueue != null
273 && paintQueue.numRequests > MAX_PENDING_REQUESTS)
274 flushPaintQueue ();
275 }
276
277 public void
278 fillRectangle (EmacsDrawable drawable, EmacsGC gc,
279 int x, int y, int width, int height)
280 {
281 EmacsPaintReq req;
282
283 ensurePaintQueue ();
284
285 req = new EmacsFillRectangle (drawable, x, y,
286 width, height,
287 gc.immutableGC ());
288 paintQueue.appendPaintOperation (req);
289 checkFlush ();
290 }
291
292 public void
293 fillPolygon (EmacsDrawable drawable, EmacsGC gc,
294 Point points[])
295 {
296 EmacsPaintReq req;
297
298 ensurePaintQueue ();
299
300 req = new EmacsFillPolygon (drawable, points,
301 gc.immutableGC ());
302 paintQueue.appendPaintOperation (req);
303 checkFlush ();
304 }
305
306 public void
307 drawRectangle (EmacsDrawable drawable, EmacsGC gc,
308 int x, int y, int width, int height)
309 {
310 EmacsPaintReq req;
311
312 ensurePaintQueue ();
313
314 if (gc.clip_rects != null && gc.clip_rects.length >= 1)
315 android.util.Log.d ("drawRectangle",
316 gc.clip_rects[0].toString ()
317 + " " + gc.toString ());
318
319 req = new EmacsDrawRectangle (drawable, x, y,
320 width, height,
321 gc.immutableGC ());
322 paintQueue.appendPaintOperation (req);
323 checkFlush ();
324 }
325
326 public void
327 drawLine (EmacsDrawable drawable, EmacsGC gc,
328 int x, int y, int x2, int y2)
329 {
330 EmacsPaintReq req;
331
332 ensurePaintQueue ();
333
334 req = new EmacsDrawLine (drawable, x, y,
335 x2, y2,
336 gc.immutableGC ());
337 paintQueue.appendPaintOperation (req);
338 checkFlush ();
339 }
340
341 public void
342 drawPoint (EmacsDrawable drawable, EmacsGC gc,
343 int x, int y)
344 {
345 EmacsPaintReq req;
346
347 ensurePaintQueue ();
348
349 req = new EmacsDrawPoint (drawable, x, y,
350 gc.immutableGC ());
351 paintQueue.appendPaintOperation (req);
352 checkFlush ();
353 }
354
355 public void
356 copyArea (EmacsDrawable srcDrawable, EmacsDrawable dstDrawable,
357 EmacsGC gc,
358 int srcX, int srcY, int width, int height, int destX,
359 int destY)
360 {
361 EmacsPaintReq req;
362
363 ensurePaintQueue ();
364
365 req = new EmacsCopyArea (srcDrawable, dstDrawable,
366 srcX, srcY, width, height, destX,
367 destY, gc.immutableGC ());
368 paintQueue.appendPaintOperation (req);
369 checkFlush ();
370 }
371
372 public void
373 clearWindow (EmacsWindow window)
374 {
375 window.clearWindow ();
376 }
377
378 public void
379 clearArea (EmacsWindow window, int x, int y, int width,
380 int height)
381 {
382 window.clearArea (x, y, width, height);
383 }
384};
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java b/java/org/gnu/emacs/EmacsSurfaceView.java
new file mode 100644
index 00000000000..194f6ad37a3
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsSurfaceView.java
@@ -0,0 +1,83 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.view.SurfaceView;
23import android.view.SurfaceHolder;
24
25import android.graphics.Canvas;
26import android.graphics.Rect;
27
28public class EmacsSurfaceView extends SurfaceView
29{
30 private boolean created;
31
32 public
33 EmacsSurfaceView (final EmacsView view)
34 {
35 super (view.getContext ());
36
37 getHolder ().addCallback (new SurfaceHolder.Callback () {
38 @Override
39 public void
40 surfaceChanged (SurfaceHolder holder, int format,
41 int width, int height)
42 {
43
44 }
45
46 @Override
47 public void
48 surfaceCreated (SurfaceHolder holder)
49 {
50 created = true;
51
52 /* Force a buffer swap now to get the contents of the Emacs
53 view on screen. */
54 view.swapBuffers ();
55 }
56
57 @Override
58 public void
59 surfaceDestroyed (SurfaceHolder holder)
60 {
61 created = false;
62 }
63 });
64 }
65
66 public boolean
67 isCreated ()
68 {
69 return created;
70 }
71
72 public Canvas
73 lockCanvas (Rect damage)
74 {
75 return getHolder ().lockCanvas (damage);
76 }
77
78 public void
79 unlockCanvasAndPost (Canvas canvas)
80 {
81 getHolder ().unlockCanvasAndPost (canvas);
82 }
83};
diff --git a/java/org/gnu/emacs/EmacsThread.java b/java/org/gnu/emacs/EmacsThread.java
new file mode 100644
index 00000000000..e9281a13391
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsThread.java
@@ -0,0 +1,44 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Thread;
23
24public class EmacsThread extends Thread
25{
26 EmacsService context;
27
28 public
29 EmacsThread (EmacsService service)
30 {
31 context = service;
32 }
33
34 public void
35 run ()
36 {
37 String args[];
38
39 args = new String[] { "android-emacs", };
40
41 /* Run the native code now. */
42 EmacsNative.initEmacs (args);
43 }
44};
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
new file mode 100644
index 00000000000..237946d6366
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -0,0 +1,211 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.view.View;
23import android.view.KeyEvent;
24import android.view.ViewGroup;
25import android.graphics.Bitmap;
26import android.graphics.Canvas;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.graphics.Paint;
30import android.util.Log;
31
32import android.os.Build;
33
34/* This is an Android view which has a back and front buffer. When
35 swapBuffers is called, the back buffer is swapped to the front
36 buffer, and any damage is invalidated. frontBitmap and backBitmap
37 are modified and used both from the UI and the Emacs thread. As a
38 result, there is a lock held during all drawing operations.
39
40 It is also a ViewGroup, as it also lays out children. */
41
42public class EmacsView extends ViewGroup
43{
44 public static final String TAG = "EmacsView";
45
46 /* The associated EmacsWindow. */
47 public EmacsWindow window;
48
49 /* The buffer bitmap. */
50 public Bitmap bitmap;
51
52 /* The associated canvases. */
53 public Canvas canvas;
54
55 /* The damage region. */
56 public Region damageRegion;
57
58 /* The paint. */
59 public Paint paint;
60
61 /* The associated surface view. */
62 private EmacsSurfaceView surfaceView;
63
64 public
65 EmacsView (EmacsWindow window)
66 {
67 super (EmacsService.SERVICE);
68
69 this.window = window;
70 this.damageRegion = new Region ();
71 this.paint = new Paint ();
72
73 /* Create the surface view. */
74 this.surfaceView = new EmacsSurfaceView (this);
75
76 setFocusable (FOCUSABLE);
77 addView (this.surfaceView);
78 }
79
80 @Override
81 protected void
82 onMeasure (int widthMeasureSpec, int heightMeasureSpec)
83 {
84 Rect measurements;
85 int width, height;
86
87 /* Return the width and height of the window regardless of what
88 the parent says. */
89 measurements = window.getGeometry ();
90
91 width = measurements.width ();
92 height = measurements.height ();
93
94 /* Now apply any extra requirements in widthMeasureSpec and
95 heightMeasureSpec. */
96
97 if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.EXACTLY)
98 width = MeasureSpec.getSize (widthMeasureSpec);
99 else if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.AT_MOST
100 && width > MeasureSpec.getSize (widthMeasureSpec))
101 width = MeasureSpec.getSize (widthMeasureSpec);
102
103 if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.EXACTLY)
104 height = MeasureSpec.getSize (heightMeasureSpec);
105 else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
106 && height > MeasureSpec.getSize (heightMeasureSpec))
107 height = MeasureSpec.getSize (heightMeasureSpec);
108
109 super.setMeasuredDimension (width, height);
110 }
111
112 @Override
113 protected void
114 onLayout (boolean changed, int left, int top, int right,
115 int bottom)
116 {
117 int count, i;
118 View child;
119 Rect windowRect;
120
121 if (changed)
122 {
123 window.viewLayout (left, top, right, bottom);
124
125 /* Recreate the front and back buffer bitmaps. */
126 bitmap
127 = Bitmap.createBitmap (right - left, bottom - top,
128 Bitmap.Config.ARGB_8888);
129
130 /* And canvases. */
131 canvas = new Canvas (bitmap);
132 }
133
134 count = getChildCount ();
135
136 for (i = 0; i < count; ++i)
137 {
138 child = getChildAt (i);
139
140 if (child == surfaceView)
141 /* The child is the surface view, so give it the entire
142 view. */
143 child.layout (left, top, right, bottom);
144 else if (child.getVisibility () != GONE)
145 {
146 if (!(child instanceof EmacsView))
147 continue;
148
149 /* What to do: lay out the view precisely according to its
150 window rect. */
151 windowRect = ((EmacsView) child).window.getGeometry ();
152 child.layout (windowRect.left, windowRect.top,
153 windowRect.right, windowRect.bottom);
154 }
155 }
156 }
157
158 public void
159 damageRect (Rect damageRect)
160 {
161 damageRegion.union (damageRect);
162 }
163
164 public void
165 swapBuffers ()
166 {
167 Bitmap back;
168 Canvas canvas;
169 Rect damageRect;
170
171 if (damageRegion.isEmpty ())
172 return;
173
174 if (!surfaceView.isCreated ())
175 return;
176
177 if (bitmap == null)
178 return;
179
180 /* Lock the canvas with the specified damage. */
181 damageRect = damageRegion.getBounds ();
182 canvas = surfaceView.lockCanvas (damageRect);
183
184 /* Return if locking the canvas failed. */
185 if (canvas == null)
186 return;
187
188 /* Copy from the back buffer to the canvas. */
189 canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
190
191 /* Unlock the canvas and clear the damage. */
192 surfaceView.unlockCanvasAndPost (canvas);
193 damageRegion.setEmpty ();
194 }
195
196 @Override
197 public boolean
198 onKeyDown (int keyCode, KeyEvent event)
199 {
200 window.onKeyDown (keyCode, event);
201 return true;
202 }
203
204 @Override
205 public boolean
206 onKeyUp (int keyCode, KeyEvent event)
207 {
208 window.onKeyUp (keyCode, event);
209 return true;
210 }
211};
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
new file mode 100644
index 00000000000..28db04a261d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -0,0 +1,336 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalStateException;
23import java.util.ArrayList;
24import java.util.List;
25
26import android.graphics.Rect;
27import android.graphics.Canvas;
28import android.graphics.Bitmap;
29import android.graphics.Point;
30
31import android.view.View;
32import android.view.ViewGroup;
33import android.view.KeyEvent;
34
35/* This defines a window, which is a handle. Windows represent a
36 rectangular subset of the screen with their own contents.
37
38 Windows either have a parent window, in which case their views are
39 attached to the parent's view, or are "floating", in which case
40 their views are attached to the parent activity (if any), else
41 nothing.
42
43 Views are also drawables, meaning they can accept drawing
44 requests. */
45
46public class EmacsWindow extends EmacsHandleObject
47 implements EmacsDrawable
48{
49 /* The view associated with the window. */
50 public EmacsView view;
51
52 /* The geometry of the window. */
53 private Rect rect;
54
55 /* The parent window, or null if it is the root window. */
56 private EmacsWindow parent;
57
58 /* List of all children in stacking order. This must be kept
59 consistent! */
60 private ArrayList<EmacsWindow> children;
61
62 /* The EmacsActivity currently attached, if it exists. */
63 private EmacsActivity attached;
64
65 /* The window background scratch GC. foreground is always the
66 window background. */
67 private EmacsGC scratchGC;
68
69 public
70 EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
71 int width, int height)
72 {
73 super (handle);
74
75 rect = new Rect (x, y, x + width, y + height);
76
77 /* Create the view from the context's UI thread. */
78 view = EmacsService.SERVICE.getEmacsView (this);
79 this.parent = parent;
80 children = new ArrayList<EmacsWindow> ();
81
82 /* The window is unmapped by default. */
83 view.setVisibility (View.GONE);
84
85 /* If parent is the root window, notice that there are new
86 children available for interested activites to pick up. */
87 if (parent == null)
88 EmacsService.SERVICE.noticeAvailableChild (this);
89 else
90 {
91 /* Otherwise, directly add this window as a child of that
92 window's view. */
93 synchronized (parent)
94 {
95 parent.children.add (this);
96 parent.view.post (new Runnable () {
97 @Override
98 public void
99 run ()
100 {
101 parent.view.addView (view);
102 }
103 });
104 }
105 }
106
107 scratchGC = new EmacsGC ((short) 0);
108 }
109
110 public void
111 changeWindowBackground (int pixel)
112 {
113 /* scratchGC is used as the argument to a FillRectangles req. */
114 scratchGC.foreground = pixel;
115 scratchGC.markDirty ();
116 }
117
118 public Rect
119 getGeometry ()
120 {
121 synchronized (this)
122 {
123 /* Huh, this is it. */
124 return rect;
125 }
126 }
127
128 @Override
129 public void
130 destroyHandle () throws IllegalStateException
131 {
132 synchronized (this)
133 {
134 if (!children.isEmpty ())
135 throw new IllegalStateException ("Trying to destroy window with "
136 + "children!");
137 }
138
139 /* Notice that the child has been destroyed. */
140 EmacsService.SERVICE.noticeChildDestroyed (this);
141
142 /* Remove the view from its parent and make it invisible. */
143 view.post (new Runnable () {
144 public void
145 run ()
146 {
147 view.setVisibility (View.GONE);
148
149 if (view.getParent () != null)
150 ((ViewGroup) view.getParent ()).removeView (view);
151
152 if (attached != null)
153 attached.makeAvailable ();
154 }
155 });
156
157 super.destroyHandle ();
158 }
159
160 public void
161 setActivity (EmacsActivity activity)
162 {
163 synchronized (this)
164 {
165 activity = activity;
166 }
167 }
168
169 public void
170 viewLayout (int left, int top, int right, int bottom)
171 {
172 synchronized (this)
173 {
174 rect.left = left;
175 rect.top = top;
176 rect.right = right;
177 rect.bottom = bottom;
178
179 EmacsNative.sendConfigureNotify (this.handle,
180 System.currentTimeMillis (),
181 left, top, rect.width (),
182 rect.height ());
183 }
184 }
185
186 public void
187 requestViewLayout ()
188 {
189 view.post (new Runnable () {
190 @Override
191 public void
192 run ()
193 {
194 view.requestLayout ();
195 }
196 });
197 }
198
199 public void
200 resizeWindow (int width, int height)
201 {
202 synchronized (this)
203 {
204 rect.right = rect.left + width;
205 rect.bottom = rect.top + height;
206 }
207 }
208
209 public void
210 moveWindow (int x, int y)
211 {
212 int width, height;
213
214 synchronized (this)
215 {
216 width = rect.width ();
217 height = rect.height ();
218
219 rect.left = x;
220 rect.top = y;
221 rect.right = x + width;
222 rect.bottom = y + height;
223
224 requestViewLayout ();
225 }
226 }
227
228 public void
229 mapWindow ()
230 {
231 view.post (new Runnable () {
232 @Override
233 public void
234 run ()
235 {
236 view.setVisibility (View.VISIBLE);
237 }
238 });
239 }
240
241 public void
242 unmapWindow ()
243 {
244 view.post (new Runnable () {
245 @Override
246 public void
247 run ()
248 {
249 view.setVisibility (View.GONE);
250 }
251 });
252 }
253
254 @Override
255 public Canvas
256 lockCanvas ()
257 {
258 if (view.canvas != null)
259 return view.canvas;
260
261 return null;
262 }
263
264 @Override
265 public void
266 unlockCanvas ()
267 {
268
269 }
270
271 @Override
272 public void
273 damageRect (Rect damageRect)
274 {
275 view.damageRect (damageRect);
276 }
277
278 public void
279 swapBuffers ()
280 {
281 /* Before calling swapBuffers, make sure to flush the paint
282 queue. */
283 EmacsService.SERVICE.flushPaintQueue ();
284 view.post (new Runnable () {
285 @Override
286 public void
287 run ()
288 {
289 view.swapBuffers ();
290 }
291 });
292 }
293
294 public void
295 clearWindow ()
296 {
297 synchronized (this)
298 {
299 EmacsService.SERVICE.fillRectangle (this, scratchGC,
300 0, 0, rect.width (),
301 rect.height ());
302 }
303 }
304
305 public void
306 clearArea (int x, int y, int width, int height)
307 {
308 EmacsService.SERVICE.fillRectangle (this, scratchGC,
309 x, y, width, height);
310 }
311
312 @Override
313 public Bitmap
314 getBitmap ()
315 {
316 return view.bitmap;
317 }
318
319 public void
320 onKeyDown (int keyCode, KeyEvent event)
321 {
322 EmacsNative.sendKeyPress (this.handle,
323 event.getEventTime (),
324 event.getModifiers (),
325 keyCode);
326 }
327
328 public void
329 onKeyUp (int keyCode, KeyEvent event)
330 {
331 EmacsNative.sendKeyRelease (this.handle,
332 event.getEventTime (),
333 event.getModifiers (),
334 keyCode);
335 }
336};