diff options
| author | Po Lu <luangruo@yahoo.com> | 2023-08-07 08:51:11 +0800 |
|---|---|---|
| committer | Po Lu <luangruo@yahoo.com> | 2023-08-07 08:51:11 +0800 |
| commit | c71a520d1da636a722cf87b46534ca3b5aafbc7b (patch) | |
| tree | 95a3099c065800f60602e0a403b551a6d6dba139 /java/org/gnu/emacs/EmacsWindow.java | |
| parent | 18e7bc87521e3c48b819cfe4a113f532ba905561 (diff) | |
| parent | 9a9f73041d09d2da7ed562c7ffae0d9519562fba (diff) | |
Introduce an Android window system port for GNU Emacs
* src/xterm.h: New fields `quit_keysym' and `quit_keysym_time'.
* src/xterm.c (handle_one_xevent): Check for the quit keysym, and
set Vquit_flag upon witnessing two clicks in rapid succession.
(x_term_init): Set `quit_keysym'.
(init_xterm): Fix typo in name of `register_textconv_interface'.
(syms_of_xterm) <Vx_toolkit_scroll_bars>: Describe its default
value on android.
* src/xfns.c (xic_string_conversion_callback): Pass `0' as the
last argument to textconv_query.
(Fx_server_vendor, Fx_server_version): Document return values on
Android.
* src/xfaces.c (Fx_family_fonts, set_lface_from_font): Use
FRAME_RES instead of FRAME_RES_Y, respecting user preferences on
window systems that have distinct display and font scaling
factors.
(Fx_load_color_file): Call `emacs_fclose', not fclose.
* src/xdisp.c (tab_bar_item_info): Allow `close_p' to be NULL.
(get_tab_bar_item): Update commentary to reflect that change.
(get_tab_bar_item_kbd): New function, resembling get_tab_bar_item.
(build_desired_tool_bar_string): Clear `f->tool_bar_wraps_p';
insert new line characters if a QCwrap item is encountered, and
set f->tool_bar_wrap_p. Replace characters beyond the end of the
tool bar with spaces.
(display_tool_bar_line): Move iterator to the next line if in
contact with an explicit line-wrap item.
(redisplay_internal): If there are newline characters in the tool
bar, refrain from coercing each row into being identically tall.
Don't call `set_tty_color_mode' on Android.
(mark_window_display_accurate_1): Report changes to the point and
mark to input methods.
(display_menu_bar): Adjust ifdefs to allow non-X window systems to
use the built-in menu bar.
(draw_row_with_mouse_face): Don't call TTY functions on Android.
(note_mouse_highlight): Call `popup_activated' on Android.
(expose_frame): Correctly work on the menu bar window.
(gui_union_rectangles): New function.
* src/window.h (struct window): New fields for recording the last
window and point positions, along with an ephemeral position used
during IM text conversion.
(WINDOW_MENU_BAR_P): Correct definition for non-X window systems
without external menu bars.
* src/window.c (replace_buffer_in_windows): Call
Qreplace_buffer_in_windows only when bound.
* src/w32proc.c (sys_spawnve): Pass extra argument to openp.
* src/w32font.c (fill_in_logfont): Use font scaling factor, not
the display scaling factor.
* src/w32.c (check_windows_init_file): Pass extra argument to
openp.
* src/verbose.mk.in (AM_V_JAVAC, AM_V_DX, AM_V_AAPT)
(AM_V_ZIPALIGN, AM_V_SILENT): New variables.
* src/textconv.h (struct textconv_interface): New `point_changed',
`compose_region_changed' and `notify_conversion'.
Add declarations for new functions.
* src/textconv.c (TEXTCONV_DEBUG): New macro.
(suppress_conversion_count): New variable.
(enum textconv_batch_edit_flags): New flag.
(copy_buffer): Don't overwrite text before the gap with the text
after.
(get_mark, select_window): New functions.
(textconv_query): New argument FLAGS. Contingent upon its value,
use the previous point or mark or skip the conversion region.
(sync_overlay, record_buffer_change, reset_frame_state)
(detect_conversion_events, restore_selected_window)
(really_commit_text, really_finish_composing_text)
(really_set_composing_region, really_delete_composing_text)
(really_request_point_update, really_set_point_and_mark)
(complete_edit): New functions.
(struct complete_edit_check_context): New structure; store in it
the result of editing operations.
(complete_edit_check, handle_pending_conversion_events_1)
(decrement_inside, handle_pending_conversion_events)
(start_batch_edit, end_batch_edit, commit_text)
(set_composing_text, textconv_set_point_and_mark)
(request_point_update, textconv_barrier, get_extracted_text)
(get_surrounding_text, conversion_disabled_p)
(report_selected_window_change, report_point_change)
(disable_text_conversion, resume_text_conversion)
(register_textconv_interface, check_postponed_buffers)
(postponed_buffers, Fset_text_conversion_style)
(syms_of_textconv) <Qaction, Qtext_conversion, Qpush_mark,
Qunderline, Qoverriding_text_conversion_style,
Vtext_conversion_edits, Voverriding_text_conversion_style,
Vtext_conversion_face>: New functions, symbols and variables.
* src/terminal.c (Fterminal_live_p): Return Qandroid if type is
output_android.
* src/termhooks.h (enum output_method): Add `output_android'.
(struct terminal) <display_info>: Add union constituent field for
`android'.
<query_colors>: Define on Android as well.
(TERMINAL_FONT_CACHE) [HAVE_ANDROID]: Return the inappropriately
named font cache field on Android.
* src/term.c (string_cost, string_cost_one_line, per_line_cost)
(calculate_costs, produce_glyphs, produce_glyphs, tty_capable_p)
(tty_capable_p, device, init_tty, maybe_fatal)
(delete_tty) [HAVE_ANDROID]: Exclude or turn these functions into
vestiges.
(Fsuspend_tty, Fresume_tty): Call `emacs_fclose' and always signal
on Android.
(Fresume_tty): Call `emacs_fdopen'.
(Ftty__set_output_buffer_size) [HAVE_ANDROID]: Remove this
function.
(encode_terminal_code): Replace with a stub.
(init_tty, delete_tty, maybe_fatal): Call `emacs_fclose'.
(syms_of_term): Remove most unnecessary code on Android.
<system_uses_terminfo>: Always set this option on Android.
* src/sysdep.c (init_standard_fds): Call emacs_fopen.
(reset_sigio, widen_foreground_group): Define out on Android.
(reset_sys_modes): Don't call either function on Android.
(init_sigbus, handle_sigbus): New functions.
(init_signals): Don't add user signals on Android. Register
signal handlers for SIGBUS, and refrain from handling SIGSEGV.
(emacs_fstatat): Wrap android_fstatat on Android.
(sys_fstat, sys_faccessat): New function.
(emacs_openat): Exclude this function when building libemacs.so.
(emacs_open, emacs_open_noquit, emacs_fopen, emacs_close): Wrap
functions defined in the Android filesystem emulation code.
(emacs_fdopen, emacs_fclose, emacs_unlink, emacs_symlink)
(emacs_rmdir, emacs_mkdir, emacs_renameat_noreplace, emacs_rename)
(emacs_fchmodat): New wrappers for more of those functions.
(close_output_streams): Placate the file descriptor sanitizer
that's included with android.
* src/sound.c (Fplay_sound_internal): Pass extra argument to openp.
* src/sfntfont.h:
* src/sfntfont.c:
* src/sfntfont-android.c:
* src/sfnt.h:
* src/sfnt.c: New files.
* src/scroll.c: Exclude the entire file on Android.
* src/process.c: (allocate_pty): Call sys_faccessat, not
faccessat.
(Fmake_process): Call openp with an extra argument.
(wait_reading_process_output): Call android_select.
(Fprocess_send_eof): Don't call tcdrain if not present.
(handle_child_signal): Write a comment describing a small, seldom
encountered issue.
* src/print.c (print_vectorlike): Don't print FONT_EXTRA_INDEX for
font entities.
* src/pdumper.c (Fdump_emacs_portable): Allow dumping in
interactive Emacs's on Android, as this is performed within
loadup.el.
(dump_discard_mem): Use madvise if posix_advise is not present.
(pdumper_load): Call sys_fstat, not fstat.
(syms_of_pdumper) <Vpdumper_fingerprint>: Calculate the
fingerprint for this Emacs executable and store it there.
* src/menu.c (have_boxes): Android has boxes.
(push_submenu_start, push_submenu_end): Define on Android.
(single_menu_item): Produce submenus on Android as well.
(x_popup_menu_1): Call EVENT_START, in contrast to duplicating its
old functionality with calls to Fcar and XCDR.
(Fx_popup_menu): Update documentation to reflect that touch screen
events are now accepted as POSITION.
* src/marker.c (set_marker_internal): Redisplay buffers when their
mark changes, enabling changes to be reported to the IME.
* src/lread.c (lread_fd, lread_fd_cmp, lread_fd_p, lread_close)
(lread_fstat, lread_read_quit, lread_lseek, file_stream)
(file_seek, file_stream_valid_p, file_stream_close)
(file_stream_invalid, getc): New macros. Define to an
implementation with file descriptors and file streams on systems
other than Android 2.3+, and one using Android file descriptors on
those systems.
(USE_ANDROID_ASSETS): Define on Android 2.3+;
(file_get_char): New function.
(infile, skip_dyn_bytes, skip_dyn_eof, readbyte_from_stdio)
(read_filtered_event, safe_to_load_version, close_infile_unwind):
Implement in terms of those macros.
(close_file_unwind_android_fd): New function.
(Fload): Pass extra argument to `openp' and use Android file
descriptors where possible.
(Flocate_file_internal): Pass extra argument to `openp'.
(maybe_swap_for_eln1): Call sys_fstat, not fstat.
(openp): New arg PLATFORM; if supplied and opening a
platform-specific file descriptor replacement is possible, place
one there.
(build_load_history): Fix typos in comments.
(skip_lazy_string): Implement in terms of the aformentioned
macros.
* src/lisp.h: Add declarations for new functions.
* src/keyboard.h (reading_key_sequence): Declare here.
(EVENT_START): Treat touch screen events specially by returning
the posn of their touch point.
* src/keyboard.c (reading_key_sequence, menu_bar_touch_id): New
variables.
(command_loop_1):
(read_menu_command): Pass false to read_key_sequence.
(read_char): Update commentary.
(readable_events): If text conversion events (edits from an input
method) are queued, return 1.
(kbd_buffer_get_event): If text conversion events exist, carry out
the edits contained within. Then, generate a Qtext_conversion
event.
(lispy_function_keys, FUNCTION_KEY_OFFSET): Define function key
array on Android.
(coords_in_tab_bar_window): New function.
(make_lispy_event) <TOUCHSCREEN_BEGIN_EVENT>: Keep track of
touches that fall into the confines of the tab bar, and include
the tab bar item in their position lists. Moreover, retain and
track the touch in C code if it's taking place within the menu
bar.
<TOUCHSCREEN_END_EVENT>: Likewise for the tab bar; generate menu
bar events if the touch ends on a menu item and was previously
singled out for tracking.
<TOUCHSCREEN_UPDATE_EVENT>: Don't deliver this event if the frame
is dead, or if it was identified for tracking since the only touch
sequence that changed begun inside the menu bar.
(handle_async_input): Call android_check_query_urgent.
(handle_input_available_signal): Add memory fence.
(parse_tool_bar_item): Handle `wrap' properties within tool bar
items moving subsequent items onto a new row.
(access_keymap_keyremap): New arguments START, END, KEYBUF.
Set Qcurrent_key_remap_sequence around calls to the remap
function.
(keyremap_step): Pass the necessary information to
access_keymap_keyremap.
(restore_reading_key_sequence): New function.
(read_key_sequence): Set `reading_key_sequence'. New arg
DISABLE_TEXT_CONVERSION_P, which causes text conversion to be
disabled as long as the key sequence is being read. Disable text
conversion as well if a menu or function key prefix is read,
insert imaginary prefix keys before touchscreen events within
special areas of a frame. Don't insert prefix keys if input is
being mocked, which transpires if the input is in actuality
originating from a key translation map.
(read_key_sequence_vs): New argument DISABLE_TEXT_CONVERSION.
(Fread_key_sequence): New argument DISABLE_TEXT_CONVERSION.
(Fopen_dribble_file): Use emacs_fclose.
(head_table): Make touchscreen-begin and touchscreen-end events
touchscreen events.
(syms_of_keyboard) <QCwrap, Qtouchscreen, Qtext_conversion>: New
symbols.
<disable_inhibit_text_conversion, Vcurrent_key_remap_sequence>:
New variables.
* src/inotify.c (Finotify_add_watch): Detect and avoid watching
special files that don't exist from the POV of inotify.
* src/image.c (image_create_bitmap_from_data)
(image_create_bitmap_from_file, free_bitmap_record)
(prepare_image_for_display, image_clear_image_1)
(image_clear_image_1, image_size_in_bytes, image_set_transform):
(Create_Pixmap_From_Bitmap_Data, lookup_rgb_color)
(image_to_emacs_colors, image_from_emacs_colors)
(image_pixmap_draw_cross, image_disable_image): Implement on
Android, reusing much of the X11 code.
(matrix_identity, matrix_rotate, matrix_mirror_horizontal)
(matrix_translate): New functions.
(x_check_image_size, x_create_x_image_and_pixmap)
(x_destroy_x_image, image_check_image_size)
(image_create_x_image_and_pixmap_1, image_destroy_x_image)
(gui_put_x_image, image_get_x_image, image_unget_x_image):
Implement on Android.
(image_find_image_fd): Return an Android file descriptor if
possible.
(close_android_fd): New function.
(slurp_file): Accept `image_fds', defined to Android file
descriptors.
(xpm_load): Enable built-in XPM support on Android.
(xbm_load, pbm_load, png_load_body, jpeg_load_body, gif_load)
(webp_load, imagemagick_load_image, svg_load): Use image file
descriptors on Android; these file descriptors may in fact
represent compressed asset streams, and obviate the necessity of
creating a new file descriptor for each asset image opened.
(Fimage_transforms_p): Report rotate90 on Android.
(image_types, syms_of_image): Enable built-in XPM support on
Android.
* src/fringe.c (init_fringe_bitmap): Bit swap bitmaps on Android,
as on X.
* src/frame.h (enum text_conversion_operation): New enumerator.
(struct text_conversion_action, struct text_conversion_state): New
variable.
(struct frame): New fields `tool_bar_wraps_p' and `conversion'.
Increase the width of `output_method'.
<output_data>: Add `android' field.
<wait_event_type>: Define on Android as well.
(fset_menu_bar_window): Define correctly, so that it's declared on
non-X builds without external menu bars.
(FRAME_ANDROID_P): Define macro.
(FRAME_WINDOW_P) [HAVE_ANDROID]: Define to FRAME_ANDROID_P.
(FRAME_RES): New macro.
(MOUSE_HL_INFO): Define without referencing tty output data on
Android, which doesn't have them.
* src/frame.c (Fframep): Return `android' on Android systems.
(Fwindow_system): Likewise.
(make_frame): Clear text conversion state and `tool_bar_wraps_p'.
(Fmake_terminal_frame): Signal that Android doesn't support text
terminals.
(delete_frame): Reset text conversion state prior to deleting the
frame.
(gui_display_get_resource): Don't call the resource hook on
Android.
(Fx_parse_geometry): Pacify compiler warning.
(make_monitor_attribute_list): Don't always use SOURCE if nil.
(syms_of_frame) <Qandroid>: New symbol.
<Vdefault_frame_scroll_bars>: Don't default scroll bars to an
enabled state on Android.
* src/fontset.c (fontset_find_font): Tackle an unusual problem.
* src/font.h (struct font_entity): New field `is_android'.
(PT_PER_INCH): Define to 160.00 on Android.
* src/font.c (font_make_entity): New function.
(font_make_entity_android): New variant that sets `is_android' to
true.
(font_pixel_size, font_find_for_lface, font_open_for_lface)
(Ffont_face_attributes, Fopen_font): Respect the distinction
between frame text and display scales.
* src/fns.c (Flocale_info): Silence compiler warning.
* src/filelock.c (BOOT_TIME): Undefine BOOT_TIME when building
libemacs.so
(get_boot_time, rename_lock_file, create_lock_file)
(current_lock_owner, make_lock_file_name, unlock_file): Employ
wrappers for Android filesystem operations.
* src/fileio.c (emacs_fd, emacs_fd_open, emacs_fd_close)
(emacs_fd_read, emacs_fd_lseek, emacs_fd_fstat, emacs_fd_valid_p):
New type and macros; define them to suitable values, akin to those
in lread.c
(check_vfs_filename): New function.
(file_access_p): Call `sys_faccessat'.
(close_file_unwind_emacs_fd): New function.
(fclose_unwind): Call `emacs_fclose', not fclose.
(file_name_directory): Export this function.
(user_homedir): If PW->pw_dir is not set and its uid is the
current user, call `android_get_home_directory'.
(get_homedir): Call `android_get_home_directory' if PW->pw_dir is
not set.
(Fcopy_file, Fmake_directory_internal, Fdelete_directory_internal)
(Fdelete_file, Frename_file, Fmake_symbolic_link, Faccess_file)
(file_directory_p, file_accessible_directory_p, Fset_file_modes)
(Fset_file_times, Ffile_newer_than_file_p, read_non_regular)
(Finsert_file_contents, write_region)
(Fverify_visited_file_modtime, Fset_visited_file_modtime)
(do_auto_save_unwind): Make use of Android filesystem wrappers and
file descriptors where possible.
(Fadd_name_to_file): Prohibit creating links to and from files
residing on Android special directories.
(Ffile_system_info): Avoid compilation failure on Android, where
Gnulib can't find out how to implement statfs.
* src/epaths.in [HAVE_ANDROID && !ANDROID_STUBIFY]: Deface this
file, so Makefile cannot change the hard-coded values within.
* src/emacs.c (using_utf8): Correctly initialize mbstate_t on
Android.
(init_cmdargs): Pass extra argument to openp.
(load_pdump): When building libemacs.so, use solely the file
provided on the command line or as an argument to
`android_emacs_init'.
(load_seccomp): Call sys_fstat, not fstat.
(main, android_emacs_init): Name `main' `android_emacs_init' when
building libemacs.so, and accept an argument designating the dump
file.
(main): Initialize text conversion and Android. Don't presume
that argv is NULL terminated.
(Fkill_emacs, shut_down_emacs): Properly implement RESTART on
Android.
(syms_of_emacs) <Vsystem_type>: Describe the possible value
`android'.
* src/emacs-module.c (MODULE_HANDLE_NONLOCAL_EXIT): Cease relying
on GCC clean-up attribute extension.
(MODULE_INTERNAL_CLEANUP): New macro.
(module_make_global_ref, module_free_global_ref)
(module_make_function, module_get_function_finalizer)
(module_make_interactive, module_funcall, module_extract_integer)
(module_extract_float, module_copy_string_contents)
(module_get_user_ptr, module_set_user_ptr)
(module_get_user_finalizer, module_set_user_finalizer)
(module_vec_set, module_vec_size, module_process_input)
(module_extract_big_integer, module_make_big_integer): Carry out
necessary clean-up tasks using MODULE_HANDLE_NONLOCAL_EXIT.
* src/editfns.c (Fuser_full_name): Call `android_user_full_name',
as USER_FULL_NAME doesn't always work.
* src/doc.c (doc_fd, doc_fd_p, doc_open, doc_read_quit)
(doc_lseek): New types and macros, resembling those in lread.c.
(get_doc_string, Fsnarf_documentation): Implement in terms of
those macros, so as to use Android asset streams directly.
* src/dispnew.c (clear_current_matrices, clear_desired_matrices)
(allocate_matrices_for_window_redisplay, free_glyphs)
(redraw_frame, update_frame, scrolling, update_frame_line):
Disable support for text terminals when building for Android.
(Fopen_termscript): Use emacs_fclose.
(init_display_interactive): Set Vinitial_window_system to
Qandroid, and lose if Emacs needs to create a text terminal.
* src/dispextern.h (No_Cursor, Emacs_Rectangle, struct gui_box):
New definitions.
(struct glyph_string) <gc>: Define to the Android GC type.
(HAVE_NATIVE_TRANSPHORMS): Define on Android.
(struct image): New fields `ximg', `mask_img', as on X.
(enum tool_bar_item_idx): New tool bar item property
TOOL_BAR_ITEM_WRAP.
* src/dired.c (emacs_dir, emacs_closedir, emacs_readdir): New
typedef and definitions.
(open_directory): Return emacs_dir; use android_opendir on
Android, instead of at-funcs.
(directory_files_internal_unwind): Call emacs_closedir.
(read_dirent): Call emacs_readdir.
(directory_files_internal, file_name_completion)
(file_name_completion_dirp): Use Android wrappers for directories
and files.
(file_attributes): Abstain from openat on Android.
* src/conf_post.h (MB_CUR_MAX): Define to REPLACEMENT_MB_CUR_MAX
if necessary to counteract inept LLVM headers.
* src/coding.h (from_unicode_buffer): Define if HAVE_ANDROID as
well.
* src/coding.c (from_unicode_buffer): Define on Android, creating
a variant that understands UCS-16 extended into wchar_t.
(syms_of_coding) <Qutf_16le>: Define on Android.
* src/charset.c (load_charset_map_from_file): Supply extra
argument to openp, and call Emacs wrappers for fdopen and fclose.
* src/callproc.c (get_current_directory): Return the home
directory if ENCODED is a special directory.
(delete_temp_file): Call emacs_unlink in lieu of unlink.
(call_process): Use openp.
(emacs_spawn): Use Android executable loader binary if needed and
enabled.
(init_callproc): Set Vshell_file_name to /system/bin/sh if
libemacs.so.
(syms_of_callproc) <Vctags_program_name, Vetags_program_name,
Vhexl_program_name, Vemacsclient_program_name,
Vmovemail_program_name>: New variables. Define to the names of
the programs they respectively stand for.
* src/callint.c (Fcall_interactively): Supply new argument in
calls to Fread_key_sequence and Fread_key_sequence_vector.
* src/buffer.h (struct buffer) <text_conversion_style_>: New bvar.
(bset_text_conversion_style): New bvar setter.
* src/buffer.c (init_buffer_once): Set the text conversion style.
(syms_of_buffer) <BVAR (current_buffer, text_conversion_style)>:
Define new BLV.
* src/androidvfs.c:
* src/androidterm.h:
* src/androidterm.c:
* src/androidselect.c:
* src/androidmenu.c:
* src/androidgui.h:
* src/androidfont.c:
* src/androidfns.c:
* src/android.h:
* src/android.c:
* src/android-emacs.c:
* src/android-asset.h: New function.
* src/alloc.c (cleanup_vector): Finalize Android font entities.
(find_string_data_in_pure) [__i386__ && !__clang__]: On Android,
compensate for a bug in the latest NDK GCC.
(mark_pinned_symbols, android_make_lisp_symbol): Elude another
bug in debuginfo generation with an almost nonsensical fix.
(garbage_collect): Mark androidterm and sfntfont.
(mark_frame): Mark text conversion actions and info.
* src/Makefile.in (XCONFIGURE): New variable. If set, add srcdir
to vpath.
(hostlib): New variable, always defined to libgnu.a on the build
machine.
(GIF_CFLAGS, JPEG_CFLAGS, TIFF_CFLAGS, SQLITE3_CFLAGS)
(LIBSELINUX_CFLAGS, ANDROID_OBJ, ANDROID_LIBS, ANDROID_LDFLAGS)
(ANDROID_BUILD_CFLAGS, LIBGMP_CFLAGS): New variables.
(CM_OBJ): Update commentary.
(EMACS_CFLAGS): Add new compiler flags variables.
(base_obj): Add ANDROID_OBJ.
(SOME_MACHINE_OBJECTS): Add Android-related objects.
(lisp.mk): Generate from its absolute file name.
($(lispsource)/international/charprop.el): Don't generate when
building libemacs.so.
($(libsrc)/make-docfile$(EXEEXT)
$(libsrc)/make-fingerprint$(EXEEXT)): Depend on libgnu.a on the
build machine.
(mostlyclean): Remove libemacs.so.
(build-counter.c, libemacs.so, android-emacs): New targets. These
targets are made from this Makefile copied to a subdirectory of
`cross', and provide the Emacs library and an ancillary binary
used by the Android port.
* nt/mingw-cfg.site:
* nt/gnulib-cfg.mk: Impede building Gnulib's vasnprintf* code.
* msdos/sedlibmk.inp:
* msdos/sedlibcf.inp:
* msdos/sed3v2.inp:
* msdos/sed1v2.inp: Fix the DJGPP build.
* make-dist (possibly_non_vc_files): Add exec/configure and
exec/config.h.in.
* m4/ndk-build.m4: New file.
* m4/getline.m4:
* m4/getdelim.m4:
* m4/asm-underscore.m4: Update from Gnulib.
* lisp/wid-edit.el (widget-event-point): Treat touch screen events
correctly.
(widget-keymap): Map touchscreen-begin to widget-button-click.
(widget-event-start): New function.
(widget-button--check-and-call-button):
(widget-button-click): Behave correctly when confronted by touch
screen events.
* lisp/version.el (android-read-build-system)
(android_read_build_time): New functions.
(emacs-build-system, emacs-repository-version-android)
(emacs-repository-get-version):
(emacs-repository-get-branch): Implement properly on Android, by
reading a file generated during the packaging process.
* lisp/touch-screen.el: New file, supplying support for
translating raw touch screen events into gestures.
* lisp/tool-bar.el (secondary-tool-bar-map): New defvar.
(tool-bar--cache-key, tool-bar--secondary-cache-key): Make
defsubsts.
(tool-bar--flush-key): Flush caches for the secondary tool bar as
well.
(tool-bar-make-keymap, tool-bar-make-keymap-1): Append the
secondary tool bar map below the primary tool bar map.
(modifier-bar-modifier-list): New variable.
(tool-bar-apply-modifiers, modifier-bar-button)
(tool-bar-event-apply-alt-modifier)
(tool-bar-event-apply-super-modifier)
(tool-bar-event-apply-hyper-modifier)
(tool-bar-event-apply-shift-modifier)
(tool-bar-event-apply-control-modifier)
(tool-bar-event-apply-meta-modifier, modifier-bar-available-p)
(modifier-bar-mode): New functions.
* lisp/textmodes/text-mode.el (text-mode): Set
text-conversion-style to t.
* lisp/textmodes/reftex-global.el (reftex-create-tags-file): Use
etags-program-name to provide the name of the etags program.
* lisp/textmodes/conf-mode.el (conf-mode-initialize): Enable text
conversion.
* lisp/textmodes/artist.el (artist-figlet-get-font-list): Use
/system/bin/sh on Android.
* lisp/term/android-win.el: New file.
* lisp/term.el (term-mode): Always display the on screen keyboard.
(term-exec-1): Use /system/bin/sh on Android.
* lisp/tab-line.el (tab-line-tab-map)
(tab-line-new-tab)
(tab-line-select-tab)
(tab-line-close-tab)
(tab-line-track-tap)
(tab-line-event-start): Improve support for touch screen events.
* lisp/tab-bar.el (tab-bar-mouse-context-menu):
(tab-bar-map): Likewise.
(tab-bar-handle-timeout, tab-bar-touchscreen-begin): New
functions.
* lisp/subr.el (event-start): Don't return nonsense if EVENT is a
touchscreen event.
(event-end): Likewise.
(read-key): Disable text conversion within
read-key-sequence-vector.
(read-char-choice-with-read-key): Display the on screen keyboard.
(read-char-from-minibuffer): Disable text conversion.
(use-dialog-box-p): Prefer dialog boxes on Android.
(y-or-n-p): Disable text conversion properly under all three modes
of operation.
* lisp/startup.el (android-fonts-enumerated): New variable.
(normal-top-level): Load system fonts on Android.
* lisp/speedbar.el (speedbar-fetch-etags-command): Use
etags-program-name instead of hard-coding `etags'.
* lisp/simple.el (normal-erase-is-backspace-setup-frame): Return
true on Android.
(event-apply-modifier): Correctly apply Shift and Control
modifiers to keys with other modifiers.
(undo-auto-amalgamate): Mention analyze-text-conversion wrt being
an amalgamating command.
* lisp/shell.el (shell--command-completion-data): Don't lose
if PATH contains an inaccessible directory.
* lisp/progmodes/prog-mode.el (prog-mode): Enable text conversion.
* lisp/progmodes/cperl-mode.el (cperl-etags): Don't hard-code
etags, employ etags-program-name instead.
* lisp/progmodes/cc-mode.el (c-initialize-cc-mode): Initialize
text conversion hook.
* lisp/progmodes/cc-cmds.el (c-post-text-conversion): New
function. Do electric characters.
* lisp/play/gamegrid.el (gamegrid-setup-default-font): Don't crash
if the display resolution is too high.
* lisp/play/dunnet.el (text-conversion-style):
* lisp/play/doctor.el (doctor-mode): Enable text conversion.
* lisp/pixel-scroll.el (pixel-scroll-precision-scroll-down-page)
(pixel-scroll-precision-scroll-Up-page): Make autoloads.
* lisp/org/org-ctags.el (org-ctags-path-to-ctags): Use
ctags-program-name, not ctags.
* lisp/obsolete/terminal.el (terminal-emulator): Start
/system/bin/sh, not /bin/sh.
* lisp/net/tramp.el (tramp-encoding-shell): Use /system/bin/sh on
Android.
* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Define these faces on
Android as well.
* lisp/net/browse-url.el (browse-url-default-browser)
(browse-url--browser-defcustom-type): Specify on Android.
(browse-url-android-share, browse-url-default-android-browser):
New option and function.
* lisp/mwheel.el (mouse-wheel-down-event, mouse-wheel-up-event)
(mouse-wheel-left-event, mouse-wheel-right-event): Define suitably
on Android.
* lisp/mouse.el (minor-mode-menu-from-indicator): New argument
EVENT. Use it for positioning the menu.
(mouse-minor-mode-menu): Pass EVENT to that function.
* lisp/minibuffer.el (clear-minibuffer-message): Don't clear the
message if `touch-screen-preview-select' may be underway.
(minibuffer-mode): Enable text conversion.
(minibuffer-setup-on-screen-keyboard)
(minibuffer-exit-on-screen-keyboard): New functions.
* lisp/menu-bar.el (menu-bar-close-window): New option.
(menu-bar-edit-menu): Bind execute-extended-command to a menu
item.
(kill-this-buffer, kill-this-buffer-enabled-p): Respect
menu-bar-close-window.
* lisp/mail/rmail.el (rmail-autodetect, rmail-insert-inbox-text):
Don't hard-code the name of movemail; rather, use
movemail-program-name.
* lisp/mail/emacsbug.el (emacs-build-description): Insert the
Android version and manufacturer.
* lisp/ls-lisp.el (ls-lisp-use-insert-directory-program): Default
to off on Android.
* lisp/loadup.el: Set load-list to empty load list after startup;
dump the first time Emacs starts, and load Android related
miscellanea.
* lisp/isearch.el (isearch-text-conversion-style): New variable.
(isearch-mode, isearch-done): Display the OSK, then temporarily
disable and restore the on screen keyboard.
* lisp/international/mule-cmds.el (set-coding-system-map): Update
menu definition for Android.
* lisp/international/fontset.el (script-representative-chars)
(setup-default-fontset): Improve detection of CJK fonts.
* lisp/image/wallpaper.el: Fix compiler warning.
* lisp/ielm.el (inferior-emacs-lisp-mode): Don't hard-code name of
hexl, replacing that with hexl-program-name.
* lisp/htmlfontify.el (hfy-etags-bin): Replace hard-coded Emacs
with etags-program-name.
* lisp/hexl.el (hexl-program): Replace hard-coded hexl.
* lisp/help-macro.el (make-help-screen): Display the on screen
keyboard and disable text conversion prior to reading options.
* lisp/gnus/mail-source.el (mail-source-movemail-program): Replace
hard-coded movemail with movemail-program-name.
* lisp/gnus/gnus-score.el (gnus-read-char): New function.
(gnus-summary-increase-score): Use a dialog box to display
these options on Android.
* lisp/frame.el (frame-geometry, frame-edges)
(mouse-absolute-pixel-position, set-mouse-absolute-pixel-position)
(frame-list-z-order, frame-restack, display-mouse-p)
(display-popup-menus-p, display-graphic-p, display-symbol-keys-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, display-monitor-attributes-list): Implement
window system specific functions on Android.
* lisp/files.el (basic-save-buffer): Allow files to exist without
a parent directory.
* lisp/faces.el (tool-bar): Use default definition on Android.
* lisp/emacs-lisp/eldoc.el (eldoc-add-command-completions): Add
touch-screen-handle-touch and analyze-text-conversion.
* lisp/elec-pair.el (electric-pair-analyze-conversion): New
function.
* lisp/doc-view.el (doc-view-menu): Improve menu.
(doc-view-tool-bar-map): Add a new tool bar for Doc View.
(doc-view-new-search): New command.
(doc-view-mode): Enable that new tool bar.
* lisp/dired-aux.el (dired-do-chxxx, dired-do-chmod)
(dired-do-print, dired-do-shell-command, dired-do-compress-to)
(dired-do-create-files, dired-do-rename, dired-do-isearch)
(dired-do-isearch-regexp, dired-do-search)
(dired-do-query-replace-regexp, dired-do-find-regexp)
(dired-vc-next-action): Disable ``click to select'' after
running this command.
* lisp/dired.el (dired-insert-set-properties): Attach
click-to-select keymap to file names if necessary.
(dired-mode-map): Bind `touchscreen-hold' to click to select
mode.
(dired-post-do-command): New function.
(dired-do-delete): Call it.
(dired-mark-for-click, dired-enable-click-to-select-mode): New
functions.
(dired-click-to-select-mode): New minor mode.
* lisp/cus-edit.el (custom-button-mouse, custom-button-pressed)
(custom-display): Define faces to their default values on Android.
* lisp/comint.el (comint-mode): Enable text conversion.
* lisp/cedet/semantic/db-ebrowse.el
(semanticdb-create-ebrowse-database): Replace fixed ebrowse with
ebrowse-program-name.
* lisp/calc/calc.el (calc-mode): Display the on screen keyboard.
(calc): Insist on displaying the on screen keyboard.
* lisp/button.el (button-map): Bind touch screen events to
push-button.
(push-button): Deal with touch screen events.
* lisp/bindings.el (cut, paste, cut, text-conversion): New
bindings.
* lisp/battery.el (battery-status-function): Use
`battery-android'.
(battery-android): New function.
* lib/gnulib.mk.in:
* lib/getline.c:
* lib/getdelim.c:
* lib/Makefile.in: Update from Gnulib.
* lib-src/emacsclient.c (decode_options): Set `alt_display' to
`android'.
* lib-src/asset-directory-tool.c: New file.
* lib-src/Makefile.in: Adapt for cross-compilation.
* java/res/xml/preferences.xml:
* java/res/values/style.xml:
* java/res/values/strings.xml:
* java/res/values/bool.xml:
* java/res/values-v29/style.xml:
* java/res/values-v24/bool.xml:
* java/res/values-v19/bool.xml:
* java/res/values-v14/style.xml:
* java/res/values-v11/style.xml:
* java/org/gnu/emacs/EmacsWindowAttachmentManager.java:
* java/org/gnu/emacs/EmacsWindow.java:
* java/org/gnu/emacs/EmacsView.java:
* java/org/gnu/emacs/EmacsThread.java:
* java/org/gnu/emacs/EmacsSurfaceView.java:
* java/org/gnu/emacs/EmacsService.java:
* java/org/gnu/emacs/EmacsSdk8Clipboard.java:
* java/org/gnu/emacs/EmacsSdk7FontDriver.java:
* java/org/gnu/emacs/EmacsSdk23FontDriver.java:
* java/org/gnu/emacs/EmacsSdk11Clipboard.java:
* java/org/gnu/emacs/EmacsSafThread.java:
* java/org/gnu/emacs/EmacsPreferencesActivity.java:
* java/org/gnu/emacs/EmacsPixmap.java:
* java/org/gnu/emacs/EmacsOpenActivity.java:
* java/org/gnu/emacs/EmacsNoninteractive.java:
* java/org/gnu/emacs/EmacsNative.java:
* java/org/gnu/emacs/EmacsMultitaskActivity.java:
* java/org/gnu/emacs/EmacsLauncherPreferencesActivity.java:
* java/org/gnu/emacs/EmacsInputConnection.java:
* java/org/gnu/emacs/EmacsHolder.java:
* java/org/gnu/emacs/EmacsHandleObject.java:
* java/org/gnu/emacs/EmacsGC.java:
* java/org/gnu/emacs/EmacsFontDriver.java:
* java/org/gnu/emacs/EmacsFillRectangle.java:
* java/org/gnu/emacs/EmacsFillPolygon.java:
* java/org/gnu/emacs/EmacsDrawable.java:
* java/org/gnu/emacs/EmacsDrawRectangle.java:
* java/org/gnu/emacs/EmacsDrawPoint.java:
* java/org/gnu/emacs/EmacsDrawLine.java:
* java/org/gnu/emacs/EmacsDocumentsProvider.java:
* java/org/gnu/emacs/EmacsDirectoryEntry.java:
* java/org/gnu/emacs/EmacsDialogButtonLayout.java:
* java/org/gnu/emacs/EmacsDialog.java:
* java/org/gnu/emacs/EmacsCursor.java:
* java/org/gnu/emacs/EmacsContextMenu.java:
* java/org/gnu/emacs/EmacsClipboard.java:
* java/org/gnu/emacs/EmacsApplication.java:
* java/org/gnu/emacs/EmacsActivity.java:
* java/debug.sh:
* java/README:
* java/Makefile.in:
* java/INSTALL:
* java/AndroidManifest.xml.in:
* exec/trace.c:
* exec/test.c:
* exec/mipsfpu.h:
* exec/mipsfpu.c:
* exec/mipsel-user.h:
* exec/loader-x86_64.s:
* exec/loader-x86.s:
* exec/loader-mipsel.s:
* exec/loader-mips64el.s:
* exec/loader-armeabi.s:
* exec/loader-aarch64.s:
* exec/install-sh:
* exec/exec1.c:
* exec/exec.h:
* exec/exec.c:
* exec/deps.mk:
* exec/configure.ac:
* exec/config.sub:
* exec/config.h.in:
* exec/config.guess:
* exec/config-mips.m4.in:
* exec/README:
* exec/Makefile.in:
* etc/images/last-page.xpm: New files.
* etc/PROBLEMS: Expound upon problems with font instructing on
Android.
* etc/NEWS: Announce changes.
* etc/MACHINES: Describe support for Android.
* etc/DEBUG: Illustrate the steps to debug Emacs on Android.
* doc/lispref/processes.texi (Subprocess Creation):
* doc/lispref/os.texi (System Environment):
* doc/lispref/keymaps.texi (Translation Keymaps):
(Extended Menu Items):
(Tool Bar):
* doc/lispref/frames.texi (Frames):
(Frame Layout):
(Font and Color Parameters):
(Pop-Up Menus):
(Window System Selections):
* doc/lispref/elisp.texi (Top):
* doc/lispref/display.texi (Defining Faces):
(Window Systems):
* doc/lispref/commands.texi (Touchscreen Events):
(Touchscreen Events):
(Misc Events):
(Key Sequence Input):
* doc/emacs/windows.texi (Tab Line):
* doc/emacs/input.texi:
* doc/emacs/frames.texi (Tool Bars):
(Tab Bars):
* doc/emacs/emacs.texi (Top):
* doc/emacs/dired.texi (Marks vs Flags):
* doc/emacs/android.texi:
* doc/emacs/Makefile.in (EMACSSOURCES): Update the documentation
to properly describe changes effected.
* cross/verbose.mk.android:
* cross/ndk-build/ndk-resolve.mk:
* cross/ndk-build/ndk-prebuilt-static-library.mk:
* cross/ndk-build/ndk-prebuilt-shared-library.mk:
* cross/ndk-build/ndk-clear-vars.mk:
* cross/ndk-build/ndk-build.mk.in:
* cross/ndk-build/ndk-build-static-library.mk:
* cross/ndk-build/ndk-build-shared-library.mk:
* cross/ndk-build/ndk-build-executable.mk:
* cross/ndk-build/README:
* cross/ndk-build/Makefile.in:
* cross/langinfo.h:
* cross/README:
* cross/Makefile.in: New files.
* configure.ac: Configure Emacs for cross-compilation on Android.
* build-aux/ndk-module-extract.awk:
* build-aux/ndk-build-helper.mk:
* build-aux/ndk-build-helper-4.mk:
* build-aux/ndk-build-helper-3.mk:
* build-aux/ndk-build-helper-2.mk:
* build-aux/ndk-build-helper-1.mk:
* build-aux/makecounter.sh: New file.
* autogen.sh: Autogen in exec as well.
* admin/merge-gnulib (GNULIB_MODULES): Add getline, stpncpy and
strnlen. Clean lib.
* README:
* Makefile.in:
* INSTALL: Update for Android.
* .dir-locals.el (c-mode): Add a few new types.
Diffstat (limited to 'java/org/gnu/emacs/EmacsWindow.java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindow.java | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java new file mode 100644 index 00000000000..a1f70644e16 --- /dev/null +++ b/java/org/gnu/emacs/EmacsWindow.java @@ -0,0 +1,1445 @@ +/* Communication module for Android terminals. -*- c-file-style: "GNU" -*- + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ + +package org.gnu.emacs; + +import java.lang.IllegalStateException; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import android.content.Context; + +import android.graphics.Rect; +import android.graphics.Canvas; +import android.graphics.Bitmap; +import android.graphics.PixelFormat; + +import android.view.View; +import android.view.ViewManager; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.InputDevice; +import android.view.WindowManager; + +import android.util.Log; + +import android.os.Build; + +/* This defines a window, which is a handle. Windows represent a + rectangular subset of the screen with their own contents. + + Windows either have a parent window, in which case their views are + attached to the parent's view, or are "floating", in which case + their views are attached to the parent activity (if any), else + nothing. + + Views are also drawables, meaning they can accept drawing + requests. */ + +public final class EmacsWindow extends EmacsHandleObject + implements EmacsDrawable +{ + private static final String TAG = "EmacsWindow"; + + private static class Coordinate + { + /* Integral coordinate. */ + int x, y; + + /* Button associated with the coordinate, or 0 if it is a touch + event. */ + int button; + + /* Pointer ID associated with the coordinate. */ + int id; + + public + Coordinate (int x, int y, int button, int id) + { + this.x = x; + this.y = y; + this.button = button; + this.id = id; + } + }; + + /* The view associated with the window. */ + public EmacsView view; + + /* The geometry of the window. */ + private Rect rect; + + /* The parent window, or null if it is the root window. */ + public EmacsWindow parent; + + /* List of all children in stacking order. This must be kept + consistent with their Z order! */ + public ArrayList<EmacsWindow> children; + + /* Map between pointer identifiers and last known position. Used to + compute which pointer changed upon a touch event. */ + private HashMap<Integer, Coordinate> pointerMap; + + /* The window consumer currently attached, if it exists. */ + private EmacsWindowAttachmentManager.WindowConsumer attached; + + /* The window background scratch GC. foreground is always the + window background. */ + private EmacsGC scratchGC; + + /* The button state and keyboard modifier mask at the time of the + last button press or release event. */ + public int lastButtonState; + + /* Whether or not the window is mapped. */ + private volatile boolean isMapped; + + /* Whether or not to ask for focus upon being mapped. */ + private boolean dontFocusOnMap; + + /* Whether or not the window is override-redirect. An + override-redirect window always has its own system window. */ + private boolean overrideRedirect; + + /* The window manager that is the parent of this window. NULL if + there is no such window manager. */ + private WindowManager windowManager; + + /* The time of the last KEYCODE_VOLUME_DOWN release. This is used + to quit Emacs upon two rapid clicks of the volume down + button. */ + private long lastVolumeButtonRelease; + + /* Linked list of character strings which were recently sent as + events. */ + public LinkedHashMap<Integer, String> eventStrings; + + /* Whether or not this window is fullscreen. */ + public boolean fullscreen; + + /* The window background pixel. This is used by EmacsView when + creating new bitmaps. */ + public volatile int background; + + /* The position of this window relative to the root window. */ + public int xPosition, yPosition; + + public + EmacsWindow (short handle, final EmacsWindow parent, int x, int y, + int width, int height, boolean overrideRedirect) + { + super (handle); + + rect = new Rect (x, y, x + width, y + height); + pointerMap = new HashMap<Integer, Coordinate> (); + + /* Create the view from the context's UI thread. The window is + unmapped, so the view is GONE. */ + view = EmacsService.SERVICE.getEmacsView (this, View.GONE, + parent == null); + this.parent = parent; + this.overrideRedirect = overrideRedirect; + + /* Create the list of children. */ + children = new ArrayList<EmacsWindow> (); + + if (parent != null) + { + parent.children.add (this); + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + parent.view.addView (view); + } + }); + } + + scratchGC = new EmacsGC ((short) 0); + + /* Create the map of input method-committed strings. Keep at most + ten strings in the map. */ + + eventStrings + = new LinkedHashMap<Integer, String> () { + @Override + protected boolean + removeEldestEntry (Map.Entry<Integer, String> entry) + { + return size () > 10; + } + }; + } + + public void + changeWindowBackground (int pixel) + { + /* scratchGC is used as the argument to a FillRectangles req. */ + scratchGC.foreground = pixel; + scratchGC.markDirty (false); + + /* Make the background known to the view as well. */ + background = pixel; + } + + public synchronized Rect + getGeometry () + { + return new Rect (rect); + } + + @Override + public synchronized void + destroyHandle () throws IllegalStateException + { + if (parent != null) + parent.children.remove (this); + + EmacsActivity.invalidateFocus (); + + if (!children.isEmpty ()) + throw new IllegalStateException ("Trying to destroy window with " + + "children!"); + + /* Remove the view from its parent and make it invisible. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + public void + run () + { + ViewManager parent; + EmacsWindowAttachmentManager manager; + + if (EmacsActivity.focusedWindow == EmacsWindow.this) + EmacsActivity.focusedWindow = null; + + manager = EmacsWindowAttachmentManager.MANAGER; + view.setVisibility (View.GONE); + + /* If the window manager is set, use that instead. */ + if (windowManager != null) + parent = windowManager; + else + parent = (ViewManager) view.getParent (); + windowManager = null; + + if (parent != null) + parent.removeView (view); + + manager.detachWindow (EmacsWindow.this); + } + }); + + super.destroyHandle (); + } + + public void + setConsumer (EmacsWindowAttachmentManager.WindowConsumer consumer) + { + attached = consumer; + } + + public EmacsWindowAttachmentManager.WindowConsumer + getAttachedConsumer () + { + return attached; + } + + public synchronized long + viewLayout (int left, int top, int right, int bottom) + { + int rectWidth, rectHeight; + + rect.left = left; + rect.top = top; + rect.right = right; + rect.bottom = bottom; + + rectWidth = right - left; + rectHeight = bottom - top; + + /* If parent is null, use xPosition and yPosition instead of the + geometry rectangle positions. */ + + if (parent == null) + { + left = xPosition; + top = yPosition; + } + + return EmacsNative.sendConfigureNotify (this.handle, + System.currentTimeMillis (), + left, top, rectWidth, + rectHeight); + } + + public void + requestViewLayout () + { + view.explicitlyDirtyBitmap (); + + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + if (overrideRedirect) + /* Set the layout parameters again. */ + view.setLayoutParams (getWindowLayoutParams ()); + + view.mustReportLayout = true; + view.requestLayout (); + } + }); + } + + public synchronized void + resizeWindow (int width, int height) + { + rect.right = rect.left + width; + rect.bottom = rect.top + height; + + requestViewLayout (); + } + + public synchronized void + moveWindow (int x, int y) + { + int width, height; + + width = rect.width (); + height = rect.height (); + + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + requestViewLayout (); + } + + private WindowManager.LayoutParams + getWindowLayoutParams () + { + WindowManager.LayoutParams params; + int flags, type; + Rect rect; + + flags = 0; + rect = getGeometry (); + flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; + + params + = new WindowManager.LayoutParams (rect.width (), rect.height (), + rect.left, rect.top, + type, flags, + PixelFormat.RGBA_8888); + params.gravity = Gravity.TOP | Gravity.LEFT; + return params; + } + + private Context + findSuitableActivityContext () + { + /* Find a recently focused activity. */ + if (!EmacsActivity.focusedActivities.isEmpty ()) + return EmacsActivity.focusedActivities.get (0); + + /* Return the service context, which probably won't work. */ + return EmacsService.SERVICE; + } + + public synchronized void + mapWindow () + { + final int width, height; + + if (isMapped) + return; + + isMapped = true; + width = rect.width (); + height = rect.height (); + + if (parent == null) + { + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + EmacsWindowAttachmentManager manager; + WindowManager windowManager; + Context ctx; + Object tem; + WindowManager.LayoutParams params; + + /* Make the view visible, first of all. */ + view.setVisibility (View.VISIBLE); + + if (!overrideRedirect) + { + manager = EmacsWindowAttachmentManager.MANAGER; + + /* If parent is the root window, notice that there are new + children available for interested activites to pick + up. */ + manager.registerWindow (EmacsWindow.this); + + if (!getDontFocusOnMap ()) + /* Eventually this should check no-focus-on-map. */ + view.requestFocus (); + } + else + { + /* But if the window is an override-redirect window, + then: + + - Find an activity that is currently active. + + - Map the window as a panel on top of that + activity using the system window manager. */ + + ctx = findSuitableActivityContext (); + tem = ctx.getSystemService (Context.WINDOW_SERVICE); + windowManager = (WindowManager) tem; + + /* Calculate layout parameters. */ + params = getWindowLayoutParams (); + view.setLayoutParams (params); + + /* Attach the view. */ + try + { + view.prepareForLayout (width, height); + windowManager.addView (view, params); + + /* Record the window manager being used in the + EmacsWindow object. */ + EmacsWindow.this.windowManager = windowManager; + } + catch (Exception e) + { + Log.w (TAG, + "failed to attach override-redirect window, " + e); + } + } + } + }); + } + else + { + /* Do the same thing as above, but don't register this + window. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + /* Prior to mapping the view, set its measuredWidth and + measuredHeight to some reasonable value, in order to + avoid excessive bitmap dirtying. */ + + view.prepareForLayout (width, height); + view.setVisibility (View.VISIBLE); + + if (!getDontFocusOnMap ()) + view.requestFocus (); + } + }); + } + } + + public synchronized void + unmapWindow () + { + if (!isMapped) + return; + + isMapped = false; + + view.post (new Runnable () { + @Override + public void + run () + { + EmacsWindowAttachmentManager manager; + + manager = EmacsWindowAttachmentManager.MANAGER; + + view.setVisibility (View.GONE); + + /* Detach the view from the window manager if possible. */ + if (windowManager != null) + windowManager.removeView (view); + windowManager = null; + + /* Now that the window is unmapped, unregister it as + well. */ + manager.detachWindow (EmacsWindow.this); + } + }); + } + + @Override + public Canvas + lockCanvas (EmacsGC gc) + { + return view.getCanvas (gc); + } + + @Override + public void + damageRect (Rect damageRect) + { + view.damageRect (damageRect); + } + + public void + swapBuffers () + { + view.swapBuffers (); + } + + public void + clearWindow () + { + EmacsService.SERVICE.fillRectangle (this, scratchGC, + 0, 0, rect.width (), + rect.height ()); + } + + public void + clearArea (int x, int y, int width, int height) + { + EmacsService.SERVICE.fillRectangle (this, scratchGC, + x, y, width, height); + } + + @Override + public Bitmap + getBitmap () + { + return view.getBitmap (); + } + + /* event.getCharacters is used because older input methods still + require it. */ + @SuppressWarnings ("deprecation") + public int + getEventUnicodeChar (KeyEvent event, int state) + { + String characters; + + if (event.getUnicodeChar (state) != 0) + return event.getUnicodeChar (state); + + characters = event.getCharacters (); + + if (characters != null && characters.length () == 1) + return characters.charAt (0); + + return characters == null ? 0 : -1; + } + + public void + saveUnicodeString (int serial, String string) + { + eventStrings.put (serial, string); + } + + + + /* Return the modifier mask associated with the specified keyboard + input EVENT. Replace bits corresponding to Left or Right keys + with their corresponding general modifier bits. */ + + private int + eventModifiers (KeyEvent event) + { + int state; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) + state = event.getModifiers (); + else + { + /* Replace this with getMetaState and manual + normalization. */ + state = event.getMetaState (); + + /* Normalize the state by setting the generic modifier bit if + either a left or right modifier is pressed. */ + + if ((state & KeyEvent.META_ALT_LEFT_ON) != 0 + || (state & KeyEvent.META_ALT_RIGHT_ON) != 0) + state |= KeyEvent.META_ALT_MASK; + + if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0 + || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0) + state |= KeyEvent.META_CTRL_MASK; + } + + return state; + } + + /* event.getCharacters is used because older input methods still + require it. */ + @SuppressWarnings ("deprecation") + public void + onKeyDown (int keyCode, KeyEvent event) + { + int state, state_1; + long serial; + String characters; + + state = eventModifiers (event); + + /* Ignore meta-state understood by Emacs for now, or key presses + such as Ctrl+C and Meta+C will not be recognized as an ASCII + key press event. */ + + state_1 + = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK + | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK); + + synchronized (eventStrings) + { + serial + = EmacsNative.sendKeyPress (this.handle, + event.getEventTime (), + state, keyCode, + getEventUnicodeChar (event, + state_1)); + + characters = event.getCharacters (); + + if (characters != null && characters.length () > 1) + saveUnicodeString ((int) serial, characters); + } + } + + public void + onKeyUp (int keyCode, KeyEvent event) + { + int state, state_1; + long time; + + /* Compute the event's modifier mask. */ + state = eventModifiers (event); + + /* Ignore meta-state understood by Emacs for now, or key presses + such as Ctrl+C and Meta+C will not be recognized as an ASCII + key press event. */ + + state_1 + = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK + | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK); + + EmacsNative.sendKeyRelease (this.handle, + event.getEventTime (), + state, keyCode, + getEventUnicodeChar (event, + state_1)); + + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) + { + /* Check if this volume down press should quit Emacs. + Most Android devices have no physical keyboard, so it + is unreasonably hard to press C-g. */ + + time = event.getEventTime (); + + if (time - lastVolumeButtonRelease < 350) + EmacsNative.quit (); + + lastVolumeButtonRelease = time; + } + } + + public void + onFocusChanged (boolean gainFocus) + { + EmacsActivity.invalidateFocus (); + } + + /* Notice that the activity has been detached or destroyed. + + ISFINISHING is set if the activity is not the main activity, or + if the activity was not destroyed in response to explicit user + action. */ + + public void + onActivityDetached (boolean isFinishing) + { + /* Destroy the associated frame when the activity is detached in + response to explicit user action. */ + + if (isFinishing) + EmacsNative.sendWindowAction (this.handle, 0); + } + + + + /* Mouse and touch event handling. + + Android does not conceptually distinguish between mouse events + (those coming from a device whose movement affects the on-screen + pointer image) and touch screen events. Each click or touch + starts a single pointer gesture sequence, and subsequent motion + of the device will result in updates being reported relative to + that sequence until the mouse button or touch is released. + + When a touch, click, or pointer motion takes place, several kinds + of event can be sent: + + ACTION_DOWN or ACTION_POINTER_DOWN is sent with a new coordinate + and an associated ``pointer ID'' identifying the event and its + gesture sequence when a click or touch takes place. Emacs is + responsible for recording both the position and pointer ID of + this click for the purpose of determining future changes to its + position. + + ACTION_UP or ACTION_POINTER_UP is sent with a pointer ID when the + click associated with a previous ACTION_DOWN event is released. + + ACTION_CANCEL (or ACTION_POINTER_UP with FLAG_CANCELED) is sent + if a similar situation transpires: the window system has chosen + to grab the click, and future changes to its position will no + longer be reported to Emacs. + + ACTION_MOVE is sent if a coordinate tied to a click that has not + been released changes. Emacs processes this event by comparing + each of the coordinates within the event with its recollection of + those contained within prior ACTION_DOWN and ACTION_MOVE events; + the pointer ID of the differing coordinate is then reported + within a touch or pointer motion event along with its new + position. + + The events described above are all sent for both touch and mouse + click events. Determining whether an ACTION_DOWN event is + associated with a button event is performed by inspecting the + mouse button state associated with that event. If it contains + any mouse buttons that were not contained in the button state at + the time of the last ACTION_DOWN or ACTION_UP event, the + coordinate contained within is assumed to be a mouse click, + leading to it and associated motion or ACTION_UP events being + reported as mouse button or motion events. Otherwise, those + events are reported as touch screen events, with the touch ID set + to the pointer ID. + + In addition to the events illustrated above, Android also sends + several other types of event upon select types of activity from a + mouse device: + + ACTION_HOVER_MOVE is sent with the coordinate of the mouse + pointer if it moves above a frame prior to any click taking + place. Emacs sends a mouse motion event containing the + coordinate. + + ACTION_HOVER_ENTER and ACTION_HOVER_LEAVE are respectively sent + when the mouse pointer enters and leaves a frame. Moreover, + ACTION_HOVER_LEAVE events are sent immediately before an + ACTION_DOWN event associated with a mouse click. These + extraneous events are distinct in that their button states always + contain an additional button compared to the button state + recorded at the time of the last ACTION_UP event. + + On Android 6.0 and later, ACTION_BUTTON_PRESS is sent with the + coordinate of the mouse pointer if a mouse click occurs, + alongside a ACTION_DOWN event. ACTION_BUTTON_RELEASE is sent + with the same information upon a mouse click being released, also + accompanying an ACTION_UP event. + + However, both types of button events are implemented in a buggy + fashion and cannot be used to report button events. */ + + /* Look through the button state to determine what button EVENT was + generated from. DOWN is true if EVENT is a button press event, + false otherwise. Value is the X number of the button. */ + + private int + whatButtonWasIt (MotionEvent event, boolean down) + { + int eventState, notIn; + + /* Obtain the new button state. */ + eventState = event.getButtonState (); + + /* Compute which button is now set or no longer set. */ + + notIn = (down ? eventState & ~lastButtonState + : lastButtonState & ~eventState); + + if ((notIn & (MotionEvent.BUTTON_PRIMARY + | MotionEvent.BUTTON_SECONDARY + | MotionEvent.BUTTON_TERTIARY)) == 0) + /* No buttons have been pressed, so this is a touch event. */ + return 0; + + if ((notIn & MotionEvent.BUTTON_PRIMARY) != 0) + return 1; + + if ((notIn & MotionEvent.BUTTON_SECONDARY) != 0) + return 3; + + if ((notIn & MotionEvent.BUTTON_TERTIARY) != 0) + return 2; + + /* Buttons 4, 5, 6 and 7 are actually scroll wheels under X. + Thus, report additional buttons starting at 8. */ + + if ((notIn & MotionEvent.BUTTON_BACK) != 0) + return 8; + + if ((notIn & MotionEvent.BUTTON_FORWARD) != 0) + return 9; + + /* Report stylus events as touch screen events. */ + + if ((notIn & MotionEvent.BUTTON_STYLUS_PRIMARY) != 0) + return 0; + + if ((notIn & MotionEvent.BUTTON_STYLUS_SECONDARY) != 0) + return 0; + + /* Not a real value. */ + return 11; + } + + /* Return the mouse button associated with the specified ACTION_DOWN + or ACTION_POINTER_DOWN EVENT. + + Value is 0 if no mouse button was pressed, or the X number of + that mouse button. */ + + private int + buttonForEvent (MotionEvent event) + { + /* ICS and earlier don't support true mouse button events, so + treat all down events as touch screen events. */ + + if (Build.VERSION.SDK_INT + < Build.VERSION_CODES.ICE_CREAM_SANDWICH) + return 0; + + return whatButtonWasIt (event, true); + } + + /* Return the coordinate object associated with the specified + EVENT, or null if it is not known. */ + + private Coordinate + figureChange (MotionEvent event) + { + int i, truncatedX, truncatedY, pointerIndex, pointerID, count; + Coordinate coordinate; + + /* Initialize this variable now. */ + coordinate = null; + + switch (event.getActionMasked ()) + { + case MotionEvent.ACTION_DOWN: + /* Primary pointer pressed with index 0. */ + + pointerID = event.getPointerId (0); + coordinate = new Coordinate ((int) event.getX (0), + (int) event.getY (0), + buttonForEvent (event), + pointerID); + pointerMap.put (pointerID, coordinate); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + /* Primary pointer released with index 0. */ + pointerID = event.getPointerId (0); + coordinate = pointerMap.remove (pointerID); + break; + + case MotionEvent.ACTION_POINTER_DOWN: + /* New pointer. Find the pointer ID from the index and place + it in the map. */ + pointerIndex = event.getActionIndex (); + pointerID = event.getPointerId (pointerIndex); + coordinate = new Coordinate ((int) event.getX (0), + (int) event.getY (0), + buttonForEvent (event), + pointerID); + pointerMap.put (pointerID, coordinate); + break; + + case MotionEvent.ACTION_POINTER_UP: + /* Pointer removed. Remove it from the map. */ + pointerIndex = event.getActionIndex (); + pointerID = event.getPointerId (pointerIndex); + coordinate = pointerMap.remove (pointerID); + break; + + default: + + /* Loop through each pointer in the event. */ + + count = event.getPointerCount (); + for (i = 0; i < count; ++i) + { + pointerID = event.getPointerId (i); + + /* Look up that pointer in the map. */ + coordinate = pointerMap.get (pointerID); + + if (coordinate != null) + { + /* See if coordinates have changed. */ + truncatedX = (int) event.getX (i); + truncatedY = (int) event.getY (i); + + if (truncatedX != coordinate.x + || truncatedY != coordinate.y) + { + /* The pointer changed. Update the coordinate and + break out of the loop. */ + coordinate.x = truncatedX; + coordinate.y = truncatedY; + + break; + } + } + } + + /* Set coordinate to NULL if the loop failed to find any + matching pointer. */ + + if (i == count) + coordinate = null; + } + + /* Return the pointer ID. */ + return coordinate; + } + + /* Return the modifier mask associated with the specified motion + EVENT. Replace bits corresponding to Left or Right keys with + their corresponding general modifier bits. */ + + private int + motionEventModifiers (MotionEvent event) + { + int state; + + state = event.getMetaState (); + + /* Normalize the state by setting the generic modifier bit if + either a left or right modifier is pressed. */ + + if ((state & KeyEvent.META_ALT_LEFT_ON) != 0 + || (state & KeyEvent.META_ALT_RIGHT_ON) != 0) + state |= KeyEvent.META_ALT_MASK; + + if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0 + || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0) + state |= KeyEvent.META_CTRL_MASK; + + return state; + } + + /* Process a single ACTION_DOWN, ACTION_POINTER_DOWN, ACTION_UP, + ACTION_POINTER_UP, ACTION_CANCEL, or ACTION_MOVE event. + + Ascertain which coordinate changed and send an appropriate mouse + or touch screen event. */ + + private void + motionEvent (MotionEvent event) + { + Coordinate coordinate; + int modifiers; + long time; + + /* Find data associated with this event's pointer. Namely, its + current location, whether or not a change has taken place, and + whether or not it is a button event. */ + + coordinate = figureChange (event); + + if (coordinate == null) + return; + + time = event.getEventTime (); + + if (coordinate.button != 0) + { + /* This event is tied to a mouse click, so report mouse motion + and button events. */ + + modifiers = motionEventModifiers (event); + + switch (event.getAction ()) + { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_DOWN: + EmacsNative.sendButtonPress (this.handle, coordinate.x, + coordinate.y, time, modifiers, + coordinate.button); + break; + + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + EmacsNative.sendButtonRelease (this.handle, coordinate.x, + coordinate.y, time, modifiers, + coordinate.button); + break; + + case MotionEvent.ACTION_MOVE: + EmacsNative.sendMotionNotify (this.handle, coordinate.x, + coordinate.y, time); + break; + } + } + else + { + /* This event is a touch event, and the touch ID is the + pointer ID. */ + + switch (event.getActionMasked ()) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + /* Touch down event. */ + EmacsNative.sendTouchDown (this.handle, coordinate.x, + coordinate.y, time, + coordinate.id, 0); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + /* Touch up event. */ + EmacsNative.sendTouchUp (this.handle, coordinate.x, + coordinate.y, time, + coordinate.id, 0); + break; + + case MotionEvent.ACTION_CANCEL: + /* Touch sequence cancellation event. */ + EmacsNative.sendTouchUp (this.handle, coordinate.x, + coordinate.y, time, + coordinate.id, + 1 /* ANDROID_TOUCH_SEQUENCE_CANCELED */); + break; + + case MotionEvent.ACTION_MOVE: + /* Pointer motion event. */ + EmacsNative.sendTouchMove (this.handle, coordinate.x, + coordinate.y, time, + coordinate.id, 0); + break; + } + } + + if (Build.VERSION.SDK_INT + < Build.VERSION_CODES.ICE_CREAM_SANDWICH) + return; + + /* Now update the button state. */ + lastButtonState = event.getButtonState (); + return; + } + + public boolean + onTouchEvent (MotionEvent event) + { + switch (event.getActionMasked ()) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_MOVE: + motionEvent (event); + return true; + } + + return false; + } + + public boolean + onGenericMotionEvent (MotionEvent event) + { + switch (event.getAction ()) + { + case MotionEvent.ACTION_HOVER_ENTER: + EmacsNative.sendEnterNotify (this.handle, (int) event.getX (), + (int) event.getY (), + event.getEventTime ()); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + EmacsNative.sendMotionNotify (this.handle, (int) event.getX (), + (int) event.getY (), + event.getEventTime ()); + return true; + + case MotionEvent.ACTION_HOVER_EXIT: + + /* If the exit event comes from a button press, its button + state will have extra bits compared to the last known + button state. Since the exit event will interfere with + tool bar button presses, ignore such splurious events. */ + + if ((event.getButtonState () & ~lastButtonState) == 0) + EmacsNative.sendLeaveNotify (this.handle, (int) event.getX (), + (int) event.getY (), + event.getEventTime ()); + + return true; + + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_MOVE: + /* MotionEvents may either be sent to onGenericMotionEvent or + onTouchEvent depending on if Android thinks it is a mouse + event or not, but we detect them ourselves. */ + motionEvent (event); + return true; + + case MotionEvent.ACTION_SCROLL: + /* Send a scroll event with the specified deltas. */ + EmacsNative.sendWheel (this.handle, (int) event.getX (), + (int) event.getY (), + event.getEventTime (), + motionEventModifiers (event), + event.getAxisValue (MotionEvent.AXIS_HSCROLL), + event.getAxisValue (MotionEvent.AXIS_VSCROLL)); + return true; + } + + return false; + } + + + + public synchronized void + reparentTo (final EmacsWindow otherWindow, int x, int y) + { + int width, height; + + /* Reparent this window to the other window. */ + + if (parent != null) + parent.children.remove (this); + + if (otherWindow != null) + otherWindow.children.add (this); + + parent = otherWindow; + + /* Move this window to the new location. */ + width = rect.width (); + height = rect.height (); + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + /* Now do the work necessary on the UI thread to reparent the + window. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + EmacsWindowAttachmentManager manager; + ViewManager parent; + + /* First, detach this window if necessary. */ + manager = EmacsWindowAttachmentManager.MANAGER; + manager.detachWindow (EmacsWindow.this); + + /* Also unparent this view. */ + + /* If the window manager is set, use that instead. */ + if (windowManager != null) + parent = windowManager; + else + parent = (ViewManager) view.getParent (); + windowManager = null; + + if (parent != null) + parent.removeView (view); + + /* Next, either add this window as a child of the new + parent's view, or make it available again. */ + if (otherWindow != null) + otherWindow.view.addView (view); + else if (EmacsWindow.this.isMapped) + manager.registerWindow (EmacsWindow.this); + + /* Request relayout. */ + view.requestLayout (); + } + }); + } + + public void + makeInputFocus (long time) + { + /* TIME is currently ignored. Request the input focus now. */ + + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + view.requestFocus (); + } + }); + } + + public synchronized void + raise () + { + /* This does nothing here. */ + if (parent == null) + return; + + /* Remove and add this view again. */ + parent.children.remove (this); + parent.children.add (this); + + /* Request a relayout. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + view.raise (); + } + }); + } + + public synchronized void + lower () + { + /* This does nothing here. */ + if (parent == null) + return; + + /* Remove and add this view again. */ + parent.children.remove (this); + parent.children.add (this); + + /* Request a relayout. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + view.lower (); + } + }); + } + + public synchronized int[] + getWindowGeometry () + { + int[] array; + + array = new int[4]; + + array[0] = parent != null ? rect.left : xPosition; + array[1] = parent != null ? rect.top : yPosition; + array[2] = rect.width (); + array[3] = rect.height (); + + return array; + } + + public void + noticeIconified () + { + EmacsNative.sendIconified (this.handle); + } + + public void + noticeDeiconified () + { + EmacsNative.sendDeiconified (this.handle); + } + + public synchronized void + setDontAcceptFocus (final boolean dontAcceptFocus) + { + /* Update the view's focus state. */ + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + view.setFocusable (!dontAcceptFocus); + view.setFocusableInTouchMode (!dontAcceptFocus); + } + }); + } + + public synchronized void + setDontFocusOnMap (final boolean dontFocusOnMap) + { + this.dontFocusOnMap = dontFocusOnMap; + } + + public synchronized boolean + getDontFocusOnMap () + { + return dontFocusOnMap; + } + + public int[] + translateCoordinates (int x, int y) + { + int[] array; + + /* This is supposed to translate coordinates to the root + window. */ + array = new int[2]; + EmacsService.SERVICE.getLocationOnScreen (view, array); + + /* Now, the coordinates of the view should be in array. Offset X + and Y by them. */ + array[0] += x; + array[1] += y; + + /* Return the resulting coordinates. */ + return array; + } + + public void + toggleOnScreenKeyboard (final boolean on) + { + /* Even though InputMethodManager functions are thread safe, + `showOnScreenKeyboard' etc must be called from the UI thread in + order to avoid deadlocks if the calls happen in tandem with a + call to a synchronizing function within + `onCreateInputConnection'. */ + + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + if (on) + view.showOnScreenKeyboard (); + else + view.hideOnScreenKeyboard (); + } + }); + } + + public String + lookupString (int eventSerial) + { + String any; + + synchronized (eventStrings) + { + any = eventStrings.remove (eventSerial); + } + + return any; + } + + public void + setFullscreen (final boolean isFullscreen) + { + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + EmacsActivity activity; + Object tem; + + fullscreen = isFullscreen; + tem = getAttachedConsumer (); + + if (tem != null) + { + activity = (EmacsActivity) tem; + activity.syncFullscreenWith (EmacsWindow.this); + } + } + }); + } + + public void + defineCursor (final EmacsCursor cursor) + { + /* Don't post this message if pointer icons aren't supported. */ + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + view.post (new Runnable () { + @Override + public void + run () + { + if (cursor != null) + view.setPointerIcon (cursor.icon); + else + view.setPointerIcon (null); + } + }); + } + + public synchronized void + notifyContentRectPosition (int xPosition, int yPosition) + { + Rect geometry; + + /* Ignore these notifications if not a child of the root + window. */ + if (parent != null) + return; + + /* xPosition and yPosition are the position of this window + relative to the screen. Set them and request a ConfigureNotify + event. */ + + if (this.xPosition != xPosition + || this.yPosition != yPosition) + { + this.xPosition = xPosition; + this.yPosition = yPosition; + + EmacsNative.sendConfigureNotify (this.handle, + System.currentTimeMillis (), + xPosition, yPosition, + rect.width (), rect.height ()); + } + } +}; |
