mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
Update Android port
* configure.ac (ANDROID_MIN_SDK): New variable. (DX): Remove and replace with D8. (XCONFIGURE): Check for the minimum version of Android the cross compiler compiles for. Generate java/AndroidManifest.xml from java/AndroidManifest.xml.in. Allow using Zlib on Android. * java/AndroidManifest.xml.in: New file. Use the minimum SDK detected by configure. * java/Makefile.in (top_srcdir, version): New variables. (DX, D8): Replace with D8. (ANDROID_MIN_SDK, APK_NAME): New variables. (.PHONY): (.PRECIOUS): (classes.dex): (emacs.apk): Generate $(APK_NAME) instead of `emacs.apk'. * java/debug.sh: New option --attach-existing. Attach to an existing Emacs instance when specified. * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): New field `isPaused'. (invalidateFocus1): Fix infinite recursion. (detachWindow): Deiconify window. (attachWindow): Iconify the window if the activity is paused. (onCreate): Use the ``no title bar'' theme. (onPause, onResume): New functions. * java/org/gnu/emacs/EmacsNative.java (sendTouchUp, sendTouchDown) (sendTouchMove, sendWheel, sendIconified, sendDeiconified): New functions. * java/org/gnu/emacs/EmacsSdk7FontDriver.java (Sdk7Typeface): (list): Remove logging for code that is mostly going to be unused. * java/org/gnu/emacs/EmacsService.java (ringBell, queryTree) (getScreenWidth, getScreenHeight, detectMouse): New functions. * java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView) (surfaceChanged, surfaceCreated, surfaceDestroyed): Add extra debug logging. Avoid deadlock in surfaceCreated. * java/org/gnu/emacs/EmacsView.java (EmacsView): Try very hard to make the SurfaceView respect Z order. It didn't work. (handleDirtyBitmap): Copy over the contents from the old bitmap. (explicitlyDirtyBitmap): New function. (onLayout): Don't dirty bitmap if unnecessary. (damageRect, swapBuffers): Don't synchronize so hard. (onTouchEvent): Call window.onTouchEvent instead. (moveChildToBack, raise, lower): New functions. * java/org/gnu/emacs/EmacsWindow.java (Coordinate): New subclass. (pointerMap, isMapped, isIconified, dontFocusOnMap) (dontAcceptFocus): New fields. (EmacsWindow): Don't immediately register unmapped window. (viewLayout): Send configure event outside the lock. (requestViewLayout): Explicitly dirty the bitmap. (mapWindow): Register the window now. Respect dontFocusOnMap. (unmapWindow): Unregister the window now. (figureChange, onTouchEvent): New functions. (onSomeKindOfMotionEvent): Handle scroll wheel events. (reparentTo, makeInputFocus, raise, lower, getWindowGeometry) (noticeIconified, noticeDeiconified, setDontAcceptFocus) (setDontFocusOnMap, getDontFocusOnMap): New functions. * java/org/gnu/emacs/EmacsWindowAttachmentManager.java (registerWindow, detachWindow): Synchronize. (noticeIconified, noticeDeiconified): New functions. (copyWindows): New function. * 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-monitor-attributes-list): Implement on Android. * lisp/mwheel.el (mouse-wheel-down-event): (mouse-wheel-up-event): (mouse-wheel-left-event): (mouse-wheel-right-event): Define on Android. * src/android.c (struct android_emacs_service): New methods `ringBell', `queryTree', `getScreenWidth', `getScreenHeight', and `detectMouse'. (struct android_event_queue, android_init_events) (android_next_event, android_write_event): Remove write limit. (android_file_access_p): Handle directories correcty. (android_close): Fix coding style. (android_fclose): New function. (android_init_emacs_service): Initialize new methods. (android_reparent_window): Implement function. (android_bell, android_set_input_focus, android_raise_window) (android_lower_window, android_query_tree, android_get_geometry) (android_get_screen_width, android_get_screen_height) (android_get_mm_width, android_get_mm_height, android_detect_mouse) (android_set_dont_focus_on_map, android_set_dont_accept_focus): New functions. (struct android_dir): New structure. (android_opendir, android_readdir, android_closedir): New functions. (emacs_abort): Implement here on Android and poke debuggerd into generating a tombstone. * src/android.h: Update prototypes. * src/androidfns.c (android_set_parent_frame): New function. (android_default_font_parameter): Use sane font size by default. (Fx_display_pixel_width, Fx_display_pixel_height) (Fx_display_mm_width, Fx_display_mm_height) (Fx_display_monitor_attributes_list): Rename to start with `android-'. Implement. Fiddle with documentation to introduce Android specific nuances. (Fandroid_display_monitor_attributes_list): New function. (Fx_frame_geometry, frame_geometry): New function. (Fandroid_frame_geometry): Implement correctly. (Fx_frame_list_z_order): Rename to start with `android-'. (android_frame_list_z_order, Fandroid_frame_list_z_order): Implement. (Fx_frame_restack): Rename to start with `android-'. (Fandroid_frame_restack): ``Implement''. (Fx_mouse_absolute_pixel_position): Rename to start with `android-'. (Fandroid_mouse_absolute_pixel_position): ``Implement''. (Fx_set_mouse_absolute_pixel_position): Rename to start with `android-'. (Fandroid_set_mouse_absolute_pixel_position): ``Implement''. (Fandroid_detect_mouse): New function. (android_set_menu_bar_lines): Use FRAME_ANDROID_DRAWABLE when clearing area. (android_set_no_focus_on_map, android_set_no_accept_focus): New functions. (android_frame_parm_handlers): Register new frame parameter handlers. (syms_of_androidfns): Update appropriately. * src/androidfont.c (androidfont_draw): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW. * src/androidgui.h (enum android_event_type): New events. (struct android_touch_event, struct android_wheel_event) (struct android_iconify_event): New structures. (union android_event): Add new events. * src/androidterm.c (android_clear_frame): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW. (android_flash, android_ring_bell): Implement bell ringing. (android_toggle_invisible_pointer): Don't TODO function that can't be implemented. (show_back_buffer, android_flush_dirty_back_buffer_on): Check if a buffer flip is required before doing the flip. (android_lower_frame, android_raise_frame): Implement functions. (android_update_tools, android_find_tool): New functions. (handle_one_android_event): Handle new iconification, wheel and touch events. (android_read_socket): Implement pending-autoraise-frames. (android_frame_up_to_date): Implement bell ringing. (android_buffer_flipping_unblocked_hook): Check if a buffer flip is required before doing the flip. (android_focus_frame, android_frame_highlight) (android_frame_unhighlight): New function. (android_frame_rehighlight): Implement functions. (android_iconify_frame): Always display error. (android_set_alpha): Update commentary. (android_free_frame_resources): Free frame touch points. (android_scroll_run, android_flip_and_flush) (android_clear_rectangle, android_draw_fringe_bitmap) (android_draw_glyph_string_background, android_fill_triangle) (android_clear_point, android_draw_relief_rect) (android_draw_box_rect, android_draw_glyph_string_bg_rect) (android_draw_image_foreground, 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_clear_frame_area) (android_clear_under_internal_border, android_draw_hollow_cursor) (android_draw_bar_cursor, android_draw_vertical_window_border) (android_draw_window_divider): Use FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW for drawing operations. * src/androidterm.h (struct android_touch_point): New structure. (struct android_output): New fields. (FRAME_ANDROID_NEED_BUFFER_FLIP): New macro. * src/dired.c (emacs_readdir, open_directory) (directory_files_internal_unwind, read_dirent) (directory_files_internal, file_name_completion): Add indirection over readdir and opendir. Use android variants on Android. * src/dispnew.c (Fopen_termscript): * src/fileio.c (fclose_unwind): Use emacs_fclose. (Faccess_file): Call android_file_access_p. (file_accessible_directory_p): Append right suffix to Android assets directory. (do_auto_save_unwind): Use emacs_fclose. * src/keyboard.c (lispy_function_keys): Use right function key for page up and page down. (Fopen_dribble_file): Use emacs_fclose. * src/lisp.h: New prototype emacs_fclose. * src/lread.c (close_infile_unwind): Use emacs_fclose. * src/sfnt.c (sfnt_curve_is_flat): Fix area-squared computation. (sfnt_prepare_raster): Compute raster width and height consistently with outline building. (sfnt_build_outline_edges): Use the same offsets used to set offy and offx. (main): Adjust debug code. * src/sfntfont-android.c (sfntfont_android_saturate32): Delete function. (sfntfont_android_blend, sfntfont_android_blendrgb): Remove unnecessary debug code. (sfntfont_android_composite_bitmap): Prevent out of bounds write. (sfntfont_android_put_glyphs): Use FRAME_ANDROID_DRAWABLE. (init_sfntfont_android): Initialize Monospace Serif font to something sensible. * src/sfntfont.c (sfntfont_text_extents): Clear glyph metrics before summing up pcm. (sfntfont_draw): Use s->font instead of s->face->font. * src/sysdep.c (emacs_fclose): Wrap around android_fclose on android. * src/term.c (Fsuspend_tty): (delete_tty): Use emacs_fclose. * src/verbose.mk.in (AM_V_DX): Replace with D8 version.
This commit is contained in:
parent
2fa5583d96
commit
f9732131cf
35
configure.ac
35
configure.ac
@ -816,8 +816,8 @@ a valid path to android.jar. See config.log for more details.])
|
||||
Please verify that the path to the SDK build tools you specified is correct])
|
||||
fi
|
||||
|
||||
AC_PATH_PROGS([DX], [dx d8], [], "${SDK_BUILD_TOOLS}:$PATH")
|
||||
if test "DX" = ""; then
|
||||
AC_PATH_PROGS([D8], [d8], [], "${SDK_BUILD_TOOLS}:$PATH")
|
||||
if test "D8" = ""; then
|
||||
AC_MSG_ERROR([The Android dexer was not found.
|
||||
Please verify that the path to the SDK build tools you specified is correct])
|
||||
fi
|
||||
@ -867,6 +867,25 @@ in the ANDROID_CC variable when you ran configure.])
|
||||
|
||||
ANDROID_ABI=$android_abi
|
||||
|
||||
dnl Obtain the minimum SDK version of the resulting Emacs binary
|
||||
dnl built with this NDK.
|
||||
|
||||
ANDROID_MIN_SDK=8
|
||||
AC_MSG_CHECKING([for the lowest Android version Emacs can run on])
|
||||
[android_sdk=`echo "$cc_target" | grep -oE 'android([0-9][0-9]?)'`]
|
||||
|
||||
if test -n "$android_sdk"; then
|
||||
android_sdk=`echo "$android_sdk" | sed -n 's/android//p'`
|
||||
AC_MSG_RESULT([$android_sdk])
|
||||
ANDROID_MIN_SDK=$android_sdk
|
||||
else
|
||||
AC_MSG_RESULT([unknown ($cc_target); assuming 8])
|
||||
AC_MSG_WARN([configure could not determine the versions of Android \
|
||||
a binary built with this compiler will run on. The generated application \
|
||||
package will likely install on older systems but crash on startup.])
|
||||
fi
|
||||
AC_SUBST([ANDROID_MIN_SDK])
|
||||
|
||||
# Save confdefs.h and config.log for now.
|
||||
mv -f confdefs.h _confdefs.h
|
||||
mv -f config.log _config.log
|
||||
@ -899,7 +918,7 @@ fi
|
||||
AC_SUBST([ANDROID])
|
||||
AC_SUBST([JAVAC])
|
||||
AC_SUBST([AAPT])
|
||||
AC_SUBST([DX])
|
||||
AC_SUBST([D8])
|
||||
AC_SUBST([ZIPALIGN])
|
||||
AC_SUBST([ANDROID_JAR])
|
||||
AC_SUBST([ANDROID_ABI])
|
||||
@ -914,7 +933,7 @@ fi
|
||||
AC_SUBST([XCONFIGURE])
|
||||
|
||||
if test "$ANDROID" = "yes"; then
|
||||
# When --with-android is specified, all build options must be
|
||||
# When --with-android is specified, almost all build options must be
|
||||
# disabled, both within the recursive invocation of configure and
|
||||
# outside.
|
||||
with_xpm=no
|
||||
@ -938,11 +957,12 @@ if test "$ANDROID" = "yes"; then
|
||||
with_gpm=no
|
||||
with_dbus=no
|
||||
with_gsettings=no
|
||||
with_selinx=no
|
||||
with_selinux=no
|
||||
with_gnutls=no
|
||||
with_zlib=no
|
||||
with_modules=no
|
||||
with_threads=no
|
||||
|
||||
# zlib is available in android.
|
||||
fi
|
||||
|
||||
dnl This used to use changequote, but, apart from 'changequote is evil'
|
||||
@ -7211,6 +7231,9 @@ fi
|
||||
ARCH_INDEPENDENT_CONFIG_FILES([java/Makefile])
|
||||
ARCH_INDEPENDENT_CONFIG_FILES([xcompile/Makefile])
|
||||
|
||||
# Make java/AndroidManifest.xml
|
||||
ARCH_INDEPENDENT_CONFIG_FILES([java/AndroidManifest.xml])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
if test ! "$with_mailutils"; then
|
||||
|
84
java/AndroidManifest.xml.in
Normal file
84
java/AndroidManifest.xml.in
Normal file
@ -0,0 +1,84 @@
|
||||
<!-- @configure_input@
|
||||
|
||||
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/>. -->
|
||||
|
||||
<!-- targetSandboxVersion must be 1. Otherwise, fascist security
|
||||
restrictions prevent Emacs from making HTTP connections. -->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.gnu.emacs"
|
||||
android:targetSandboxVersion="1"
|
||||
android:installLocation="auto"
|
||||
android:versionName="@version@">
|
||||
|
||||
<!-- Paste in every permission in existence so Emacs can do
|
||||
anything. -->
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SMS"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.TRANSMIT_IR" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@"
|
||||
android:targetSdkVersion="28"/>
|
||||
|
||||
<application android:name="org.gnu.emacs.EmacsApplication"
|
||||
android:label="Emacs"
|
||||
android:hardwareAccelerated="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@android:style/Theme"
|
||||
android:debuggable="true"
|
||||
android:extractNativeLibs="true">
|
||||
<activity android:name="org.gnu.emacs.EmacsActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.gnu.emacs.EmacsMultitaskActivity"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/>
|
||||
|
||||
<service android:name="org.gnu.emacs.EmacsService"
|
||||
android:directBootAware="false"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:label="GNU Emacs service"/>
|
||||
</application>
|
||||
</manifest>
|
@ -18,13 +18,15 @@
|
||||
# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
version = @version@
|
||||
|
||||
-include ${top_builddir}/src/verbose.mk
|
||||
|
||||
SHELL = @SHELL@
|
||||
JAVAC = @JAVAC@
|
||||
AAPT = @AAPT@
|
||||
DX = @DX@
|
||||
D8 = @D8@
|
||||
ZIPALIGN = @ZIPALIGN@
|
||||
JARSIGNER = @JARSIGNER@
|
||||
ANDROID_JAR = @ANDROID_JAR@
|
||||
@ -39,6 +41,12 @@ SIGN_EMACS = -keystore emacs.keystore -storepass emacs1
|
||||
JAVA_FILES = $(shell find . -type f -name *.java)
|
||||
CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
|
||||
|
||||
# Compute the name for the Emacs application package. This should be:
|
||||
# emacs-<version>-<min-sdk>-<abi>.apk
|
||||
|
||||
ANDROID_MIN_SDK = @ANDROID_MIN_SDK@
|
||||
APK_NAME = emacs-$(version)-$(ANDROID_MIN_SDK)-$(ANDROID_ABI).apk
|
||||
|
||||
# How this stuff works.
|
||||
|
||||
# emacs.apk depends on emacs.apk-in, which is simply a ZIP archive
|
||||
@ -55,7 +63,7 @@ CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
|
||||
# assets/lisp/
|
||||
|
||||
.PHONY: emacs.apk-in all
|
||||
all: emacs.apk
|
||||
all: $(APK_NAME)
|
||||
|
||||
# Binaries to cross-compile.
|
||||
CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \
|
||||
@ -118,6 +126,18 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
|
||||
pushd install_temp; $(AAPT) add ../$@ `find assets -type f`; popd
|
||||
rm -rf install_temp
|
||||
|
||||
# Makefile itself.
|
||||
.PRECIOUS: ../config.status Makefile
|
||||
../config.status: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4
|
||||
$(MAKE) -C $(dir $@) $(notdir $@)
|
||||
Makefile: ../config.status $(top_builddir)/java/Makefile.in
|
||||
$(MAKE) -C .. java/$@
|
||||
|
||||
# AndroidManifest.xml:
|
||||
AndroidManifest.xml: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4 \
|
||||
AndroidManifest.xml.in
|
||||
pushd ..; ./config.status java/AndroidManifest.xml; popd
|
||||
|
||||
.SUFFIXES: .java .class
|
||||
.java.class &:
|
||||
$(AM_V_JAVAC) $(JAVAC) $(JAVAFLAGS) $<
|
||||
@ -126,7 +146,7 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
|
||||
# nested classes.
|
||||
|
||||
classes.dex: $(CLASS_FILES)
|
||||
$(AM_V_DX) $(DX) --classpath $(ANDROID_JAR) \
|
||||
$(AM_V_D8) $(D8) --classpath $(ANDROID_JAR) \
|
||||
$(subst $$,\$$,$(shell find . -type f -name *.class))
|
||||
|
||||
# When emacs.keystore expires, regenerate it with:
|
||||
@ -136,7 +156,7 @@ classes.dex: $(CLASS_FILES)
|
||||
|
||||
.PHONY: clean maintainer-clean
|
||||
|
||||
emacs.apk: classes.dex emacs.apk-in emacs.keystore
|
||||
$(APK_NAME): classes.dex emacs.apk-in emacs.keystore
|
||||
cp -f emacs.apk-in $@.unaligned
|
||||
$(AAPT) add $@.unaligned classes.dex
|
||||
$(JARSIGNER) $(SIGN_EMACS) $@.unaligned "Emacs keystore"
|
||||
@ -144,7 +164,7 @@ emacs.apk: classes.dex emacs.apk-in emacs.keystore
|
||||
rm -f $@.unaligned
|
||||
|
||||
clean:
|
||||
rm -f emacs.apk emacs.apk-in *.dex *.unaligned *.class
|
||||
rm -f *.apk emacs.apk-in *.dex *.unaligned *.class
|
||||
rm -rf install-temp
|
||||
find . -name '*.class' -delete
|
||||
|
||||
|
@ -30,6 +30,7 @@ activity=org.gnu.emacs.EmacsActivity
|
||||
gdb_port=5039
|
||||
jdb_port=64013
|
||||
jdb=no
|
||||
attach_existing=no
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
@ -48,6 +49,7 @@ while [ $# -gt 0 ]; do
|
||||
echo " --port PORT run the GDB server on a specific port"
|
||||
echo " --jdb-port PORT run the JDB server on a specific port"
|
||||
echo " --jdb run JDB instead of GDB"
|
||||
echo " --attach-existing attach to an existing process"
|
||||
echo " --help print this message"
|
||||
echo ""
|
||||
echo "Available devices:"
|
||||
@ -63,6 +65,9 @@ while [ $# -gt 0 ]; do
|
||||
"--port" )
|
||||
gdb_port=$1
|
||||
;;
|
||||
"--attach-existing" )
|
||||
attach_existing=yes
|
||||
;;
|
||||
"--" )
|
||||
shift
|
||||
gdbargs=$@
|
||||
@ -120,30 +125,32 @@ package_pids=`awk -- '{
|
||||
print $1
|
||||
}' <<< $package_pids`
|
||||
|
||||
# Finally, kill each existing process.
|
||||
for pid in $package_pids; do
|
||||
echo "Killing existing process $pid..."
|
||||
adb -s $device shell run-as $package kill -9 $pid &> /dev/null
|
||||
done
|
||||
if [ "$attach_existing" != "yes" ]; then
|
||||
# Finally, kill each existing process.
|
||||
for pid in $package_pids; do
|
||||
echo "Killing existing process $pid..."
|
||||
adb -s $device shell run-as $package kill -9 $pid &> /dev/null
|
||||
done
|
||||
|
||||
# Now run the main activity. This must be done as the adb user and
|
||||
# not as the package user.
|
||||
echo "Starting activity $activity and attaching debugger"
|
||||
# Now run the main activity. This must be done as the adb user and
|
||||
# not as the package user.
|
||||
echo "Starting activity $activity and attaching debugger"
|
||||
|
||||
# Exit if the activity could not be started.
|
||||
adb -s $device shell am start -D "$package/$activity"
|
||||
if [ ! $? ]; then
|
||||
exit 1;
|
||||
fi
|
||||
# Exit if the activity could not be started.
|
||||
adb -s $device shell am start -D "$package/$activity"
|
||||
if [ ! $? ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Now look for processes matching the package again.
|
||||
package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
|
||||
# Now look for processes matching the package again.
|
||||
package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
|
||||
|
||||
# Next, remove lines matching "ps" itself.
|
||||
package_pids=`awk -- '{
|
||||
# Next, remove lines matching "ps" itself.
|
||||
package_pids=`awk -- '{
|
||||
if (!match ($0, /(PID|ps)/))
|
||||
print $1
|
||||
}' <<< $package_pids`
|
||||
fi
|
||||
|
||||
pid=$package_pids
|
||||
num_pids=`wc -w <<< "$package_pids"`
|
||||
|
@ -48,6 +48,9 @@ public class EmacsActivity extends Activity
|
||||
/* The currently focused window. */
|
||||
public static EmacsWindow focusedWindow;
|
||||
|
||||
/* Whether or not this activity is paused. */
|
||||
private boolean isPaused;
|
||||
|
||||
static
|
||||
{
|
||||
focusedActivities = new ArrayList<EmacsActivity> ();
|
||||
@ -60,7 +63,7 @@ public class EmacsActivity extends Activity
|
||||
focusedWindow = window;
|
||||
|
||||
for (EmacsWindow child : window.children)
|
||||
invalidateFocus1 (window);
|
||||
invalidateFocus1 (child);
|
||||
}
|
||||
|
||||
public static void
|
||||
@ -103,6 +106,9 @@ public class EmacsActivity extends Activity
|
||||
/* Clear the window's pointer to this activity and remove the
|
||||
window's view. */
|
||||
window.setConsumer (null);
|
||||
|
||||
/* The window can't be iconified any longer. */
|
||||
window.noticeDeiconified ();
|
||||
layout.removeView (window.view);
|
||||
window = null;
|
||||
|
||||
@ -114,6 +120,8 @@ public class EmacsActivity extends Activity
|
||||
public void
|
||||
attachWindow (EmacsWindow child)
|
||||
{
|
||||
Log.d (TAG, "attachWindow: " + child);
|
||||
|
||||
if (window != null)
|
||||
throw new IllegalStateException ("trying to attach window when one"
|
||||
+ " already exists");
|
||||
@ -124,6 +132,10 @@ public class EmacsActivity extends Activity
|
||||
layout.addView (window.view);
|
||||
child.setConsumer (this);
|
||||
|
||||
/* If the activity is iconified, send that to the window. */
|
||||
if (isPaused)
|
||||
window.noticeIconified ();
|
||||
|
||||
/* Invalidate the focus. */
|
||||
invalidateFocus ();
|
||||
}
|
||||
@ -148,6 +160,9 @@ public class EmacsActivity extends Activity
|
||||
{
|
||||
FrameLayout.LayoutParams params;
|
||||
|
||||
/* Set the theme to one without a title bar. */
|
||||
setTheme (android.R.style.Theme_NoTitleBar);
|
||||
|
||||
params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
|
||||
@ -192,4 +207,24 @@ public class EmacsActivity extends Activity
|
||||
|
||||
invalidateFocus ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
onPause ()
|
||||
{
|
||||
isPaused = true;
|
||||
|
||||
EmacsWindowAttachmentManager.MANAGER.noticeIconified (this);
|
||||
super.onResume ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void
|
||||
onResume ()
|
||||
{
|
||||
isPaused = false;
|
||||
|
||||
EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this);
|
||||
super.onResume ();
|
||||
}
|
||||
};
|
||||
|
@ -96,11 +96,34 @@ public static native void sendButtonPress (short window, int x, int y,
|
||||
long time, int state,
|
||||
int button);
|
||||
|
||||
/* Send an ANDROID_BUTTON_RELEASE event. */
|
||||
/* Send an ANDROID_BUTTON_RELEASE event. */
|
||||
public static native void sendButtonRelease (short window, int x, int y,
|
||||
long time, int state,
|
||||
int button);
|
||||
|
||||
/* Send an ANDROID_TOUCH_DOWN event. */
|
||||
public static native void sendTouchDown (short window, int x, int y,
|
||||
long time, int pointerID);
|
||||
|
||||
/* Send an ANDROID_TOUCH_UP event. */
|
||||
public static native void sendTouchUp (short window, int x, int y,
|
||||
long time, int pointerID);
|
||||
|
||||
/* Send an ANDROID_TOUCH_MOVE event. */
|
||||
public static native void sendTouchMove (short window, int x, int y,
|
||||
long time, int pointerID);
|
||||
|
||||
/* Send an ANDROID_WHEEL event. */
|
||||
public static native void sendWheel (short window, int x, int y,
|
||||
long time, int state,
|
||||
float xDelta, float yDelta);
|
||||
|
||||
/* Send an ANDROID_ICONIFIED event. */
|
||||
public static native void sendIconified (short window);
|
||||
|
||||
/* Send an ANDROID_DEICONIFIED event. */
|
||||
public static native void sendDeiconified (short window);
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary ("emacs");
|
||||
|
@ -149,8 +149,6 @@ else if (style.contains ("Expanded"))
|
||||
}
|
||||
else
|
||||
familyName = fileName;
|
||||
|
||||
Log.d (TAG, "Initialized new typeface " + familyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -321,17 +319,12 @@ protected class Sdk7FontObject extends FontObject
|
||||
|
||||
list = new LinkedList<FontEntity> ();
|
||||
|
||||
Log.d (TAG, ("Looking for fonts matching font spec: "
|
||||
+ fontSpec.toString ()));
|
||||
|
||||
for (i = 0; i < typefaceList.length; ++i)
|
||||
{
|
||||
if (checkMatch (typefaceList[i], fontSpec))
|
||||
list.add (new Sdk7FontEntity (typefaceList[i]));
|
||||
}
|
||||
|
||||
Log.d (TAG, "Found font entities: " + list.toString ());
|
||||
|
||||
return (FontEntity[]) list.toArray (new FontEntity[0]);
|
||||
}
|
||||
|
||||
|
@ -28,20 +28,27 @@
|
||||
import android.graphics.Point;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.os.IBinder;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorManager;
|
||||
import android.os.VibrationEffect;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import android.hardware.input.InputManager;
|
||||
|
||||
class Holder<T>
|
||||
{
|
||||
T thing;
|
||||
@ -250,4 +257,113 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
|
||||
{
|
||||
window.clearArea (x, y, width, height);
|
||||
}
|
||||
|
||||
@SuppressWarnings ("deprecation")
|
||||
public void
|
||||
ringBell ()
|
||||
{
|
||||
Vibrator vibrator;
|
||||
VibrationEffect effect;
|
||||
VibratorManager vibratorManager;
|
||||
Object tem;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
{
|
||||
tem = getSystemService (Context.VIBRATOR_MANAGER_SERVICE);
|
||||
vibratorManager = (VibratorManager) tem;
|
||||
vibrator = vibratorManager.getDefaultVibrator ();
|
||||
}
|
||||
else
|
||||
vibrator
|
||||
= (Vibrator) getSystemService (Context.VIBRATOR_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
{
|
||||
effect
|
||||
= VibrationEffect.createOneShot (50,
|
||||
VibrationEffect.DEFAULT_AMPLITUDE);
|
||||
vibrator.vibrate (effect);
|
||||
}
|
||||
else
|
||||
vibrator.vibrate (50);
|
||||
}
|
||||
|
||||
public short[]
|
||||
queryTree (EmacsWindow window)
|
||||
{
|
||||
short[] array;
|
||||
List<EmacsWindow> windowList;
|
||||
int i;
|
||||
|
||||
if (window == null)
|
||||
/* Just return all the windows without a parent. */
|
||||
windowList = EmacsWindowAttachmentManager.MANAGER.copyWindows ();
|
||||
else
|
||||
windowList = window.children;
|
||||
|
||||
array = new short[windowList.size () + 1];
|
||||
i = 1;
|
||||
|
||||
array[0] = window.parent != null ? 0 : window.parent.handle;
|
||||
|
||||
for (EmacsWindow treeWindow : windowList)
|
||||
array[i++] = treeWindow.handle;
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public int
|
||||
getScreenWidth (boolean mmWise)
|
||||
{
|
||||
DisplayMetrics metrics;
|
||||
|
||||
metrics = getResources ().getDisplayMetrics ();
|
||||
|
||||
if (!mmWise)
|
||||
return metrics.widthPixels;
|
||||
else
|
||||
return (int) ((metrics.widthPixels / metrics.xdpi) * 2540.0);
|
||||
}
|
||||
|
||||
public int
|
||||
getScreenHeight (boolean mmWise)
|
||||
{
|
||||
DisplayMetrics metrics;
|
||||
|
||||
metrics = getResources ().getDisplayMetrics ();
|
||||
|
||||
if (!mmWise)
|
||||
return metrics.heightPixels;
|
||||
else
|
||||
return (int) ((metrics.heightPixels / metrics.ydpi) * 2540.0);
|
||||
}
|
||||
|
||||
public boolean
|
||||
detectMouse ()
|
||||
{
|
||||
InputManager manager;
|
||||
InputDevice device;
|
||||
int[] ids;
|
||||
int i;
|
||||
|
||||
if (Build.VERSION.SDK_INT
|
||||
< Build.VERSION_CODES.JELLY_BEAN)
|
||||
return false;
|
||||
|
||||
manager = (InputManager) getSystemService (Context.INPUT_SERVICE);
|
||||
ids = manager.getInputDeviceIds ();
|
||||
|
||||
for (i = 0; i < ids.length; ++i)
|
||||
{
|
||||
device = manager.getInputDevice (ids[i]);
|
||||
|
||||
if (device == null)
|
||||
continue;
|
||||
|
||||
if (device.supportsSource (InputDevice.SOURCE_MOUSE))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@ -27,8 +27,12 @@
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class EmacsSurfaceView extends SurfaceView
|
||||
{
|
||||
private static final String TAG = "EmacsSurfaceView";
|
||||
|
||||
public Object surfaceChangeLock;
|
||||
private boolean created;
|
||||
|
||||
@ -45,6 +49,7 @@ public class EmacsSurfaceView extends SurfaceView
|
||||
surfaceChanged (SurfaceHolder holder, int format,
|
||||
int width, int height)
|
||||
{
|
||||
Log.d (TAG, "surfaceChanged: " + view);
|
||||
view.swapBuffers ();
|
||||
}
|
||||
|
||||
@ -54,9 +59,13 @@ public class EmacsSurfaceView extends SurfaceView
|
||||
{
|
||||
synchronized (surfaceChangeLock)
|
||||
{
|
||||
Log.d (TAG, "surfaceCreated: " + view);
|
||||
created = true;
|
||||
view.swapBuffers ();
|
||||
}
|
||||
|
||||
/* Drop the lock when doing this, or a deadlock can
|
||||
result. */
|
||||
view.swapBuffers ();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,6 +74,7 @@ public class EmacsSurfaceView extends SurfaceView
|
||||
{
|
||||
synchronized (surfaceChangeLock)
|
||||
{
|
||||
Log.d (TAG, "surfaceDestroyed: " + view);
|
||||
created = false;
|
||||
}
|
||||
}
|
||||
@ -93,6 +103,16 @@ public class EmacsSurfaceView extends SurfaceView
|
||||
return holder.lockCanvas (damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void
|
||||
onLayout (boolean changed, int left, int top, int right,
|
||||
int bottom)
|
||||
{
|
||||
Log.d (TAG, ("onLayout: " + left + " " + top + " " + right
|
||||
+ " " + bottom + " -- " + changed + " visibility "
|
||||
+ getVisibility ()));
|
||||
}
|
||||
|
||||
/* This method is only used during debugging when it seems damage
|
||||
isn't working correctly. */
|
||||
|
||||
|
@ -87,12 +87,27 @@ public class EmacsView extends ViewGroup
|
||||
|
||||
/* Create the surface view. */
|
||||
this.surfaceView = new EmacsSurfaceView (this);
|
||||
this.surfaceView.setZOrderMediaOverlay (true);
|
||||
addView (this.surfaceView);
|
||||
|
||||
/* Not sure exactly what this does but it makes things magically
|
||||
work. Why is something as simple as XRaiseWindow so involved
|
||||
on Android? */
|
||||
setChildrenDrawingOrderEnabled (true);
|
||||
|
||||
/* Get rid of the foreground and background tint. */
|
||||
setBackgroundTintList (null);
|
||||
setForegroundTintList (null);
|
||||
}
|
||||
|
||||
private void
|
||||
handleDirtyBitmap ()
|
||||
{
|
||||
Bitmap oldBitmap;
|
||||
|
||||
/* Save the old bitmap. */
|
||||
oldBitmap = bitmap;
|
||||
|
||||
/* Recreate the front and back buffer bitmaps. */
|
||||
bitmap
|
||||
= Bitmap.createBitmap (bitmapDirty.width (),
|
||||
@ -103,12 +118,23 @@ public class EmacsView extends ViewGroup
|
||||
/* And canvases. */
|
||||
canvas = new Canvas (bitmap);
|
||||
|
||||
/* If Emacs is drawing to the bitmap right now from the
|
||||
main thread, the image contents are lost until the next
|
||||
ConfigureNotify and complete garbage. Sorry! */
|
||||
/* Copy over the contents of the old bitmap. */
|
||||
if (oldBitmap != null)
|
||||
canvas.drawBitmap (oldBitmap, 0f, 0f, new Paint ());
|
||||
|
||||
bitmapDirty = null;
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
explicitlyDirtyBitmap (Rect rect)
|
||||
{
|
||||
if (bitmapDirty == null
|
||||
&& (bitmap == null
|
||||
|| rect.width () != bitmap.getWidth ()
|
||||
|| rect.height () != bitmap.getHeight ()))
|
||||
bitmapDirty = rect;
|
||||
}
|
||||
|
||||
public synchronized Bitmap
|
||||
getBitmap ()
|
||||
{
|
||||
@ -168,25 +194,31 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
|
||||
View child;
|
||||
Rect windowRect;
|
||||
|
||||
count = getChildCount ();
|
||||
|
||||
if (changed || mustReportLayout)
|
||||
{
|
||||
mustReportLayout = false;
|
||||
window.viewLayout (left, top, right, bottom);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
if (changed
|
||||
/* Check that a change has really happened. */
|
||||
&& (bitmapDirty == null
|
||||
|| bitmapDirty.width () != right - left
|
||||
|| bitmapDirty.height () != bottom - top))
|
||||
bitmapDirty = new Rect (left, top, right, bottom);
|
||||
|
||||
count = getChildCount ();
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
child = getChildAt (i);
|
||||
|
||||
Log.d (TAG, "onLayout: " + child);
|
||||
|
||||
if (child == surfaceView)
|
||||
/* The child is the surface view, so give it the entire
|
||||
view. */
|
||||
child.layout (left, top, right, bottom);
|
||||
child.layout (0, 0, right - left, bottom - top);
|
||||
else if (child.getVisibility () != GONE)
|
||||
{
|
||||
if (!(child instanceof EmacsView))
|
||||
@ -201,59 +233,68 @@ else if (child.getVisibility () != GONE)
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
public void
|
||||
damageRect (Rect damageRect)
|
||||
{
|
||||
damageRegion.union (damageRect);
|
||||
synchronized (damageRegion)
|
||||
{
|
||||
damageRegion.union (damageRect);
|
||||
}
|
||||
}
|
||||
|
||||
/* This method is called from both the UI thread and the Emacs
|
||||
thread. */
|
||||
|
||||
public synchronized void
|
||||
public void
|
||||
swapBuffers (boolean force)
|
||||
{
|
||||
Canvas canvas;
|
||||
Rect damageRect;
|
||||
Bitmap bitmap;
|
||||
|
||||
if (damageRegion.isEmpty ())
|
||||
return;
|
||||
/* Code must always take damageRegion, and then surfaceChangeLock,
|
||||
never the other way around! */
|
||||
|
||||
bitmap = getBitmap ();
|
||||
|
||||
/* Emacs must take the following lock to ensure the access to the
|
||||
canvas occurs with the surface created. Otherwise, Android
|
||||
will throttle calls to lockCanvas. */
|
||||
|
||||
synchronized (surfaceView.surfaceChangeLock)
|
||||
synchronized (damageRegion)
|
||||
{
|
||||
damageRect = damageRegion.getBounds ();
|
||||
|
||||
if (!surfaceView.isCreated ())
|
||||
if (damageRegion.isEmpty ())
|
||||
return;
|
||||
|
||||
if (bitmap == null)
|
||||
return;
|
||||
bitmap = getBitmap ();
|
||||
|
||||
/* Lock the canvas with the specified damage. */
|
||||
canvas = surfaceView.lockCanvas (damageRect);
|
||||
/* Emacs must take the following lock to ensure the access to the
|
||||
canvas occurs with the surface created. Otherwise, Android
|
||||
will throttle calls to lockCanvas. */
|
||||
|
||||
/* Return if locking the canvas failed. */
|
||||
if (canvas == null)
|
||||
return;
|
||||
synchronized (surfaceView.surfaceChangeLock)
|
||||
{
|
||||
damageRect = damageRegion.getBounds ();
|
||||
|
||||
/* Copy from the back buffer to the canvas. If damageRect was
|
||||
made empty, then draw the entire back buffer. */
|
||||
if (!surfaceView.isCreated ())
|
||||
return;
|
||||
|
||||
if (damageRect.isEmpty ())
|
||||
canvas.drawBitmap (bitmap, 0f, 0f, paint);
|
||||
else
|
||||
canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
|
||||
if (bitmap == null)
|
||||
return;
|
||||
|
||||
/* Unlock the canvas and clear the damage. */
|
||||
surfaceView.unlockCanvasAndPost (canvas);
|
||||
damageRegion.setEmpty ();
|
||||
/* Lock the canvas with the specified damage. */
|
||||
canvas = surfaceView.lockCanvas (damageRect);
|
||||
|
||||
/* Return if locking the canvas failed. */
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
/* Copy from the back buffer to the canvas. If damageRect was
|
||||
made empty, then draw the entire back buffer. */
|
||||
|
||||
if (damageRect.isEmpty ())
|
||||
canvas.drawBitmap (bitmap, 0f, 0f, paint);
|
||||
else
|
||||
canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
|
||||
|
||||
/* Unlock the canvas and clear the damage. */
|
||||
surfaceView.unlockCanvasAndPost (canvas);
|
||||
damageRegion.setEmpty ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,6 +349,78 @@ else if (child.getVisibility () != GONE)
|
||||
public boolean
|
||||
onTouchEvent (MotionEvent motion)
|
||||
{
|
||||
return window.onSomeKindOfMotionEvent (motion);
|
||||
return window.onTouchEvent (motion);
|
||||
}
|
||||
|
||||
private void
|
||||
moveChildToBack (View child)
|
||||
{
|
||||
int index;
|
||||
|
||||
index = indexOfChild (child);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
detachViewFromParent (index);
|
||||
|
||||
/* The view at 0 is the surface view. */
|
||||
attachViewToParent (child, 1,
|
||||
child.getLayoutParams());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions must not be called if the view has no
|
||||
parent, or is parented to an activity. */
|
||||
|
||||
public void
|
||||
raise ()
|
||||
{
|
||||
EmacsView parent;
|
||||
|
||||
parent = (EmacsView) getParent ();
|
||||
|
||||
Log.d (TAG, "raise: parent " + parent);
|
||||
|
||||
if (parent.indexOfChild (this)
|
||||
== parent.getChildCount () - 1)
|
||||
return;
|
||||
|
||||
parent.bringChildToFront (this);
|
||||
|
||||
/* Yes, all of this is really necessary! */
|
||||
parent.requestLayout ();
|
||||
parent.invalidate ();
|
||||
requestLayout ();
|
||||
invalidate ();
|
||||
|
||||
/* The surface view must be destroyed and recreated. */
|
||||
removeView (surfaceView);
|
||||
addView (surfaceView, 0);
|
||||
}
|
||||
|
||||
public void
|
||||
lower ()
|
||||
{
|
||||
EmacsView parent;
|
||||
|
||||
parent = (EmacsView) getParent ();
|
||||
|
||||
Log.d (TAG, "lower: parent " + parent);
|
||||
|
||||
if (parent.indexOfChild (this) == 1)
|
||||
return;
|
||||
|
||||
parent.moveChildToBack (this);
|
||||
|
||||
/* Yes, all of this is really necessary! */
|
||||
parent.requestLayout ();
|
||||
parent.invalidate ();
|
||||
requestLayout ();
|
||||
invalidate ();
|
||||
|
||||
/* The surface view must be removed and attached again. */
|
||||
removeView (surfaceView);
|
||||
addView (surfaceView, 0);
|
||||
}
|
||||
};
|
||||
|
@ -22,6 +22,7 @@
|
||||
import java.lang.IllegalStateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Canvas;
|
||||
@ -50,9 +51,29 @@ their views are attached to the parent activity (if any), else
|
||||
Views are also drawables, meaning they can accept drawing
|
||||
requests. */
|
||||
|
||||
/* Help wanted. What does not work includes `EmacsView.raise',
|
||||
`EmacsView.lower', reparenting a window onto another window.
|
||||
|
||||
All three are likely undocumented restrictions within
|
||||
EmacsSurface. */
|
||||
|
||||
public class EmacsWindow extends EmacsHandleObject
|
||||
implements EmacsDrawable
|
||||
{
|
||||
private static final String TAG = "EmacsWindow";
|
||||
|
||||
private class Coordinate
|
||||
{
|
||||
/* Integral coordinate. */
|
||||
int x, y;
|
||||
|
||||
Coordinate (int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
};
|
||||
|
||||
/* The view associated with the window. */
|
||||
public EmacsView view;
|
||||
|
||||
@ -60,12 +81,16 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
private Rect rect;
|
||||
|
||||
/* The parent window, or null if it is the root window. */
|
||||
private EmacsWindow parent;
|
||||
public EmacsWindow parent;
|
||||
|
||||
/* List of all children in stacking order. This must be kept
|
||||
consistent! */
|
||||
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;
|
||||
|
||||
@ -77,6 +102,14 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
last button press or release event. */
|
||||
private int lastButtonState, lastModifiers;
|
||||
|
||||
/* Whether or not the window is mapped, and whether or not it is
|
||||
deiconified. */
|
||||
private boolean isMapped, isIconified;
|
||||
|
||||
/* Whether or not to ask for focus upon being mapped, and whether or
|
||||
not the window should be focusable. */
|
||||
private boolean dontFocusOnMap, dontAcceptFocus;
|
||||
|
||||
public
|
||||
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
|
||||
int width, int height)
|
||||
@ -84,6 +117,7 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
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. */
|
||||
@ -97,7 +131,7 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
if (parent != null)
|
||||
{
|
||||
parent.children.add (this);
|
||||
parent.view.post (new Runnable () {
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
@ -106,23 +140,6 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
scratchGC = new EmacsGC ((short) 0);
|
||||
}
|
||||
@ -159,7 +176,7 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
+ "children!");
|
||||
|
||||
/* Remove the view from its parent and make it invisible. */
|
||||
view.post (new Runnable () {
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
@ -174,7 +191,7 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
|
||||
parent = (View) view.getParent ();
|
||||
|
||||
if (parent != null && attached == null)
|
||||
if (parent != null)
|
||||
((ViewGroup) parent).removeView (view);
|
||||
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
@ -199,24 +216,33 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
public void
|
||||
viewLayout (int left, int top, int right, int bottom)
|
||||
{
|
||||
int rectWidth, rectHeight;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
rect.left = left;
|
||||
rect.top = top;
|
||||
rect.right = right;
|
||||
rect.bottom = bottom;
|
||||
|
||||
EmacsNative.sendConfigureNotify (this.handle,
|
||||
System.currentTimeMillis (),
|
||||
left, top, rect.width (),
|
||||
rect.height ());
|
||||
}
|
||||
|
||||
rectWidth = right - left;
|
||||
rectHeight = bottom - top;
|
||||
|
||||
EmacsNative.sendConfigureNotify (this.handle,
|
||||
System.currentTimeMillis (),
|
||||
left, top, rectWidth,
|
||||
rectHeight);
|
||||
}
|
||||
|
||||
public void
|
||||
requestViewLayout ()
|
||||
{
|
||||
view.post (new Runnable () {
|
||||
/* This is necessary because otherwise subsequent drawing on the
|
||||
Emacs thread may be lost. */
|
||||
view.explicitlyDirtyBitmap (rect);
|
||||
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
@ -261,28 +287,77 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
public void
|
||||
mapWindow ()
|
||||
{
|
||||
view.post (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
if (isMapped)
|
||||
return;
|
||||
|
||||
view.setVisibility (View.VISIBLE);
|
||||
/* Eventually this should check no-focus-on-map. */
|
||||
view.requestFocus ();
|
||||
}
|
||||
});
|
||||
isMapped = true;
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
|
||||
/* Make the view visible, first of all. */
|
||||
view.setVisibility (View.VISIBLE);
|
||||
|
||||
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
|
||||
{
|
||||
/* Do the same thing as above, but don't register this
|
||||
window. */
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
view.setVisibility (View.VISIBLE);
|
||||
|
||||
if (!getDontFocusOnMap ())
|
||||
/* Eventually this should check no-focus-on-map. */
|
||||
view.requestFocus ();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
unmapWindow ()
|
||||
{
|
||||
if (!isMapped)
|
||||
return;
|
||||
|
||||
isMapped = false;
|
||||
|
||||
view.post (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
|
||||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
|
||||
view.setVisibility (View.GONE);
|
||||
|
||||
/* Now that the window is unmapped, unregister it as
|
||||
well. */
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -413,6 +488,161 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* Return the ID of the pointer which changed in EVENT. Value is -1
|
||||
if it could not be determined, else the pointer that changed, or
|
||||
-2 if -1 would have been returned, but there is also a pointer
|
||||
that is a mouse. */
|
||||
|
||||
private int
|
||||
figureChange (MotionEvent event)
|
||||
{
|
||||
int pointerID, i, truncatedX, truncatedY, pointerIndex;
|
||||
Coordinate coordinate;
|
||||
boolean mouseFlag;
|
||||
|
||||
/* pointerID is always initialized but the Java compiler is too
|
||||
dumb to know that. */
|
||||
pointerID = -1;
|
||||
mouseFlag = false;
|
||||
|
||||
switch (event.getActionMasked ())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
/* Primary pointer pressed with index 0. */
|
||||
|
||||
/* Detect mice. If this is a mouse event, give it to
|
||||
onSomeKindOfMotionEvent. */
|
||||
if ((Build.VERSION.SDK_INT
|
||||
>= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
&& event.getToolType (0) == MotionEvent.TOOL_TYPE_MOUSE)
|
||||
return -2;
|
||||
|
||||
pointerID = event.getPointerId (0);
|
||||
pointerMap.put (pointerID,
|
||||
new Coordinate ((int) event.getX (0),
|
||||
(int) event.getY (0)));
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
/* Primary pointer released with index 0. */
|
||||
pointerID = event.getPointerId (0);
|
||||
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);
|
||||
pointerMap.put (pointerID,
|
||||
new Coordinate ((int) event.getX (pointerID),
|
||||
(int) event.getY (pointerID)));
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
/* Pointer removed. Remove it from the map. */
|
||||
pointerIndex = event.getActionIndex ();
|
||||
pointerID = event.getPointerId (pointerIndex);
|
||||
pointerMap.remove (pointerID);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Loop through each pointer in the event. */
|
||||
for (i = 0; i < event.getPointerCount (); ++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;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if this is a mouse. If so, set the mouseFlag. */
|
||||
if ((Build.VERSION.SDK_INT
|
||||
>= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
&& event.getToolType (i) == MotionEvent.TOOL_TYPE_MOUSE)
|
||||
mouseFlag = true;
|
||||
}
|
||||
|
||||
/* Set the pointer ID to -1 if the loop failed to find any
|
||||
changed pointer. If a mouse pointer was found, set it to
|
||||
-2. */
|
||||
if (i == event.getPointerCount ())
|
||||
pointerID = (mouseFlag ? -2 : -1);
|
||||
}
|
||||
|
||||
/* Return the pointer ID. */
|
||||
return pointerID;
|
||||
}
|
||||
|
||||
public boolean
|
||||
onTouchEvent (MotionEvent event)
|
||||
{
|
||||
int pointerID, index;
|
||||
|
||||
/* Extract the ``touch ID'' (or in Android, the ``pointer
|
||||
ID''.) */
|
||||
pointerID = figureChange (event);
|
||||
|
||||
if (pointerID < 0)
|
||||
{
|
||||
/* If this is a mouse event, give it to
|
||||
onSomeKindOfMotionEvent. */
|
||||
if (pointerID == -2)
|
||||
return onSomeKindOfMotionEvent (event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find the pointer index corresponding to the event. */
|
||||
index = event.findPointerIndex (pointerID);
|
||||
|
||||
switch (event.getActionMasked ())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
/* Touch down event. */
|
||||
EmacsNative.sendTouchDown (this.handle, (int) event.getX (index),
|
||||
(int) event.getY (index),
|
||||
event.getEventTime (), pointerID);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
/* Touch up event. */
|
||||
EmacsNative.sendTouchUp (this.handle, (int) event.getX (index),
|
||||
(int) event.getY (index),
|
||||
event.getEventTime (), pointerID);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
/* Pointer motion event. */
|
||||
EmacsNative.sendTouchMove (this.handle, (int) event.getX (index),
|
||||
(int) event.getY (index),
|
||||
event.getEventTime (), pointerID);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean
|
||||
onSomeKindOfMotionEvent (MotionEvent event)
|
||||
{
|
||||
@ -472,13 +702,201 @@ public class EmacsWindow extends EmacsHandleObject
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_UP:
|
||||
/* Emacs must return true even though touch events are not yet
|
||||
handled, because the value of this function is used by the
|
||||
system to decide whether or not Emacs gets ACTION_MOVE
|
||||
/* Emacs must return true even though touch events are not
|
||||
handled here, because the value of this function is used by
|
||||
the system to decide whether or not Emacs gets ACTION_MOVE
|
||||
events. */
|
||||
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 (),
|
||||
lastModifiers,
|
||||
event.getAxisValue (MotionEvent.AXIS_HSCROLL),
|
||||
event.getAxisValue (MotionEvent.AXIS_VSCROLL));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public 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. */
|
||||
synchronized (this)
|
||||
{
|
||||
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;
|
||||
View parent;
|
||||
|
||||
/* First, detach this window if necessary. */
|
||||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
|
||||
/* Also unparent this view. */
|
||||
parent = (View) view.getParent ();
|
||||
|
||||
if (parent != null)
|
||||
((ViewGroup) 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 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 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 int[]
|
||||
getWindowGeometry ()
|
||||
{
|
||||
int[] array;
|
||||
Rect rect;
|
||||
|
||||
array = new int[4];
|
||||
rect = getGeometry ();
|
||||
|
||||
array[0] = rect.left;
|
||||
array[1] = rect.top;
|
||||
array[2] = rect.width ();
|
||||
array[3] = rect.height ();
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public void
|
||||
noticeIconified ()
|
||||
{
|
||||
isIconified = true;
|
||||
EmacsNative.sendIconified (this.handle);
|
||||
}
|
||||
|
||||
public void
|
||||
noticeDeiconified ()
|
||||
{
|
||||
isIconified = false;
|
||||
EmacsNative.sendDeiconified (this.handle);
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
setDontAcceptFocus (final boolean dontAcceptFocus)
|
||||
{
|
||||
this.dontAcceptFocus = 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;
|
||||
}
|
||||
};
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -68,7 +69,7 @@ public interface WindowConsumer
|
||||
};
|
||||
|
||||
private List<WindowConsumer> consumers;
|
||||
private List<EmacsWindow> windows;
|
||||
public List<EmacsWindow> windows;
|
||||
|
||||
public
|
||||
EmacsWindowAttachmentManager ()
|
||||
@ -98,12 +99,19 @@ public interface WindowConsumer
|
||||
EmacsNative.sendWindowAction ((short) 0, 0);
|
||||
}
|
||||
|
||||
public void
|
||||
public synchronized void
|
||||
registerWindow (EmacsWindow window)
|
||||
{
|
||||
Intent intent;
|
||||
|
||||
Log.d (TAG, "registerWindow " + window);
|
||||
Log.d (TAG, "registerWindow (maybe): " + window);
|
||||
|
||||
if (windows.contains (window))
|
||||
/* The window is already registered. */
|
||||
return;
|
||||
|
||||
Log.d (TAG, "registerWindow: " + window);
|
||||
|
||||
windows.add (window);
|
||||
|
||||
for (WindowConsumer consumer : consumers)
|
||||
@ -146,7 +154,7 @@ public interface WindowConsumer
|
||||
consumers.remove (consumer);
|
||||
}
|
||||
|
||||
public void
|
||||
public synchronized void
|
||||
detachWindow (EmacsWindow window)
|
||||
{
|
||||
WindowConsumer consumer;
|
||||
@ -162,5 +170,43 @@ public interface WindowConsumer
|
||||
consumers.remove (consumer);
|
||||
consumer.destroy ();
|
||||
}
|
||||
|
||||
windows.remove (window);
|
||||
}
|
||||
|
||||
public void
|
||||
noticeIconified (WindowConsumer consumer)
|
||||
{
|
||||
EmacsWindow window;
|
||||
|
||||
Log.d (TAG, "noticeIconified " + consumer);
|
||||
|
||||
/* If a window is attached, send the appropriate iconification
|
||||
events. */
|
||||
window = consumer.getAttachedWindow ();
|
||||
|
||||
if (window != null)
|
||||
window.noticeIconified ();
|
||||
}
|
||||
|
||||
public void
|
||||
noticeDeiconified (WindowConsumer consumer)
|
||||
{
|
||||
EmacsWindow window;
|
||||
|
||||
Log.d (TAG, "noticeDeiconified " + consumer);
|
||||
|
||||
/* If a window is attached, send the appropriate iconification
|
||||
events. */
|
||||
window = consumer.getAttachedWindow ();
|
||||
|
||||
if (window != null)
|
||||
window.noticeDeiconified ();
|
||||
}
|
||||
|
||||
public synchronized List<EmacsWindow>
|
||||
copyWindows ()
|
||||
{
|
||||
return new ArrayList<EmacsWindow> (windows);
|
||||
}
|
||||
};
|
||||
|
@ -1647,6 +1647,7 @@ live frame and defaults to the selected one."
|
||||
(declare-function ns-frame-geometry "nsfns.m" (&optional frame))
|
||||
(declare-function pgtk-frame-geometry "pgtkfns.c" (&optional frame))
|
||||
(declare-function haiku-frame-geometry "haikufns.c" (&optional frame))
|
||||
(declare-function android-frame-geometry "androidfns.c" (&optional frame))
|
||||
|
||||
(defun frame-geometry (&optional frame)
|
||||
"Return geometric attributes of FRAME.
|
||||
@ -1700,6 +1701,8 @@ and width values are in pixels.
|
||||
(pgtk-frame-geometry frame))
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-frame-geometry frame))
|
||||
((eq frame-type 'android)
|
||||
(android-frame-geometry frame))
|
||||
(t
|
||||
(list
|
||||
'(outer-position 0 . 0)
|
||||
@ -1826,6 +1829,7 @@ of frames like calls to map a frame or change its visibility."
|
||||
(declare-function ns-frame-edges "nsfns.m" (&optional frame type))
|
||||
(declare-function pgtk-frame-edges "pgtkfns.c" (&optional frame type))
|
||||
(declare-function haiku-frame-edges "haikufns.c" (&optional frame type))
|
||||
(declare-function android-frame-edges "androidfns.c" (&optional frame type))
|
||||
|
||||
(defun frame-edges (&optional frame type)
|
||||
"Return coordinates of FRAME's edges.
|
||||
@ -1853,6 +1857,8 @@ FRAME."
|
||||
(pgtk-frame-edges frame type))
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-frame-edges frame type))
|
||||
((eq frame-type 'android)
|
||||
(android-frame-edges frame type))
|
||||
(t
|
||||
(list 0 0 (frame-width frame) (frame-height frame))))))
|
||||
|
||||
@ -1861,6 +1867,7 @@ FRAME."
|
||||
(declare-function ns-mouse-absolute-pixel-position "nsfns.m")
|
||||
(declare-function pgtk-mouse-absolute-pixel-position "pgtkfns.c")
|
||||
(declare-function haiku-mouse-absolute-pixel-position "haikufns.c")
|
||||
(declare-function android-mouse-absolute-pixel-position "androidfns.c")
|
||||
|
||||
(defun mouse-absolute-pixel-position ()
|
||||
"Return absolute position of mouse cursor in pixels.
|
||||
@ -1879,6 +1886,8 @@ position (0, 0) of the selected frame's terminal."
|
||||
(pgtk-mouse-absolute-pixel-position))
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-mouse-absolute-pixel-position))
|
||||
((eq frame-type 'android)
|
||||
(android-mouse-absolute-pixel-position))
|
||||
(t
|
||||
(cons 0 0)))))
|
||||
|
||||
@ -1887,6 +1896,8 @@ position (0, 0) of the selected frame's terminal."
|
||||
(declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
|
||||
(declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
|
||||
(declare-function haiku-set-mouse-absolute-pixel-position "haikufns.c" (x y))
|
||||
(declare-function android-set-mouse-absolute-pixel-position
|
||||
"androidfns.c" (x y))
|
||||
|
||||
(defun set-mouse-absolute-pixel-position (x y)
|
||||
"Move mouse pointer to absolute pixel position (X, Y).
|
||||
@ -1903,7 +1914,9 @@ position (0, 0) of the selected frame's terminal."
|
||||
((eq frame-type 'w32)
|
||||
(w32-set-mouse-absolute-pixel-position x y))
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-set-mouse-absolute-pixel-position x y)))))
|
||||
(haiku-set-mouse-absolute-pixel-position x y))
|
||||
((eq frame-type 'android)
|
||||
(android-set-mouse-absolute-pixel-position x y)))))
|
||||
|
||||
(defun frame-monitor-attributes (&optional frame)
|
||||
"Return the attributes of the physical monitor dominating FRAME.
|
||||
@ -1999,6 +2012,7 @@ workarea attribute."
|
||||
;; TODO: implement this on PGTK.
|
||||
;; (declare-function pgtk-frame-list-z-order "pgtkfns.c" (&optional display))
|
||||
(declare-function haiku-frame-list-z-order "haikufns.c" (&optional display))
|
||||
(declare-function android-frame-list-z-order "androidfns.c" (&optional display))
|
||||
|
||||
(defun frame-list-z-order (&optional display)
|
||||
"Return list of Emacs' frames, in Z (stacking) order.
|
||||
@ -2024,13 +2038,17 @@ Return nil if DISPLAY contains no Emacs frame."
|
||||
;; (pgtk-frame-list-z-order display)
|
||||
nil)
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-frame-list-z-order display)))))
|
||||
(haiku-frame-list-z-order display))
|
||||
((eq frame-type 'android)
|
||||
(android-frame-list-z-order display)))))
|
||||
|
||||
(declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above))
|
||||
(declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above))
|
||||
(declare-function ns-frame-restack "nsfns.m" (frame1 frame2 &optional above))
|
||||
(declare-function pgtk-frame-restack "pgtkfns.c" (frame1 frame2 &optional above))
|
||||
(declare-function haiku-frame-restack "haikufns.c" (frame1 frame2 &optional above))
|
||||
(declare-function android-frame-restack "androidfns.c" (frame1 frame2
|
||||
&optional above))
|
||||
|
||||
(defun frame-restack (frame1 frame2 &optional above)
|
||||
"Restack FRAME1 below FRAME2.
|
||||
@ -2064,7 +2082,9 @@ Some window managers may refuse to restack windows."
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-frame-restack frame1 frame2 above))
|
||||
((eq frame-type 'pgtk)
|
||||
(pgtk-frame-restack frame1 frame2 above))))
|
||||
(pgtk-frame-restack frame1 frame2 above))
|
||||
((eq frame-type 'android)
|
||||
(android-frame-restack frame1 frame2 above))))
|
||||
(error "Cannot restack frames")))
|
||||
|
||||
(defun frame-size-changed-p (&optional frame)
|
||||
@ -2113,6 +2133,8 @@ frame's display)."
|
||||
(> w32-num-mouse-buttons 0)))
|
||||
((memq frame-type '(x ns haiku pgtk))
|
||||
t) ;; We assume X, NeXTstep, GTK, and Haiku *always* have a pointing device
|
||||
((eq frame-type 'android)
|
||||
(android-detect-mouse))
|
||||
(t
|
||||
(or (and (featurep 'xt-mouse)
|
||||
xterm-mouse-mode)
|
||||
@ -2396,6 +2418,8 @@ If DISPLAY is omitted or nil, it defaults to the selected frame's display."
|
||||
(&optional terminal))
|
||||
(declare-function haiku-display-monitor-attributes-list "haikufns.c"
|
||||
(&optional terminal))
|
||||
(declare-function android-display-monitor-attributes-list "androidfns.c"
|
||||
(&optional terminal))
|
||||
|
||||
(defun display-monitor-attributes-list (&optional display)
|
||||
"Return a list of physical monitor attributes on DISPLAY.
|
||||
@ -2449,6 +2473,8 @@ monitors."
|
||||
(pgtk-display-monitor-attributes-list display))
|
||||
((eq frame-type 'haiku)
|
||||
(haiku-display-monitor-attributes-list display))
|
||||
((eq frame-type 'android)
|
||||
(android-display-monitor-attributes-list display))
|
||||
(t
|
||||
(let ((geometry (list 0 0 (display-pixel-width display)
|
||||
(display-pixel-height display))))
|
||||
|
@ -58,7 +58,8 @@
|
||||
|
||||
(defcustom mouse-wheel-down-event
|
||||
(if (or (featurep 'w32-win) (featurep 'ns-win)
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win))
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win)
|
||||
(featurep 'android-win))
|
||||
'wheel-up
|
||||
'mouse-4)
|
||||
"Event used for scrolling down."
|
||||
@ -79,7 +80,8 @@
|
||||
|
||||
(defcustom mouse-wheel-up-event
|
||||
(if (or (featurep 'w32-win) (featurep 'ns-win)
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win))
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win)
|
||||
(featurep 'android-win))
|
||||
'wheel-down
|
||||
'mouse-5)
|
||||
"Event used for scrolling up."
|
||||
@ -254,7 +256,8 @@ Also see `mouse-wheel-tilt-scroll'."
|
||||
|
||||
(defvar mouse-wheel-left-event
|
||||
(if (or (featurep 'w32-win) (featurep 'ns-win)
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win))
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win)
|
||||
(featurep 'android-win))
|
||||
'wheel-left
|
||||
'mouse-6)
|
||||
"Event used for scrolling left.")
|
||||
@ -268,7 +271,8 @@ Also see `mouse-wheel-tilt-scroll'."
|
||||
|
||||
(defvar mouse-wheel-right-event
|
||||
(if (or (featurep 'w32-win) (featurep 'ns-win)
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win))
|
||||
(featurep 'haiku-win) (featurep 'pgtk-win)
|
||||
(featurep 'android-win))
|
||||
'wheel-right
|
||||
'mouse-7)
|
||||
"Event used for scrolling right.")
|
||||
|
551
src/android.c
551
src/android.c
@ -82,6 +82,11 @@ struct android_emacs_service
|
||||
jmethodID copy_area;
|
||||
jmethodID clear_window;
|
||||
jmethodID clear_area;
|
||||
jmethodID ring_bell;
|
||||
jmethodID query_tree;
|
||||
jmethodID get_screen_width;
|
||||
jmethodID get_screen_height;
|
||||
jmethodID detect_mouse;
|
||||
};
|
||||
|
||||
struct android_emacs_pixmap
|
||||
@ -196,9 +201,6 @@ struct android_event_queue
|
||||
/* The thread used to run select. */
|
||||
pthread_t select_thread;
|
||||
|
||||
/* Condition variable for the writing side. */
|
||||
pthread_cond_t write_var;
|
||||
|
||||
/* Condition variables for the reading side. */
|
||||
pthread_cond_t read_var;
|
||||
|
||||
@ -314,11 +316,6 @@ android_init_events (void)
|
||||
"pthread_mutex_init: %s",
|
||||
strerror (errno));
|
||||
|
||||
if (pthread_cond_init (&event_queue.write_var, NULL))
|
||||
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||
"pthread_cond_init: %s",
|
||||
strerror (errno));
|
||||
|
||||
if (pthread_cond_init (&event_queue.read_var, NULL))
|
||||
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||
"pthread_cond_init: %s",
|
||||
@ -387,8 +384,7 @@ android_next_event (union android_event *event_return)
|
||||
/* Free the container. */
|
||||
free (container);
|
||||
|
||||
/* Signal that events can now be written. */
|
||||
pthread_cond_signal (&event_queue.write_var);
|
||||
/* Unlock the queue. */
|
||||
pthread_mutex_unlock (&event_queue.mutex);
|
||||
}
|
||||
|
||||
@ -407,12 +403,6 @@ android_write_event (union android_event *event)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock (&event_queue.mutex);
|
||||
|
||||
/* The event queue is full, wait for events to be read. */
|
||||
if (event_queue.num_events >= 1024)
|
||||
pthread_cond_wait (&event_queue.write_var,
|
||||
&event_queue.mutex);
|
||||
|
||||
container->next = event_queue.events.next;
|
||||
container->last = &event_queue.events;
|
||||
container->next->last = container;
|
||||
@ -421,6 +411,10 @@ android_write_event (union android_event *event)
|
||||
event_queue.num_events++;
|
||||
pthread_cond_signal (&event_queue.read_var);
|
||||
pthread_mutex_unlock (&event_queue.mutex);
|
||||
|
||||
/* Now set pending_signals to true. This allows C-g to be handled
|
||||
immediately even without SIGIO. */
|
||||
pending_signals = true;
|
||||
}
|
||||
|
||||
int
|
||||
@ -604,31 +598,60 @@ android_file_access_p (const char *name, int amode)
|
||||
{
|
||||
AAsset *asset;
|
||||
AAssetDir *directory;
|
||||
int length;
|
||||
|
||||
if (!asset_manager)
|
||||
return false;
|
||||
|
||||
if (!(amode & W_OK) && (name = android_get_asset_name (name)))
|
||||
{
|
||||
if (!strcmp (name, "") || !strcmp (name, "/"))
|
||||
/* /assets always exists. */
|
||||
return true;
|
||||
|
||||
/* Check if the asset exists by opening it. Suboptimal! */
|
||||
asset = AAssetManager_open (asset_manager, name,
|
||||
AASSET_MODE_UNKNOWN);
|
||||
|
||||
if (!asset)
|
||||
{
|
||||
/* See if it's a directory also. */
|
||||
/* See if it's a directory as well. To open a directory
|
||||
with the asset manager, the trailing slash (if specified)
|
||||
must be removed. */
|
||||
directory = AAssetManager_openDir (asset_manager, name);
|
||||
|
||||
if (directory)
|
||||
{
|
||||
/* Make sure the directory actually has files in it. */
|
||||
|
||||
if (!AAssetDir_getNextFileName (directory))
|
||||
{
|
||||
AAssetDir_close (directory);
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
AAssetDir_close (directory);
|
||||
return true;
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
AAsset_close (asset);
|
||||
|
||||
/* If NAME is a directory name, but it was a regular file, set
|
||||
errno to ENOTDIR and return false. This is to behave like
|
||||
faccessat. */
|
||||
|
||||
length = strlen (name);
|
||||
if (name[length - 1] == '/')
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -819,12 +842,31 @@ int
|
||||
android_close (int fd)
|
||||
{
|
||||
if (fd < ANDROID_MAX_ASSET_FD
|
||||
&& (android_table[fd].flags & ANDROID_FD_TABLE_ENTRY_IS_VALID))
|
||||
&& (android_table[fd].flags
|
||||
& ANDROID_FD_TABLE_ENTRY_IS_VALID))
|
||||
android_table[fd].flags = 0;
|
||||
|
||||
return close (fd);
|
||||
}
|
||||
|
||||
/* Like fclose. However, remove any information associated with
|
||||
FILE's file descriptor from the asset table as well. */
|
||||
|
||||
int
|
||||
android_fclose (FILE *stream)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = fileno (stream);
|
||||
|
||||
if (fd != -1 && fd < ANDROID_MAX_ASSET_FD
|
||||
&& (android_table[fd].flags
|
||||
& ANDROID_FD_TABLE_ENTRY_IS_VALID))
|
||||
android_table[fd].flags = 0;
|
||||
|
||||
return fclose (stream);
|
||||
}
|
||||
|
||||
/* Return the current user's ``home'' directory, which is actually the
|
||||
app data directory on Android. */
|
||||
|
||||
@ -1010,7 +1052,12 @@ android_init_emacs_service (void)
|
||||
"(Lorg/gnu/emacs/EmacsWindow;)V");
|
||||
FIND_METHOD (clear_area, "clearArea",
|
||||
"(Lorg/gnu/emacs/EmacsWindow;IIII)V");
|
||||
|
||||
FIND_METHOD (ring_bell, "ringBell", "()V");
|
||||
FIND_METHOD (query_tree, "queryTree",
|
||||
"(Lorg/gnu/emacs/EmacsWindow;)[S");
|
||||
FIND_METHOD (get_screen_width, "getScreenWidth", "(Z)I");
|
||||
FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I");
|
||||
FIND_METHOD (detect_mouse, "detectMouse", "()Z");
|
||||
#undef FIND_METHOD
|
||||
}
|
||||
|
||||
@ -1342,6 +1389,97 @@ NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object,
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object,
|
||||
jshort window, jint x, jint y,
|
||||
jlong time, jint pointer_id)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.touch.type = ANDROID_TOUCH_DOWN;
|
||||
event.touch.window = window;
|
||||
event.touch.x = x;
|
||||
event.touch.y = y;
|
||||
event.touch.time = time;
|
||||
event.touch.pointer_id = pointer_id;
|
||||
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object,
|
||||
jshort window, jint x, jint y,
|
||||
jlong time, jint pointer_id)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.touch.type = ANDROID_TOUCH_UP;
|
||||
event.touch.window = window;
|
||||
event.touch.x = x;
|
||||
event.touch.y = y;
|
||||
event.touch.time = time;
|
||||
event.touch.pointer_id = pointer_id;
|
||||
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object,
|
||||
jshort window, jint x, jint y,
|
||||
jlong time, jint pointer_id)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.touch.type = ANDROID_TOUCH_MOVE;
|
||||
event.touch.window = window;
|
||||
event.touch.x = x;
|
||||
event.touch.y = y;
|
||||
event.touch.time = time;
|
||||
event.touch.pointer_id = pointer_id;
|
||||
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendWheel) (JNIEnv *env, jobject object,
|
||||
jshort window, jint x, jint y,
|
||||
jlong time, jint state,
|
||||
jfloat x_delta, jfloat y_delta)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.wheel.type = ANDROID_WHEEL;
|
||||
event.wheel.window = window;
|
||||
event.wheel.x = x;
|
||||
event.wheel.y = y;
|
||||
event.wheel.time = time;
|
||||
event.wheel.state = state;
|
||||
event.wheel.x_delta = x_delta;
|
||||
event.wheel.y_delta = y_delta;
|
||||
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object,
|
||||
jshort window)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.iconified.type = ANDROID_ICONIFIED;
|
||||
event.iconified.window = window;
|
||||
}
|
||||
|
||||
extern JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object,
|
||||
jshort window)
|
||||
{
|
||||
union android_event event;
|
||||
|
||||
event.iconified.type = ANDROID_DEICONIFIED;
|
||||
event.iconified.window = window;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
@ -1979,10 +2117,22 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
|
||||
}
|
||||
|
||||
void
|
||||
android_reparent_window (android_window w, android_window parent,
|
||||
android_reparent_window (android_window w, android_window parent_handle,
|
||||
int x, int y)
|
||||
{
|
||||
/* TODO */
|
||||
jobject window, parent;
|
||||
jmethodID method;
|
||||
|
||||
window = android_resolve_handle (w, ANDROID_HANDLE_WINDOW);
|
||||
parent = android_resolve_handle (parent_handle,
|
||||
ANDROID_HANDLE_WINDOW);
|
||||
|
||||
method = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"reparentTo",
|
||||
"(Lorg/gnu/emacs/EmacsWindow;II)V");
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
method,
|
||||
parent, (jint) x, (jint) y);
|
||||
}
|
||||
|
||||
/* Look up the method with SIGNATURE by NAME in CLASS. Abort if it
|
||||
@ -2904,6 +3054,163 @@ android_put_image (android_pixmap handle, struct android_image *image)
|
||||
ANDROID_DELETE_LOCAL_REF (bitmap);
|
||||
}
|
||||
|
||||
void
|
||||
android_bell (void)
|
||||
{
|
||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.ring_bell);
|
||||
}
|
||||
|
||||
void
|
||||
android_set_input_focus (android_window handle, unsigned long time)
|
||||
{
|
||||
jobject window;
|
||||
jmethodID make_input_focus;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
make_input_focus = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"makeInputFocus", "(J)V");
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
make_input_focus, (jlong) time);
|
||||
}
|
||||
|
||||
void
|
||||
android_raise_window (android_window handle)
|
||||
{
|
||||
jobject window;
|
||||
jmethodID raise;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
raise = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"raise", "()V");
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
raise);
|
||||
}
|
||||
|
||||
void
|
||||
android_lower_window (android_window handle)
|
||||
{
|
||||
jobject window;
|
||||
jmethodID lower;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
lower = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"lower", "()V");
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
lower);
|
||||
}
|
||||
|
||||
int
|
||||
android_query_tree (android_window handle, android_window *root_return,
|
||||
android_window *parent_return,
|
||||
android_window **children_return,
|
||||
unsigned int *nchildren_return)
|
||||
{
|
||||
jobject window, array;
|
||||
jsize nelements, i;
|
||||
android_window *children;
|
||||
jshort *shorts;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
|
||||
/* window can be NULL, so this is a service method. */
|
||||
array
|
||||
= (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.query_tree,
|
||||
window);
|
||||
if (!array)
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
memory_full (0);
|
||||
}
|
||||
|
||||
/* The first element of the array is the parent window. The rest
|
||||
are the children. */
|
||||
nelements = (*android_java_env)->GetArrayLength (android_java_env,
|
||||
array);
|
||||
eassert (nelements);
|
||||
|
||||
/* Now fill in the children. */
|
||||
children = xnmalloc (nelements - 1, sizeof *children);
|
||||
|
||||
shorts
|
||||
= (*android_java_env)->GetShortArrayElements (android_java_env, array,
|
||||
NULL);
|
||||
for (i = 1; i < nelements; ++i)
|
||||
children[i] = shorts[i];
|
||||
|
||||
/* Finally, return the parent and other values. */
|
||||
*root_return = 0;
|
||||
*parent_return = shorts[0];
|
||||
*children_return = children;
|
||||
|
||||
/* Release the array contents. */
|
||||
(*android_java_env)->ReleaseShortArrayElements (android_java_env, array,
|
||||
shorts, JNI_ABORT);
|
||||
|
||||
ANDROID_DELETE_LOCAL_REF (array);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
android_get_geometry (android_window handle,
|
||||
android_window *root_return,
|
||||
int *x_return, int *y_return,
|
||||
unsigned int *width_return,
|
||||
unsigned int *height_return,
|
||||
unsigned int *border_width_return)
|
||||
{
|
||||
jobject window;
|
||||
jarray window_geometry;
|
||||
jmethodID get_geometry;
|
||||
jint *ints;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
get_geometry = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"getWindowGeometry", "()[I");
|
||||
|
||||
window_geometry
|
||||
= (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
window,
|
||||
get_geometry);
|
||||
if (!window_geometry)
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
memory_full (0);
|
||||
}
|
||||
|
||||
/* window_geometry is an array containing x, y, width and
|
||||
height. border_width is always 0 on Android. */
|
||||
eassert ((*android_java_env)->GetArrayLength (android_java_env,
|
||||
window_geometry)
|
||||
== 4);
|
||||
|
||||
*root_return = 0;
|
||||
*border_width_return = 0;
|
||||
|
||||
ints
|
||||
= (*android_java_env)->GetIntArrayElements (android_java_env,
|
||||
window_geometry,
|
||||
NULL);
|
||||
|
||||
*x_return = ints[0];
|
||||
*y_return = ints[1];
|
||||
*width_return = ints[2];
|
||||
*height_return = ints[3];
|
||||
|
||||
(*android_java_env)->ReleaseIntArrayElements (android_java_env,
|
||||
window_geometry,
|
||||
ints, JNI_ABORT);
|
||||
|
||||
/* Now free the local reference. */
|
||||
ANDROID_DELETE_LOCAL_REF (window_geometry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Low level drawing primitives. */
|
||||
@ -2998,6 +3305,86 @@ android_damage_window (android_drawable handle,
|
||||
|
||||
|
||||
|
||||
/* Other misc system routines. */
|
||||
|
||||
int
|
||||
android_get_screen_width (void)
|
||||
{
|
||||
return (*android_java_env)->CallIntMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.get_screen_width,
|
||||
(jboolean) false);
|
||||
}
|
||||
|
||||
int
|
||||
android_get_screen_height (void)
|
||||
{
|
||||
return (*android_java_env)->CallIntMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.get_screen_height,
|
||||
(jboolean) false);
|
||||
}
|
||||
|
||||
int
|
||||
android_get_mm_width (void)
|
||||
{
|
||||
return (*android_java_env)->CallIntMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.get_screen_width,
|
||||
(jboolean) true);
|
||||
}
|
||||
|
||||
int
|
||||
android_get_mm_height (void)
|
||||
{
|
||||
return (*android_java_env)->CallIntMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.get_screen_height,
|
||||
(jboolean) true);
|
||||
}
|
||||
|
||||
bool
|
||||
android_detect_mouse (void)
|
||||
{
|
||||
return (*android_java_env)->CallBooleanMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.detect_mouse);
|
||||
}
|
||||
|
||||
void
|
||||
android_set_dont_focus_on_map (android_window handle,
|
||||
bool no_focus_on_map)
|
||||
{
|
||||
jmethodID method;
|
||||
jobject window;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
method = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"setDontFocusOnMap", "(Z)V");
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
method,
|
||||
(jboolean) no_focus_on_map);
|
||||
}
|
||||
|
||||
void
|
||||
android_set_dont_accept_focus (android_window handle,
|
||||
bool no_accept_focus)
|
||||
{
|
||||
jmethodID method;
|
||||
jobject window;
|
||||
|
||||
window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
|
||||
method = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"setDontAcceptFocus", "(Z)V");
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env, window,
|
||||
method,
|
||||
(jboolean) no_accept_focus);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef faccessat
|
||||
|
||||
/* Replace the system faccessat with one which understands AT_EACCESS.
|
||||
@ -3015,6 +3402,128 @@ faccessat (int dirfd, const char *pathname, int mode, int flags)
|
||||
return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Directory listing emulation. */
|
||||
|
||||
struct android_dir
|
||||
{
|
||||
/* The real DIR *, if it exists. */
|
||||
DIR *dir;
|
||||
|
||||
/* Otherwise, the AAssetDir. */
|
||||
void *asset_dir;
|
||||
};
|
||||
|
||||
/* Like opendir. However, return an asset directory if NAME points to
|
||||
an asset. */
|
||||
|
||||
struct android_dir *
|
||||
android_opendir (const char *name)
|
||||
{
|
||||
struct android_dir *dir;
|
||||
AAssetDir *asset_dir;
|
||||
const char *asset_name;
|
||||
|
||||
asset_name = android_get_asset_name (name);
|
||||
|
||||
/* If the asset manager exists and NAME is an asset, return an asset
|
||||
directory. */
|
||||
if (asset_manager && asset_name)
|
||||
{
|
||||
asset_dir = AAssetManager_openDir (asset_manager,
|
||||
asset_name);
|
||||
|
||||
if (!asset_dir)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir = xmalloc (sizeof *dir);
|
||||
dir->dir = NULL;
|
||||
dir->asset_dir = asset_dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Otherwise, open the directory normally. */
|
||||
dir = xmalloc (sizeof *dir);
|
||||
dir->asset_dir = NULL;
|
||||
dir->dir = opendir (name);
|
||||
|
||||
if (!dir->dir)
|
||||
{
|
||||
xfree (dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Like readdir, except it understands asset directories. */
|
||||
|
||||
struct dirent *
|
||||
android_readdir (struct android_dir *dir)
|
||||
{
|
||||
static struct dirent dirent;
|
||||
const char *filename;
|
||||
|
||||
if (dir->asset_dir)
|
||||
{
|
||||
filename = AAssetDir_getNextFileName (dir->asset_dir);
|
||||
errno = 0;
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
memset (&dirent, 0, sizeof dirent);
|
||||
dirent.d_ino = 0;
|
||||
dirent.d_off = 0;
|
||||
dirent.d_reclen = sizeof dirent;
|
||||
dirent.d_type = DT_UNKNOWN;
|
||||
strncpy (dirent.d_name, filename,
|
||||
sizeof dirent.d_name - 1);
|
||||
return &dirent;
|
||||
}
|
||||
|
||||
return readdir (dir->dir);
|
||||
}
|
||||
|
||||
/* Like closedir, but it also closes asset manager directories. */
|
||||
|
||||
void
|
||||
android_closedir (struct android_dir *dir)
|
||||
{
|
||||
if (dir->dir)
|
||||
closedir (dir->dir);
|
||||
else
|
||||
AAssetDir_close (dir->asset_dir);
|
||||
|
||||
xfree (dir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* emacs_abort implementation for Android. This logs a stack
|
||||
trace. */
|
||||
|
||||
void
|
||||
emacs_abort (void)
|
||||
{
|
||||
volatile char *foo;
|
||||
|
||||
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||
"emacs_abort called, please review the ensuing"
|
||||
" stack trace");
|
||||
|
||||
/* Cause a NULL pointer dereference to make debuggerd generate a
|
||||
tombstone. */
|
||||
foo = NULL;
|
||||
*foo = '\0';
|
||||
|
||||
abort ();
|
||||
}
|
||||
|
||||
#else /* ANDROID_STUBIFY */
|
||||
|
||||
/* X emulation functions for Android. */
|
||||
|
@ -27,7 +27,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#ifndef ANDROID_STUBIFY
|
||||
#include <jni.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <android/bitmap.h>
|
||||
|
||||
@ -53,6 +55,7 @@ extern int android_fstat (int, struct stat *);
|
||||
extern int android_fstatat (int, const char *restrict,
|
||||
struct stat *restrict, int);
|
||||
extern int android_close (int);
|
||||
extern int android_fclose (FILE *);
|
||||
extern const char *android_get_home_directory (void);
|
||||
|
||||
extern double android_pixel_density_x, android_pixel_density_y;
|
||||
@ -71,6 +74,26 @@ extern unsigned char *android_lock_bitmap (android_window,
|
||||
jobject *);
|
||||
extern void android_damage_window (android_window,
|
||||
struct android_rectangle *);
|
||||
extern int android_get_screen_width (void);
|
||||
extern int android_get_screen_height (void);
|
||||
extern int android_get_mm_width (void);
|
||||
extern int android_get_mm_height (void);
|
||||
extern bool android_detect_mouse (void);
|
||||
|
||||
extern void android_set_dont_focus_on_map (android_window, bool);
|
||||
extern void android_set_dont_accept_focus (android_window, bool);
|
||||
|
||||
|
||||
|
||||
/* Directory listing emulation. */
|
||||
|
||||
struct android_dir;
|
||||
|
||||
extern struct android_dir *android_opendir (const char *);
|
||||
extern struct dirent *android_readdir (struct android_dir *);
|
||||
extern void android_closedir (struct android_dir *);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
485
src/androidfns.c
485
src/androidfns.c
@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <math.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "android.h"
|
||||
#include "androidterm.h"
|
||||
#include "blockinput.h"
|
||||
#include "keyboard.h"
|
||||
@ -151,6 +152,36 @@ android_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
|
||||
signal_error ("Undefined color", color_name);
|
||||
}
|
||||
|
||||
static void
|
||||
android_set_parent_frame (struct frame *f, Lisp_Object new_value,
|
||||
Lisp_Object old_value)
|
||||
{
|
||||
struct frame *p;
|
||||
|
||||
p = NULL;
|
||||
|
||||
if (!NILP (new_value)
|
||||
&& (!FRAMEP (new_value)
|
||||
|| !FRAME_LIVE_P (p = XFRAME (new_value))
|
||||
|| !FRAME_ANDROID_P (p)))
|
||||
{
|
||||
store_frame_param (f, Qparent_frame, old_value);
|
||||
error ("Invalid specification of `parent-frame'");
|
||||
}
|
||||
|
||||
if (p != FRAME_PARENT_FRAME (f))
|
||||
{
|
||||
block_input ();
|
||||
android_reparent_window (FRAME_ANDROID_WINDOW (f),
|
||||
(p ? FRAME_ANDROID_WINDOW (p)
|
||||
: FRAME_DISPLAY_INFO (f)->root_window),
|
||||
f->left_pos, f->top_pos);
|
||||
unblock_input ();
|
||||
|
||||
fset_parent_frame (f, new_value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
android_implicitly_set_name (struct frame *f, Lisp_Object arg,
|
||||
Lisp_Object oldval)
|
||||
@ -531,9 +562,9 @@ android_default_font_parameter (struct frame *f, Lisp_Object parms)
|
||||
if (! FONTP (font) && ! STRINGP (font))
|
||||
{
|
||||
const char *names[] = {
|
||||
"Droid Sans Mono",
|
||||
"monospace",
|
||||
"DroidSansMono",
|
||||
"Droid Sans Mono-12",
|
||||
"Monospace-12",
|
||||
"DroidSansMono-12",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
@ -1119,8 +1150,7 @@ DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
return make_fixnum (android_get_screen_width ());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1133,8 +1163,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
return make_fixnum (android_get_screen_height ());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1185,8 +1214,7 @@ DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width,
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
return make_fixnum (android_get_mm_width ());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1198,8 +1226,7 @@ DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height,
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
return make_fixnum (android_get_mm_height ());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1225,77 +1252,373 @@ DEFUN ("x-display-visual-class", Fx_display_visual_class,
|
||||
return Qtrue_color;
|
||||
}
|
||||
|
||||
DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
|
||||
Sx_display_monitor_attributes_list,
|
||||
DEFUN ("android-display-monitor-attributes-list",
|
||||
Fandroid_display_monitor_attributes_list,
|
||||
Sandroid_display_monitor_attributes_list,
|
||||
0, 1, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
|
||||
|
||||
The optional argument TERMINAL specifies which display to ask about.
|
||||
TERMINAL should be a terminal object, a frame or a display name (a string).
|
||||
If omitted or nil, that stands for the selected frame's display.
|
||||
|
||||
Internal use only, use `display-monitor-attributes-list' instead. */)
|
||||
(Lisp_Object terminal)
|
||||
{
|
||||
#ifdef ANDROID_STUBIFY
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
struct MonitorInfo monitor;
|
||||
|
||||
memset (&monitor, 0, sizeof monitor);
|
||||
monitor.geom.width = android_get_screen_width ();
|
||||
monitor.geom.height = android_get_screen_height ();
|
||||
monitor.mm_width = android_get_mm_width ();
|
||||
monitor.mm_height = android_get_mm_height ();
|
||||
monitor.work = monitor.geom;
|
||||
monitor.name = (char *) "Android device monitor";
|
||||
|
||||
/* What to do about monitor_frames? */
|
||||
return make_monitor_attribute_list (&monitor, 1,
|
||||
0, Qnil, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
static Lisp_Object
|
||||
frame_geometry (Lisp_Object frame, Lisp_Object attribute)
|
||||
{
|
||||
struct frame *f = decode_live_frame (frame);
|
||||
android_window rootw;
|
||||
unsigned int native_width, native_height, x_border_width = 0;
|
||||
int x_native = 0, y_native = 0, xptr = 0, yptr = 0;
|
||||
int left_off = 0, right_off = 0, top_off = 0, bottom_off = 0;
|
||||
int outer_left, outer_top, outer_right, outer_bottom;
|
||||
int native_left, native_top, native_right, native_bottom;
|
||||
int inner_left, inner_top, inner_right, inner_bottom;
|
||||
int internal_border_width;
|
||||
bool menu_bar_external = false, tool_bar_external = false;
|
||||
int menu_bar_height = 0, menu_bar_width = 0;
|
||||
int tab_bar_height = 0, tab_bar_width = 0;
|
||||
int tool_bar_height = 0, tool_bar_width = 0;
|
||||
|
||||
if (FRAME_INITIAL_P (f) || !FRAME_ANDROID_P (f)
|
||||
|| !FRAME_ANDROID_WINDOW (f))
|
||||
return Qnil;
|
||||
|
||||
block_input ();
|
||||
android_get_geometry (FRAME_ANDROID_WINDOW (f),
|
||||
&rootw, &x_native, &y_native,
|
||||
&native_width, &native_height, &x_border_width);
|
||||
unblock_input ();
|
||||
|
||||
if (FRAME_PARENT_FRAME (f))
|
||||
{
|
||||
Lisp_Object parent, edges;
|
||||
|
||||
XSETFRAME (parent, FRAME_PARENT_FRAME (f));
|
||||
edges = Fandroid_frame_edges (parent, Qnative_edges);
|
||||
if (!NILP (edges))
|
||||
{
|
||||
x_native += XFIXNUM (Fnth (make_fixnum (0), edges));
|
||||
y_native += XFIXNUM (Fnth (make_fixnum (1), edges));
|
||||
}
|
||||
|
||||
outer_left = x_native;
|
||||
outer_top = y_native;
|
||||
outer_right = outer_left + native_width + 2 * x_border_width;
|
||||
outer_bottom = outer_top + native_height + 2 * x_border_width;
|
||||
|
||||
native_left = x_native + x_border_width;
|
||||
native_top = y_native + x_border_width;
|
||||
native_right = native_left + native_width;
|
||||
native_bottom = native_top + native_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
outer_left = xptr;
|
||||
outer_top = yptr;
|
||||
outer_right = outer_left + left_off + native_width + right_off;
|
||||
outer_bottom = outer_top + top_off + native_height + bottom_off;
|
||||
|
||||
native_left = outer_left + left_off;
|
||||
native_top = outer_top + top_off;
|
||||
native_right = native_left + native_width;
|
||||
native_bottom = native_top + native_height;
|
||||
}
|
||||
|
||||
internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
|
||||
inner_left = native_left + internal_border_width;
|
||||
inner_top = native_top + internal_border_width;
|
||||
inner_right = native_right - internal_border_width;
|
||||
inner_bottom = native_bottom - internal_border_width;
|
||||
|
||||
menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
|
||||
inner_top += menu_bar_height;
|
||||
menu_bar_width = menu_bar_height ? native_width : 0;
|
||||
|
||||
tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
|
||||
tab_bar_width = (tab_bar_height
|
||||
? native_width - 2 * internal_border_width
|
||||
: 0);
|
||||
inner_top += tab_bar_height;
|
||||
|
||||
tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
|
||||
tool_bar_width = (tool_bar_height
|
||||
? native_width - 2 * internal_border_width
|
||||
: 0);
|
||||
inner_top += tool_bar_height;
|
||||
|
||||
/* Construct list. */
|
||||
if (EQ (attribute, Qouter_edges))
|
||||
return list4i (outer_left, outer_top, outer_right, outer_bottom);
|
||||
else if (EQ (attribute, Qnative_edges))
|
||||
return list4i (native_left, native_top, native_right, native_bottom);
|
||||
else if (EQ (attribute, Qinner_edges))
|
||||
return list4i (inner_left, inner_top, inner_right, inner_bottom);
|
||||
else
|
||||
return
|
||||
list (Fcons (Qouter_position,
|
||||
Fcons (make_fixnum (outer_left),
|
||||
make_fixnum (outer_top))),
|
||||
Fcons (Qouter_size,
|
||||
Fcons (make_fixnum (outer_right - outer_left),
|
||||
make_fixnum (outer_bottom - outer_top))),
|
||||
/* Approximate. */
|
||||
Fcons (Qexternal_border_size,
|
||||
Fcons (make_fixnum (right_off),
|
||||
make_fixnum (bottom_off))),
|
||||
Fcons (Qouter_border_width, make_fixnum (x_border_width)),
|
||||
/* Approximate. */
|
||||
Fcons (Qtitle_bar_size,
|
||||
Fcons (make_fixnum (0),
|
||||
make_fixnum (top_off - bottom_off))),
|
||||
Fcons (Qmenu_bar_external, menu_bar_external ? Qt : Qnil),
|
||||
Fcons (Qmenu_bar_size,
|
||||
Fcons (make_fixnum (menu_bar_width),
|
||||
make_fixnum (menu_bar_height))),
|
||||
Fcons (Qtab_bar_size,
|
||||
Fcons (make_fixnum (tab_bar_width),
|
||||
make_fixnum (tab_bar_height))),
|
||||
Fcons (Qtool_bar_external, tool_bar_external ? Qt : Qnil),
|
||||
Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
|
||||
Fcons (Qtool_bar_size,
|
||||
Fcons (make_fixnum (tool_bar_width),
|
||||
make_fixnum (tool_bar_height))),
|
||||
Fcons (Qinternal_border_width,
|
||||
make_fixnum (internal_border_width)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DEFUN ("android-frame-geometry", Fandroid_frame_geometry,
|
||||
Sandroid_frame_geometry,
|
||||
0, 1, 0,
|
||||
doc: /* Return geometric attributes of FRAME.
|
||||
FRAME must be a live frame and defaults to the selected one. The return
|
||||
value is an association list of the attributes listed below. All height
|
||||
and width values are in pixels.
|
||||
|
||||
`outer-position' is a cons of the outer left and top edges of FRAME
|
||||
relative to the origin - the position (0, 0) - of FRAME's display.
|
||||
|
||||
`outer-size' is a cons of the outer width and height of FRAME. The
|
||||
outer size includes the title bar and the external borders as well as
|
||||
any menu and/or tool bar of frame.
|
||||
|
||||
`external-border-size' is a cons of the horizontal and vertical width of
|
||||
FRAME's external borders as supplied by the window manager.
|
||||
|
||||
`title-bar-size' is a cons of the width and height of the title bar of
|
||||
FRAME as supplied by the window manager. If both of them are zero,
|
||||
FRAME has no title bar. If only the width is zero, Emacs was not
|
||||
able to retrieve the width information.
|
||||
|
||||
`menu-bar-external', if non-nil, means the menu bar is external (never
|
||||
included in the inner edges of FRAME).
|
||||
|
||||
`menu-bar-size' is a cons of the width and height of the menu bar of
|
||||
FRAME.
|
||||
|
||||
`tool-bar-external', if non-nil, means the tool bar is external (never
|
||||
included in the inner edges of FRAME).
|
||||
|
||||
`tool-bar-position' tells on which side the tool bar on FRAME is and can
|
||||
be one of `left', `top', `right' or `bottom'. If this is nil, FRAME
|
||||
has no tool bar.
|
||||
|
||||
`tool-bar-size' is a cons of the width and height of the tool bar of
|
||||
FRAME.
|
||||
|
||||
`internal-border-width' is the width of the internal border of
|
||||
FRAME. */)
|
||||
(Lisp_Object frame)
|
||||
{
|
||||
#ifdef ANDROID_STUBIFY
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
return frame_geometry (frame, Qnil);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN ("android-frame-edges", Fandroid_frame_edges, Sandroid_frame_edges, 0, 2, 0,
|
||||
doc: /* Return edge coordinates of FRAME.
|
||||
FRAME must be a live frame and defaults to the selected one. The return
|
||||
value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are
|
||||
in pixels relative to the origin - the position (0, 0) - of FRAME's
|
||||
display.
|
||||
|
||||
If optional argument TYPE is the symbol `outer-edges', return the outer
|
||||
edges of FRAME. The outer edges comprise the decorations of the window
|
||||
manager (like the title bar or external borders) as well as any external
|
||||
menu or tool bar of FRAME. If optional argument TYPE is the symbol
|
||||
`native-edges' or nil, return the native edges of FRAME. The native
|
||||
edges exclude the decorations of the window manager and any external
|
||||
menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return
|
||||
the inner edges of FRAME. These edges exclude title bar, any borders,
|
||||
menu bar or tool bar of FRAME. */)
|
||||
(Lisp_Object frame, Lisp_Object type)
|
||||
{
|
||||
#ifndef ANDROID_STUBIFY
|
||||
return frame_geometry (frame, ((EQ (type, Qouter_edges)
|
||||
|| EQ (type, Qinner_edges))
|
||||
? type
|
||||
: Qnative_edges));
|
||||
#else
|
||||
return Qnil;
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN ("x-frame-geometry", Fx_frame_geometry, Sx_frame_geometry,
|
||||
0, 1, 0, doc: /* SKIP: real doc in xfns.c. */)
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
static Lisp_Object
|
||||
android_frame_list_z_order (struct android_display_info *dpyinfo,
|
||||
android_window window)
|
||||
{
|
||||
android_window root, parent, *children;
|
||||
unsigned int nchildren;
|
||||
unsigned long i;
|
||||
Lisp_Object frames;
|
||||
|
||||
frames = Qnil;
|
||||
|
||||
if (android_query_tree (window, &root, &parent,
|
||||
&children, &nchildren))
|
||||
{
|
||||
for (i = 0; i < nchildren; i++)
|
||||
{
|
||||
Lisp_Object frame, tail;
|
||||
|
||||
FOR_EACH_FRAME (tail, frame)
|
||||
{
|
||||
struct frame *cf = XFRAME (frame);
|
||||
|
||||
if (FRAME_ANDROID_P (cf)
|
||||
&& (FRAME_ANDROID_WINDOW (cf) == children[i]))
|
||||
frames = Fcons (frame, frames);
|
||||
}
|
||||
}
|
||||
|
||||
if (children)
|
||||
xfree (children);
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DEFUN ("android-frame-list-z-order", Fandroid_frame_list_z_order,
|
||||
Sandroid_frame_list_z_order, 0, 1, 0,
|
||||
doc: /* Return list of Emacs' frames, in Z (stacking) order.
|
||||
The optional argument TERMINAL specifies which display to ask about.
|
||||
TERMINAL should be either a frame or a display name (a string). If
|
||||
omitted or nil, that stands for the selected frame's display. Return
|
||||
nil if TERMINAL contains no Emacs frame.
|
||||
|
||||
As a special case, if TERMINAL is non-nil and specifies a live frame,
|
||||
return the child frames of that frame in Z (stacking) order.
|
||||
|
||||
Frames are listed from topmost (first) to bottommost (last).
|
||||
|
||||
On Android, the order of the frames returned is undefined unless
|
||||
TERMINAL is a frame. */)
|
||||
(Lisp_Object terminal)
|
||||
{
|
||||
#ifdef ANDROID_STUBIFY
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
struct android_display_info *dpyinfo;
|
||||
android_window window;
|
||||
|
||||
dpyinfo = check_android_display_info (terminal);
|
||||
|
||||
if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
|
||||
window = FRAME_ANDROID_WINDOW (XFRAME (terminal));
|
||||
else
|
||||
window = dpyinfo->root_window;
|
||||
|
||||
return android_frame_list_z_order (dpyinfo, window);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN ("x-frame-list-z-order", Fx_frame_list_z_order,
|
||||
Sx_frame_list_z_order, 0, 1, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
(Lisp_Object terminal)
|
||||
{
|
||||
#ifdef ANDROID_STUBIFY
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
return Qnil;
|
||||
#endif
|
||||
}
|
||||
DEFUN ("android-frame-restack", Fandroid_frame_restack,
|
||||
Sandroid_frame_restack, 2, 3, 0,
|
||||
doc: /* Restack FRAME1 below FRAME2.
|
||||
This means that if both frames are visible and the display areas of
|
||||
these frames overlap, FRAME2 (partially) obscures FRAME1. If optional
|
||||
third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This
|
||||
means that if both frames are visible and the display areas of these
|
||||
frames overlap, FRAME1 (partially) obscures FRAME2.
|
||||
|
||||
DEFUN ("x-frame-restack", Fx_frame_restack, Sx_frame_restack, 2, 3, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
This may be thought of as an atomic action performed in two steps: The
|
||||
first step removes FRAME1's window-step window from the display. The
|
||||
second step reinserts FRAME1's window below (above if ABOVE is true)
|
||||
that of FRAME2. Hence the position of FRAME2 in its display's Z
|
||||
\(stacking) order relative to all other frames excluding FRAME1 remains
|
||||
unaltered.
|
||||
|
||||
The Android system refuses to restack windows, so this does not
|
||||
work. */)
|
||||
(Lisp_Object frame1, Lisp_Object frame2, Lisp_Object frame3)
|
||||
{
|
||||
#ifdef ANDROID_STUBIFY
|
||||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
error ("Not implemented");
|
||||
/* This is not supported on Android because of limitations in the
|
||||
platform that prevent ViewGroups from restacking
|
||||
SurfaceViews. */
|
||||
return Qnil;
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN ("x-mouse-absolute-pixel-position", Fx_mouse_absolute_pixel_position,
|
||||
Sx_mouse_absolute_pixel_position, 0, 0, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
DEFUN ("android-mouse-absolute-pixel-position",
|
||||
Fandroid_mouse_absolute_pixel_position,
|
||||
Sandroid_mouse_absolute_pixel_position, 0, 0, 0,
|
||||
doc: /* Return absolute position of mouse cursor in pixels.
|
||||
The position is returned as a cons cell (X . Y) of the coordinates of
|
||||
the mouse cursor position in pixels relative to a position (0, 0) of the
|
||||
selected frame's display. This does not work on Android. */)
|
||||
(void)
|
||||
{
|
||||
/* TODO: figure out how to implement this. */
|
||||
/* This cannot be implemented on Android. */
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("x-set-mouse-absolute-pixel-position",
|
||||
Fx_set_mouse_absolute_pixel_position,
|
||||
Sx_set_mouse_absolute_pixel_position, 2, 2, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
DEFUN ("android-set-mouse-absolute-pixel-position",
|
||||
Fandroid_set_mouse_absolute_pixel_position,
|
||||
Sandroid_set_mouse_absolute_pixel_position, 2, 2, 0,
|
||||
doc: /* Move mouse pointer to a pixel position at (X, Y). The
|
||||
coordinates X and Y are interpreted to start from the top-left corner
|
||||
of the screen. This does not work on Android. */)
|
||||
(Lisp_Object x, Lisp_Object y)
|
||||
{
|
||||
/* TODO: figure out how to implement this. */
|
||||
/* This cannot be implemented on Android. */
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
@ -1364,6 +1687,20 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN ("android-detect-mouse", Fandroid_detect_mouse,
|
||||
Sandroid_detect_mouse, 0, 0, 0,
|
||||
doc: /* Figure out whether or not there is a mouse.
|
||||
Return non-nil if a mouse is connected to this computer, and nil if
|
||||
there is no mouse. */)
|
||||
(void)
|
||||
{
|
||||
#ifndef ANDROID_STUBIFY
|
||||
return android_detect_mouse () ? Qt : Qnil;
|
||||
#else
|
||||
return Qnil;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
@ -1579,7 +1916,7 @@ android_set_menu_bar_lines (struct frame *f, Lisp_Object value,
|
||||
y = FRAME_TOP_MARGIN_HEIGHT (f);
|
||||
|
||||
block_input ();
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f),
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f),
|
||||
0, y, width, height);
|
||||
unblock_input ();
|
||||
}
|
||||
@ -1590,7 +1927,7 @@ android_set_menu_bar_lines (struct frame *f, Lisp_Object value,
|
||||
height = nlines * FRAME_LINE_HEIGHT (f) - y;
|
||||
|
||||
block_input ();
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f), 0, y,
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f), 0, y,
|
||||
width, height);
|
||||
unblock_input ();
|
||||
}
|
||||
@ -1682,6 +2019,30 @@ android_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
android_set_no_focus_on_map (struct frame *f, Lisp_Object new_value,
|
||||
Lisp_Object old_value)
|
||||
{
|
||||
if (!EQ (new_value, old_value))
|
||||
{
|
||||
android_set_dont_focus_on_map (FRAME_ANDROID_WINDOW (f),
|
||||
new_value);
|
||||
FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
android_set_no_accept_focus (struct frame *f, Lisp_Object new_value,
|
||||
Lisp_Object old_value)
|
||||
{
|
||||
if (!EQ (new_value, old_value))
|
||||
{
|
||||
android_set_dont_accept_focus (FRAME_ANDROID_WINDOW (f),
|
||||
new_value);
|
||||
FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
|
||||
}
|
||||
}
|
||||
|
||||
frame_parm_handler android_frame_parm_handlers[] =
|
||||
{
|
||||
gui_set_autoraise,
|
||||
@ -1724,16 +2085,16 @@ frame_parm_handler android_frame_parm_handlers[] =
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, /* x_set_undecorated, */
|
||||
NULL, /* x_set_parent_frame, */
|
||||
NULL, /* x_set_skip_taskbar, */
|
||||
NULL, /* x_set_no_focus_on_map, */
|
||||
NULL, /* x_set_no_accept_focus, */
|
||||
NULL, /* x_set_z_group, */
|
||||
NULL, /* x_set_override_redirect, */
|
||||
NULL,
|
||||
android_set_parent_frame,
|
||||
NULL,
|
||||
android_set_no_focus_on_map,
|
||||
android_set_no_accept_focus,
|
||||
NULL,
|
||||
NULL,
|
||||
gui_set_no_special_glyphs,
|
||||
NULL, /* x_set_alpha_background, */
|
||||
NULL, /* x_set_use_frame_synchronization, */
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1766,14 +2127,16 @@ syms_of_androidfns (void)
|
||||
defsubr (&Sx_display_mm_height);
|
||||
defsubr (&Sx_display_backing_store);
|
||||
defsubr (&Sx_display_visual_class);
|
||||
defsubr (&Sx_display_monitor_attributes_list);
|
||||
defsubr (&Sx_frame_geometry);
|
||||
defsubr (&Sx_frame_list_z_order);
|
||||
defsubr (&Sx_frame_restack);
|
||||
defsubr (&Sx_mouse_absolute_pixel_position);
|
||||
defsubr (&Sx_set_mouse_absolute_pixel_position);
|
||||
defsubr (&Sandroid_display_monitor_attributes_list);
|
||||
defsubr (&Sandroid_frame_geometry);
|
||||
defsubr (&Sandroid_frame_edges);
|
||||
defsubr (&Sandroid_frame_list_z_order);
|
||||
defsubr (&Sandroid_frame_restack);
|
||||
defsubr (&Sandroid_mouse_absolute_pixel_position);
|
||||
defsubr (&Sandroid_set_mouse_absolute_pixel_position);
|
||||
defsubr (&Sandroid_get_connection);
|
||||
defsubr (&Sx_display_list);
|
||||
defsubr (&Sx_show_tip);
|
||||
defsubr (&Sx_hide_tip);
|
||||
defsubr (&Sandroid_detect_mouse);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Communication module for Android terminals.
|
||||
/* Android fallback font driver.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
@ -17,6 +17,10 @@ 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/>. */
|
||||
|
||||
/* Due to the terrible nature of the Android Typeface subsystems, this
|
||||
font driver is only used as a fallback when sfntfont-android.c
|
||||
fails to enumerate any fonts at all. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "lisp.h"
|
||||
@ -636,7 +640,7 @@ androidfont_draw (struct glyph_string *s, int from, int to,
|
||||
|
||||
gcontext = android_resolve_handle (s->gc->gcontext,
|
||||
ANDROID_HANDLE_GCONTEXT);
|
||||
drawable = android_resolve_handle (FRAME_ANDROID_WINDOW (s->f),
|
||||
drawable = android_resolve_handle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
ANDROID_HANDLE_WINDOW);
|
||||
chars = (*android_java_env)->NewIntArray (android_java_env,
|
||||
to - from);
|
||||
|
@ -222,6 +222,12 @@ enum android_event_type
|
||||
ANDROID_MOTION_NOTIFY,
|
||||
ANDROID_BUTTON_PRESS,
|
||||
ANDROID_BUTTON_RELEASE,
|
||||
ANDROID_TOUCH_DOWN,
|
||||
ANDROID_TOUCH_UP,
|
||||
ANDROID_TOUCH_MOVE,
|
||||
ANDROID_WHEEL,
|
||||
ANDROID_ICONIFIED,
|
||||
ANDROID_DEICONIFIED,
|
||||
};
|
||||
|
||||
struct android_any_event
|
||||
@ -312,6 +318,54 @@ struct android_button_event
|
||||
unsigned int button;
|
||||
};
|
||||
|
||||
struct android_touch_event
|
||||
{
|
||||
/* Type of the event. */
|
||||
enum android_event_type type;
|
||||
|
||||
/* Window associated with the event. */
|
||||
android_window window;
|
||||
|
||||
/* X and Y coordinates of the event. */
|
||||
int x, y;
|
||||
|
||||
/* Time of the event, and the pointer identifier. */
|
||||
unsigned long time;
|
||||
|
||||
/* Index of the pointer being tracked. */
|
||||
unsigned int pointer_id;
|
||||
};
|
||||
|
||||
struct android_wheel_event
|
||||
{
|
||||
/* Type of the event. */
|
||||
enum android_event_type type;
|
||||
|
||||
/* Window associated with the event. */
|
||||
android_window window;
|
||||
|
||||
/* X and Y coordinates of the event. */
|
||||
int x, y;
|
||||
|
||||
/* Time of the event, and the pointer identifier. */
|
||||
unsigned long time;
|
||||
|
||||
/* Modifier state at the time of the event. */
|
||||
int state;
|
||||
|
||||
/* Motion alongside the X and Y axes. */
|
||||
double x_delta, y_delta;
|
||||
};
|
||||
|
||||
struct android_iconify_event
|
||||
{
|
||||
/* Type of the event. */
|
||||
enum android_event_type type;
|
||||
|
||||
/* Window associated with the event. */
|
||||
android_window window;
|
||||
};
|
||||
|
||||
union android_event
|
||||
{
|
||||
enum android_event_type type;
|
||||
@ -323,8 +377,26 @@ union android_event
|
||||
struct android_crossing_event xcrossing;
|
||||
struct android_motion_event xmotion;
|
||||
struct android_button_event xbutton;
|
||||
|
||||
/* This has no parallel in X, since the X model of having
|
||||
monotonically increasing touch IDs can't work on Android. */
|
||||
struct android_touch_event touch;
|
||||
|
||||
/* This has no parallel in X outside the X Input Extension, and
|
||||
emulating the input extension interface would be awfully
|
||||
complicated. */
|
||||
struct android_wheel_event wheel;
|
||||
|
||||
/* This has no parallel in X because Android doesn't have window
|
||||
properties. */
|
||||
struct android_iconify_event iconified;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ANDROID_CURRENT_TIME = 0L,
|
||||
};
|
||||
|
||||
extern int android_pending (void);
|
||||
extern void android_next_event (union android_event *);
|
||||
|
||||
@ -396,6 +468,17 @@ extern void android_clear_area (android_window, int, int, unsigned int,
|
||||
extern android_pixmap android_create_bitmap_from_data (char *, unsigned int,
|
||||
unsigned int);
|
||||
|
||||
extern void android_bell (void);
|
||||
extern void android_set_input_focus (android_window, unsigned long);
|
||||
extern void android_raise_window (android_window);
|
||||
extern void android_lower_window (android_window);
|
||||
extern int android_query_tree (android_window, android_window *,
|
||||
android_window *, android_window **,
|
||||
unsigned int *);
|
||||
extern void android_get_geometry (android_window, android_window *,
|
||||
int *, int *, unsigned int *,
|
||||
unsigned int *, unsigned int *);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "androidterm.h"
|
||||
@ -46,6 +47,11 @@ struct android_display_info *x_display_list;
|
||||
|
||||
static bool any_help_event_p;
|
||||
|
||||
/* Counters for tallying up scroll wheel events if
|
||||
mwheel_coalesce_scroll_events is true. */
|
||||
|
||||
static double wheel_event_x, wheel_event_y;
|
||||
|
||||
enum
|
||||
{
|
||||
ANDROID_EVENT_NORMAL,
|
||||
@ -83,19 +89,133 @@ android_clear_frame (struct frame *f)
|
||||
/* Clearing the frame will erase any cursor, so mark them all as no
|
||||
longer visible. */
|
||||
mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
|
||||
android_clear_window (FRAME_ANDROID_WINDOW (f));
|
||||
android_clear_window (FRAME_ANDROID_DRAWABLE (f));
|
||||
}
|
||||
|
||||
static void
|
||||
android_flash (struct frame *f)
|
||||
{
|
||||
struct android_gc *gc;
|
||||
struct android_gc_values values;
|
||||
int rc;
|
||||
fd_set fds;
|
||||
|
||||
block_input ();
|
||||
|
||||
values.function = ANDROID_GC_XOR;
|
||||
values.foreground = (FRAME_FOREGROUND_PIXEL (f)
|
||||
^ FRAME_BACKGROUND_PIXEL (f));
|
||||
|
||||
gc = android_create_gc ((ANDROID_GC_FUNCTION
|
||||
| ANDROID_GC_FOREGROUND),
|
||||
&values);
|
||||
|
||||
/* Get the height not including a menu bar widget. */
|
||||
int height = FRAME_PIXEL_HEIGHT (f);
|
||||
/* Height of each line to flash. */
|
||||
int flash_height = FRAME_LINE_HEIGHT (f);
|
||||
/* These will be the left and right margins of the rectangles. */
|
||||
int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
|
||||
int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
|
||||
int width = flash_right - flash_left;
|
||||
|
||||
/* If window is tall, flash top and bottom line. */
|
||||
if (height > 3 * FRAME_LINE_HEIGHT (f))
|
||||
{
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left,
|
||||
(FRAME_INTERNAL_BORDER_WIDTH (f)
|
||||
+ FRAME_TOP_MARGIN_HEIGHT (f)),
|
||||
width, flash_height);
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left,
|
||||
(height - flash_height
|
||||
- FRAME_INTERNAL_BORDER_WIDTH (f)),
|
||||
width, flash_height);
|
||||
|
||||
}
|
||||
else
|
||||
/* If it is short, flash it all. */
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
|
||||
width, (height - 2
|
||||
* FRAME_INTERNAL_BORDER_WIDTH (f)));
|
||||
|
||||
flush_frame (f);
|
||||
|
||||
struct timespec delay = make_timespec (0, 150 * 1000 * 1000);
|
||||
struct timespec wakeup = timespec_add (current_timespec (), delay);
|
||||
|
||||
/* Keep waiting until past the time wakeup or any input gets
|
||||
available. */
|
||||
while (! detect_input_pending ())
|
||||
{
|
||||
struct timespec current = current_timespec ();
|
||||
struct timespec timeout;
|
||||
|
||||
/* Break if result would not be positive. */
|
||||
if (timespec_cmp (wakeup, current) <= 0)
|
||||
break;
|
||||
|
||||
/* How long `select' should wait. */
|
||||
timeout = make_timespec (0, 10 * 1000 * 1000);
|
||||
|
||||
/* Wait for some input to become available on the X
|
||||
connection. */
|
||||
FD_ZERO (&fds);
|
||||
|
||||
/* Try to wait that long--but we might wake up sooner. */
|
||||
rc = pselect (0, &fds, NULL, NULL, &timeout, NULL);
|
||||
|
||||
/* Some input is available, exit the visible bell. */
|
||||
if (rc >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If window is tall, flash top and bottom line. */
|
||||
if (height > 3 * FRAME_LINE_HEIGHT (f))
|
||||
{
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left,
|
||||
(FRAME_INTERNAL_BORDER_WIDTH (f)
|
||||
+ FRAME_TOP_MARGIN_HEIGHT (f)),
|
||||
width, flash_height);
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left,
|
||||
(height - flash_height
|
||||
- FRAME_INTERNAL_BORDER_WIDTH (f)),
|
||||
width, flash_height);
|
||||
}
|
||||
else
|
||||
/* If it is short, flash it all. */
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
|
||||
width, (height - 2
|
||||
* FRAME_INTERNAL_BORDER_WIDTH (f)));
|
||||
|
||||
android_free_gc (gc);
|
||||
flush_frame (f);
|
||||
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
static void
|
||||
android_ring_bell (struct frame *f)
|
||||
{
|
||||
/* TODO */
|
||||
if (visible_bell)
|
||||
android_flash (f);
|
||||
else
|
||||
{
|
||||
block_input ();
|
||||
android_bell ();
|
||||
unblock_input ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
android_toggle_invisible_pointer (struct frame *f, bool invisible)
|
||||
{
|
||||
/* TODO */
|
||||
|
||||
}
|
||||
|
||||
/* Start an update of frame F. This function is installed as a hook
|
||||
@ -127,10 +247,17 @@ show_back_buffer (struct frame *f)
|
||||
{
|
||||
struct android_swap_info swap_info;
|
||||
|
||||
/* Somehow Android frames can be swapped while garbaged. */
|
||||
if (FRAME_GARBAGED_P (f))
|
||||
return;
|
||||
|
||||
memset (&swap_info, 0, sizeof (swap_info));
|
||||
swap_info.swap_window = FRAME_ANDROID_WINDOW (f);
|
||||
swap_info.swap_action = ANDROID_COPIED;
|
||||
android_swap_buffers (&swap_info, 1);
|
||||
|
||||
/* Now the back buffer no longer needs to be flipped. */
|
||||
FRAME_ANDROID_NEED_BUFFER_FLIP (f) = false;
|
||||
}
|
||||
|
||||
/* Flip back buffers on F if it has undrawn content. */
|
||||
@ -142,7 +269,8 @@ android_flush_dirty_back_buffer_on (struct frame *f)
|
||||
|| buffer_flipping_blocked_p ()
|
||||
/* If the frame is not already up to date, do not flush buffers
|
||||
on input, as that will result in flicker. */
|
||||
|| !FRAME_ANDROID_COMPLETE_P (f))
|
||||
|| !FRAME_ANDROID_COMPLETE_P (f)
|
||||
&& FRAME_ANDROID_NEED_BUFFER_FLIP (f))
|
||||
return;
|
||||
|
||||
show_back_buffer (f);
|
||||
@ -174,13 +302,13 @@ static void android_frame_rehighlight (struct android_display_info *);
|
||||
static void
|
||||
android_lower_frame (struct frame *f)
|
||||
{
|
||||
/* TODO. */
|
||||
android_lower_window (FRAME_ANDROID_WINDOW (f));
|
||||
}
|
||||
|
||||
static void
|
||||
android_raise_frame (struct frame *f)
|
||||
{
|
||||
/* TODO. */
|
||||
android_raise_window (FRAME_ANDROID_WINDOW (f));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -354,6 +482,46 @@ android_construct_mouse_click (struct input_event *result,
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* Generate a TOUCHSCREEN_UPDATE_EVENT for all pressed tools in FRAME.
|
||||
Return the event in IE. Do not set IE->timestamp, as that is left
|
||||
to the caller. */
|
||||
|
||||
static void
|
||||
android_update_tools (struct frame *f, struct input_event *ie)
|
||||
{
|
||||
struct android_touch_point *touchpoint;
|
||||
|
||||
ie->kind = TOUCHSCREEN_UPDATE_EVENT;
|
||||
XSETFRAME (ie->frame_or_window, f);
|
||||
ie->arg = Qnil;
|
||||
|
||||
/* Build the list of active touches. */
|
||||
for (touchpoint = FRAME_OUTPUT_DATA (f)->touch_points;
|
||||
touchpoint; touchpoint = touchpoint->next)
|
||||
ie->arg = Fcons (list3i (touchpoint->x,
|
||||
touchpoint->y,
|
||||
touchpoint->tool_id),
|
||||
ie->arg);
|
||||
}
|
||||
|
||||
/* Find and return an existing tool pressed against FRAME, identified
|
||||
by POINTER_ID. Return NULL if no tool by that ID was found. */
|
||||
|
||||
static struct android_touch_point *
|
||||
android_find_tool (struct frame *f, int pointer_id)
|
||||
{
|
||||
struct android_touch_point *touchpoint;
|
||||
|
||||
for (touchpoint = FRAME_OUTPUT_DATA (f)->touch_points;
|
||||
touchpoint; touchpoint = touchpoint->next)
|
||||
{
|
||||
if (touchpoint->tool_id == pointer_id)
|
||||
return touchpoint;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_one_android_event (struct android_display_info *dpyinfo,
|
||||
union android_event *event, int *finish,
|
||||
@ -364,6 +532,10 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
||||
Mouse_HLInfo *hlinfo;
|
||||
union buffered_input_event inev;
|
||||
int modifiers, count, do_help;
|
||||
struct android_touch_point *touchpoint, **last;
|
||||
Lisp_Object window;
|
||||
int scroll_height;
|
||||
double scroll_unit;
|
||||
|
||||
/* It is okay for this to not resemble handle_one_xevent so much.
|
||||
Differences in event handling code are much less nasty than
|
||||
@ -633,6 +805,28 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
||||
|
||||
f = mouse_or_wdesc_frame (dpyinfo, event->xbutton.window);
|
||||
|
||||
if (f && event->xbutton.type == ANDROID_BUTTON_PRESS
|
||||
&& !popup_activated ()
|
||||
/* && !x_window_to_scroll_bar (event->xbutton.display, */
|
||||
/* event->xbutton.window, 2) */
|
||||
&& !FRAME_NO_ACCEPT_FOCUS (f))
|
||||
{
|
||||
/* When clicking into a child frame or when clicking
|
||||
into a parent frame with the child frame selected and
|
||||
`no-accept-focus' is not set, select the clicked
|
||||
frame. */
|
||||
struct frame *hf = dpyinfo->highlight_frame;
|
||||
|
||||
if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
|
||||
{
|
||||
android_set_input_focus (FRAME_ANDROID_WINDOW (f),
|
||||
event->xbutton.time);
|
||||
|
||||
if (FRAME_PARENT_FRAME (f))
|
||||
android_raise_window (FRAME_ANDROID_WINDOW (f));
|
||||
}
|
||||
}
|
||||
|
||||
if (f)
|
||||
{
|
||||
/* Is this in the tab-bar? */
|
||||
@ -715,6 +909,223 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
||||
|
||||
goto OTHER;
|
||||
|
||||
/* Touch events. The events here don't parallel X so much. */
|
||||
case ANDROID_TOUCH_DOWN:
|
||||
|
||||
if (!any)
|
||||
goto OTHER;
|
||||
|
||||
/* This event is sent when a tool is put on the screen. X and Y
|
||||
are the location of the finger, and pointer_id identifies the
|
||||
tool for as long as it is still held down. First, see if the
|
||||
touch point already exists and can be reused (this shouldn't
|
||||
happen, but be safe.) */
|
||||
|
||||
touchpoint = android_find_tool (any, event->touch.pointer_id);
|
||||
|
||||
if (touchpoint)
|
||||
{
|
||||
/* Simply update the tool position and send an update. */
|
||||
touchpoint->x = event->touch.x;
|
||||
touchpoint->y = event->touch.x;
|
||||
android_update_tools (any, &inev.ie);
|
||||
inev.ie.timestamp = event->touch.time;
|
||||
|
||||
goto OTHER;
|
||||
}
|
||||
|
||||
/* Otherwise, link a new touchpoint onto the output's list of
|
||||
pressed tools. */
|
||||
|
||||
touchpoint = xmalloc (sizeof *touchpoint);
|
||||
touchpoint->tool_id = event->touch.pointer_id;
|
||||
touchpoint->x = event->touch.x;
|
||||
touchpoint->y = event->touch.x;
|
||||
touchpoint->next = FRAME_OUTPUT_DATA (any)->touch_points;
|
||||
FRAME_OUTPUT_DATA (any)->touch_points = touchpoint;
|
||||
|
||||
/* Now generate the Emacs event. */
|
||||
inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT;
|
||||
inev.ie.timestamp = event->touch.time;
|
||||
XSETFRAME (inev.ie.frame_or_window, any);
|
||||
XSETINT (inev.ie.x, event->touch.x);
|
||||
XSETINT (inev.ie.y, event->touch.y);
|
||||
XSETINT (inev.ie.arg, event->touch.pointer_id);
|
||||
|
||||
goto OTHER;
|
||||
|
||||
case ANDROID_TOUCH_MOVE:
|
||||
|
||||
if (!any)
|
||||
goto OTHER;
|
||||
|
||||
/* Look for the tool that moved. */
|
||||
|
||||
touchpoint = android_find_tool (any, event->touch.pointer_id);
|
||||
|
||||
/* If it doesn't exist, skip processing this event. */
|
||||
|
||||
if (!touchpoint)
|
||||
goto OTHER;
|
||||
|
||||
/* Otherwise, update the position and send the update event. */
|
||||
|
||||
touchpoint->x = event->touch.x;
|
||||
touchpoint->y = event->touch.y;
|
||||
android_update_tools (any, &inev.ie);
|
||||
inev.ie.timestamp = event->touch.time;
|
||||
|
||||
goto OTHER;
|
||||
|
||||
case ANDROID_TOUCH_UP:
|
||||
|
||||
if (!any)
|
||||
goto OTHER;
|
||||
|
||||
/* Now find and unlink the tool in question. */
|
||||
|
||||
last = &FRAME_OUTPUT_DATA (any)->touch_points;
|
||||
while ((touchpoint = *last))
|
||||
{
|
||||
if (touchpoint->tool_id == event->touch.pointer_id)
|
||||
{
|
||||
*last = touchpoint->next;
|
||||
|
||||
/* The tool was unlinked. Free it and generate the
|
||||
appropriate Emacs event. */
|
||||
xfree (touchpoint);
|
||||
inev.ie.kind = TOUCHSCREEN_END_EVENT;
|
||||
inev.ie.timestamp = event->touch.time;
|
||||
|
||||
XSETFRAME (inev.ie.frame_or_window, any);
|
||||
XSETINT (inev.ie.x, event->touch.x);
|
||||
XSETINT (inev.ie.y, event->touch.y);
|
||||
XSETINT (inev.ie.arg, event->touch.pointer_id);
|
||||
|
||||
/* Break out of the loop. */
|
||||
goto OTHER;
|
||||
}
|
||||
else
|
||||
last = &touchpoint->next;
|
||||
}
|
||||
|
||||
/* No touch point was found. This shouldn't happen. */
|
||||
goto OTHER;
|
||||
|
||||
/* Wheel motion. The events here don't parallel X because
|
||||
Android doesn't have scroll valuators. */
|
||||
|
||||
case ANDROID_WHEEL:
|
||||
|
||||
if (!any)
|
||||
goto OTHER;
|
||||
|
||||
if (fabs (event->wheel.x_delta) > 0
|
||||
|| fabs (event->wheel.y_delta) > 0)
|
||||
{
|
||||
if (mwheel_coalesce_scroll_events)
|
||||
{
|
||||
if (signbit (event->wheel.x_delta)
|
||||
!= signbit (wheel_event_x))
|
||||
wheel_event_x = 0.0;
|
||||
|
||||
if (signbit (event->wheel.y_delta)
|
||||
!= signbit (wheel_event_y))
|
||||
wheel_event_y = 0.0;
|
||||
|
||||
/* Tally up deltas until one of them exceeds 1.0. */
|
||||
wheel_event_x += event->wheel.x_delta;
|
||||
wheel_event_y += event->wheel.y_delta;
|
||||
|
||||
if (fabs (wheel_event_x) < 1.0
|
||||
&& fabs (wheel_event_y) < 1.0)
|
||||
goto OTHER;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the deltas in the event. */
|
||||
wheel_event_x = event->wheel.x_delta;
|
||||
wheel_event_y = event->wheel.y_delta;
|
||||
}
|
||||
|
||||
/* Determine what kind of event to send. */
|
||||
inev.ie.kind = ((fabs (wheel_event_y)
|
||||
>= fabs (wheel_event_x))
|
||||
? WHEEL_EVENT : HORIZ_WHEEL_EVENT);
|
||||
inev.ie.timestamp = event->wheel.time;
|
||||
|
||||
/* Set the event coordinates. */
|
||||
XSETINT (inev.ie.x, event->wheel.x);
|
||||
XSETINT (inev.ie.y, event->wheel.y);
|
||||
|
||||
/* Set the frame. */
|
||||
XSETFRAME (inev.ie.frame_or_window, any);
|
||||
|
||||
/* Figure out the scroll direction. */
|
||||
inev.ie.modifiers = (signbit ((fabs (wheel_event_x)
|
||||
>= fabs (wheel_event_y))
|
||||
? wheel_event_x
|
||||
: wheel_event_y)
|
||||
? down_modifier : up_modifier);
|
||||
|
||||
/* Figure out how much to scale the deltas by. */
|
||||
window = window_from_coordinates (any, event->wheel.x,
|
||||
event->wheel.y, NULL,
|
||||
false, false);
|
||||
|
||||
if (WINDOWP (window))
|
||||
scroll_height = XWINDOW (window)->pixel_height;
|
||||
else
|
||||
/* EVENT_X and EVENT_Y can be outside the
|
||||
frame if F holds the input grab, so fall
|
||||
back to the height of the frame instead. */
|
||||
scroll_height = FRAME_PIXEL_HEIGHT (any);
|
||||
|
||||
scroll_unit = pow (scroll_height, 2.0 / 3.0);
|
||||
|
||||
/* Add the keyboard modifiers. */
|
||||
inev.ie.modifiers
|
||||
|= android_android_to_emacs_modifiers (dpyinfo,
|
||||
event->wheel.state);
|
||||
|
||||
/* Finally include the scroll deltas. */
|
||||
inev.ie.arg = list3 (Qnil,
|
||||
make_float (wheel_event_x
|
||||
* scroll_unit),
|
||||
make_float (wheel_event_y
|
||||
* scroll_unit));
|
||||
|
||||
wheel_event_x = 0.0;
|
||||
wheel_event_y = 0.0;
|
||||
}
|
||||
|
||||
goto OTHER;
|
||||
|
||||
/* Iconification. This is vastly simpler than on X. */
|
||||
case ANDROID_ICONIFIED:
|
||||
|
||||
if (FRAME_ICONIFIED_P (any))
|
||||
goto OTHER;
|
||||
|
||||
SET_FRAME_VISIBLE (any, false);
|
||||
SET_FRAME_ICONIFIED (any, true);
|
||||
|
||||
inev.ie.kind = ICONIFY_EVENT;
|
||||
XSETFRAME (inev.ie.frame_or_window, any);
|
||||
goto OTHER;
|
||||
|
||||
case ANDROID_DEICONIFIED:
|
||||
|
||||
if (!FRAME_ICONIFIED_P (any))
|
||||
goto OTHER;
|
||||
|
||||
SET_FRAME_VISIBLE (any, true);
|
||||
SET_FRAME_ICONIFIED (any, false);
|
||||
|
||||
inev.ie.kind = DEICONIFY_EVENT;
|
||||
XSETFRAME (inev.ie.frame_or_window, any);
|
||||
goto OTHER;
|
||||
|
||||
default:
|
||||
goto OTHER;
|
||||
}
|
||||
@ -781,8 +1192,7 @@ android_read_socket (struct terminal *terminal,
|
||||
now. */
|
||||
if (dpyinfo->pending_autoraise_frame)
|
||||
{
|
||||
/* android_raise_frame (dpyinfo->pending_autoraise_frame);
|
||||
TODO */
|
||||
android_raise_frame (dpyinfo->pending_autoraise_frame);
|
||||
dpyinfo->pending_autoraise_frame = NULL;
|
||||
}
|
||||
|
||||
@ -796,7 +1206,8 @@ android_frame_up_to_date (struct frame *f)
|
||||
block_input ();
|
||||
FRAME_MOUSE_UPDATE (f);
|
||||
|
||||
if (!buffer_flipping_blocked_p ())
|
||||
if (!buffer_flipping_blocked_p ()
|
||||
&& FRAME_ANDROID_NEED_BUFFER_FLIP (f))
|
||||
show_back_buffer (f);
|
||||
|
||||
/* The frame is now complete, as its contents have been drawn. */
|
||||
@ -808,7 +1219,10 @@ static void
|
||||
android_buffer_flipping_unblocked_hook (struct frame *f)
|
||||
{
|
||||
block_input ();
|
||||
show_back_buffer (f);
|
||||
|
||||
if (FRAME_ANDROID_NEED_BUFFER_FLIP (f))
|
||||
show_back_buffer (f);
|
||||
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
@ -935,7 +1349,25 @@ android_get_focus_frame (struct frame *f)
|
||||
static void
|
||||
android_focus_frame (struct frame *f, bool noactivate)
|
||||
{
|
||||
/* TODO */
|
||||
/* Set the input focus to the frame's window. The system only lets
|
||||
this work on child frames. */
|
||||
android_set_input_focus (FRAME_ANDROID_WINDOW (f),
|
||||
ANDROID_CURRENT_TIME);
|
||||
}
|
||||
|
||||
/* The two procedures below only have to update the cursor on Android,
|
||||
as there are no window borders there. */
|
||||
|
||||
static void
|
||||
android_frame_highlight (struct frame *f)
|
||||
{
|
||||
gui_update_cursor (f, true);
|
||||
}
|
||||
|
||||
static void
|
||||
android_frame_unhighlight (struct frame *f)
|
||||
{
|
||||
gui_update_cursor (f, true);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -963,12 +1395,10 @@ android_frame_rehighlight (struct android_display_info *dpyinfo)
|
||||
if (dpyinfo->highlight_frame != old_highlight)
|
||||
{
|
||||
/* This is not yet required on Android. */
|
||||
#if 0
|
||||
if (old_highlight)
|
||||
android_frame_unhighlight (old_highlight);
|
||||
if (dpyinfo->highlight_frame)
|
||||
android_frame_highlight (dpyinfo->highlight_frame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1027,7 +1457,8 @@ android_fullscreen_hook (struct frame *f)
|
||||
void
|
||||
android_iconify_frame (struct frame *f)
|
||||
{
|
||||
/* TODO */
|
||||
/* This really doesn't work on Android. */
|
||||
error ("Can't notify window manager of iconification");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1149,7 +1580,7 @@ android_set_offset (struct frame *f, int xoff, int yoff,
|
||||
static void
|
||||
android_set_alpha (struct frame *f)
|
||||
{
|
||||
/* TODO */
|
||||
/* Not supported on Android. */
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
@ -1215,6 +1646,7 @@ android_free_frame_resources (struct frame *f)
|
||||
{
|
||||
struct android_display_info *dpyinfo;
|
||||
Mouse_HLInfo *hlinfo;
|
||||
struct android_touch_point *last, *next;
|
||||
|
||||
dpyinfo = FRAME_DISPLAY_INFO (f);
|
||||
hlinfo = &dpyinfo->mouse_highlight;
|
||||
@ -1256,6 +1688,18 @@ android_free_frame_resources (struct frame *f)
|
||||
if (f == dpyinfo->last_mouse_frame)
|
||||
dpyinfo->last_mouse_frame = NULL;
|
||||
|
||||
/* Free all tool presses currently active on this frame. */
|
||||
next = FRAME_OUTPUT_DATA (f)->touch_points;
|
||||
while (next)
|
||||
{
|
||||
last = next;
|
||||
next = next->next;
|
||||
xfree (last);
|
||||
}
|
||||
|
||||
/* Clear this in case unblock_input reads events. */
|
||||
FRAME_OUTPUT_DATA (f)->touch_points = NULL;
|
||||
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
@ -1316,8 +1760,8 @@ android_scroll_run (struct window *w, struct run *run)
|
||||
/* Cursor off. Will be switched on again in gui_update_window_end. */
|
||||
gui_clear_cursor (w);
|
||||
|
||||
android_copy_area (FRAME_ANDROID_WINDOW (f),
|
||||
FRAME_ANDROID_WINDOW (f),
|
||||
android_copy_area (FRAME_ANDROID_DRAWABLE (f),
|
||||
FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x, from_y, width, height, x, to_y);
|
||||
|
||||
@ -1337,7 +1781,9 @@ static void
|
||||
android_flip_and_flush (struct frame *f)
|
||||
{
|
||||
block_input ();
|
||||
show_back_buffer (f);
|
||||
|
||||
if (FRAME_ANDROID_NEED_BUFFER_FLIP (f))
|
||||
show_back_buffer (f);
|
||||
|
||||
/* The frame is complete again as its contents were just
|
||||
flushed. */
|
||||
@ -1355,7 +1801,7 @@ android_clear_rectangle (struct frame *f, struct android_gc *gc, int x,
|
||||
| ANDROID_GC_FOREGROUND),
|
||||
&xgcv);
|
||||
android_set_foreground (gc, xgcv.background);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
x, y, width, height);
|
||||
android_set_foreground (gc, xgcv.foreground);
|
||||
}
|
||||
@ -1405,7 +1851,7 @@ android_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
|
||||
if (face->stipple)
|
||||
{
|
||||
android_set_fill_style (face->gc, ANDROID_FILL_OPAQUE_STIPPLED);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), face->gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), face->gc,
|
||||
p->bx, p->by, p->nx, p->ny);
|
||||
android_set_fill_style (face->gc, ANDROID_FILL_SOLID);
|
||||
|
||||
@ -1428,7 +1874,7 @@ android_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
|
||||
unsigned long background, cursor_pixel;
|
||||
int depth;
|
||||
|
||||
drawable = FRAME_ANDROID_WINDOW (f);
|
||||
drawable = FRAME_ANDROID_DRAWABLE (f);
|
||||
clipmask = ANDROID_NONE;
|
||||
background = face->background;
|
||||
cursor_pixel = f->output_data.android->cursor_pixel;
|
||||
@ -1697,7 +2143,7 @@ android_draw_glyph_string_background (struct glyph_string *s, bool force_p)
|
||||
{
|
||||
/* Fill background with a stipple pattern. */
|
||||
android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
s->x, s->y + box_line_width,
|
||||
s->background_width,
|
||||
s->height - 2 * box_line_width);
|
||||
@ -1734,7 +2180,7 @@ android_fill_triangle (struct frame *f, struct android_gc *gc,
|
||||
abc[1] = point2;
|
||||
abc[2] = point3;
|
||||
|
||||
android_fill_polygon (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_polygon (FRAME_ANDROID_DRAWABLE (f),
|
||||
gc, abc, 3, ANDROID_CONVEX,
|
||||
ANDROID_COORD_MODE_ORIGIN);
|
||||
}
|
||||
@ -1776,7 +2222,7 @@ android_clear_point (struct frame *f, struct android_gc *gc,
|
||||
android_get_gc_values (gc, ANDROID_GC_BACKGROUND | ANDROID_GC_FOREGROUND,
|
||||
&xgcv);
|
||||
android_set_foreground (gc, xgcv.background);
|
||||
android_draw_point (FRAME_ANDROID_WINDOW (f), gc, x, y);
|
||||
android_draw_point (FRAME_ANDROID_DRAWABLE (f), gc, x, y);
|
||||
android_set_foreground (gc, xgcv.foreground);
|
||||
}
|
||||
|
||||
@ -1798,7 +2244,7 @@ android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
|
||||
black_gc = f->output_data.android->black_relief.gc;
|
||||
normal_gc = f->output_data.android->normal_gc;
|
||||
|
||||
drawable = FRAME_ANDROID_WINDOW (f);
|
||||
drawable = FRAME_ANDROID_DRAWABLE (f);
|
||||
|
||||
android_set_clip_rectangles (white_gc, 0, 0, clip_rect, 1);
|
||||
android_set_clip_rectangles (black_gc, 0, 0, clip_rect, 1);
|
||||
@ -1811,11 +2257,11 @@ android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
|
||||
/* Draw lines. */
|
||||
|
||||
if (top_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, left_x, top_y,
|
||||
right_x - left_x + 1, hwidth);
|
||||
|
||||
if (left_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, left_x, top_y,
|
||||
vwidth, bottom_y - top_y + 1);
|
||||
|
||||
if (raised_p)
|
||||
@ -1824,12 +2270,12 @@ android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
|
||||
gc = white_gc;
|
||||
|
||||
if (bot_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, left_x,
|
||||
bottom_y - hwidth + 1,
|
||||
right_x - left_x + 1, hwidth);
|
||||
|
||||
if (right_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc,
|
||||
right_x - vwidth + 1,
|
||||
top_y, vwidth, bottom_y - top_y + 1);
|
||||
|
||||
@ -1853,7 +2299,7 @@ android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x,
|
||||
|
||||
if (top_p && left_p && bot_p && right_p
|
||||
&& hwidth > 1 && vwidth > 1)
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
black_gc, left_x, top_y,
|
||||
right_x - left_x, bottom_y - top_y);
|
||||
else
|
||||
@ -1913,22 +2359,22 @@ android_draw_box_rect (struct glyph_string *s,
|
||||
android_set_clip_rectangles (s->gc, 0, 0, clip_rect, 1);
|
||||
|
||||
/* Top. */
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x,
|
||||
left_x, right_x - left_x + 1, hwidth);
|
||||
|
||||
/* Left. */
|
||||
if (left_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x,
|
||||
top_y, vwidth, bottom_y - top_y + 1);
|
||||
|
||||
/* Bottom. */
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x,
|
||||
bottom_y - hwidth + 1, right_x - left_x + 1,
|
||||
hwidth);
|
||||
|
||||
/* Right. */
|
||||
if (right_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
right_x - vwidth + 1, top_y, vwidth,
|
||||
bottom_y - top_y + 1);
|
||||
|
||||
@ -2153,7 +2599,7 @@ android_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y,
|
||||
{
|
||||
/* Fill background with a stipple pattern. */
|
||||
android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, x,
|
||||
y, w, h);
|
||||
android_set_fill_style (s->gc, ANDROID_FILL_SOLID);
|
||||
}
|
||||
@ -2294,7 +2740,7 @@ android_draw_image_foreground (struct glyph_string *s)
|
||||
|
||||
if (gui_intersect_rectangles (&clip_rect, &image_rect, &r))
|
||||
android_copy_area (s->img->pixmap,
|
||||
FRAME_ANDROID_WINDOW (s->f),
|
||||
FRAME_ANDROID_DRAWABLE (s->f),
|
||||
s->gc, s->slice.x + r.x - x,
|
||||
s->slice.y + r.y - y,
|
||||
r.width, r.height, r.x, r.y);
|
||||
@ -2307,7 +2753,7 @@ android_draw_image_foreground (struct glyph_string *s)
|
||||
if (s->hl == DRAW_CURSOR && !s->img->mask)
|
||||
{
|
||||
int relief = eabs (s->img->relief);
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
x - relief, y - relief,
|
||||
s->slice.width + relief*2 - 1,
|
||||
s->slice.height + relief*2 - 1);
|
||||
@ -2317,7 +2763,7 @@ android_draw_image_foreground (struct glyph_string *s)
|
||||
}
|
||||
else
|
||||
/* Draw a rectangle if image could not be loaded. */
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y,
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, x, y,
|
||||
s->slice.width - 1, s->slice.height - 1);
|
||||
}
|
||||
|
||||
@ -2444,7 +2890,7 @@ android_draw_stretch_glyph_string (struct glyph_string *s)
|
||||
{
|
||||
/* Fill background with a stipple pattern. */
|
||||
android_set_fill_style (gc, ANDROID_FILL_OPAQUE_STIPPLED);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
gc, x, y, w, h);
|
||||
android_set_fill_style (gc, ANDROID_FILL_SOLID);
|
||||
|
||||
@ -2457,7 +2903,7 @@ android_draw_stretch_glyph_string (struct glyph_string *s)
|
||||
| ANDROID_GC_BACKGROUND),
|
||||
&xgcv);
|
||||
android_set_foreground (gc, xgcv.background);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
gc, x, y, w, h);
|
||||
android_set_foreground (gc, xgcv.foreground);
|
||||
}
|
||||
@ -2536,7 +2982,7 @@ android_draw_underwave (struct glyph_string *s, int decoration_width)
|
||||
|
||||
while (x1 <= xmax)
|
||||
{
|
||||
android_draw_line (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_draw_line (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
x1, y1, x2, y2);
|
||||
x1 = x2, y1 = y2;
|
||||
x2 += dx, y2 = y0 + odd*dy;
|
||||
@ -2567,7 +3013,7 @@ android_draw_glyph_string_foreground (struct glyph_string *s)
|
||||
for (i = 0; i < s->nchars; ++i)
|
||||
{
|
||||
struct glyph *g = s->first_glyph + i;
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
s->gc, x, s->y,
|
||||
g->pixel_width - 1,
|
||||
s->height - 1);
|
||||
@ -2618,7 +3064,7 @@ android_draw_composite_glyph_string_foreground (struct glyph_string *s)
|
||||
if (s->font_not_found_p)
|
||||
{
|
||||
if (s->cmp_from == 0)
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
s->gc, x, s->y,
|
||||
s->width - 1, s->height - 1);
|
||||
}
|
||||
@ -2754,7 +3200,7 @@ android_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
|
||||
false);
|
||||
}
|
||||
if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
x, s->ybase - glyph->ascent,
|
||||
glyph->pixel_width - 1,
|
||||
glyph->ascent + glyph->descent - 1);
|
||||
@ -2987,14 +3433,14 @@ android_draw_glyph_string (struct glyph_string *s)
|
||||
s->underline_position = position;
|
||||
y = s->ybase + position;
|
||||
if (s->face->underline_defaulted_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
s->x, y, decoration_width, thickness);
|
||||
else
|
||||
{
|
||||
struct android_gc_values xgcv;
|
||||
android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv);
|
||||
android_set_foreground (s->gc, s->face->underline_color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
s->x, y, decoration_width, thickness);
|
||||
android_set_foreground (s->gc, xgcv.foreground);
|
||||
}
|
||||
@ -3006,7 +3452,7 @@ android_draw_glyph_string (struct glyph_string *s)
|
||||
unsigned long dy = 0, h = 1;
|
||||
|
||||
if (s->face->overline_color_defaulted_p)
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
s->gc, s->x, s->y + dy,
|
||||
decoration_width, h);
|
||||
else
|
||||
@ -3014,8 +3460,8 @@ android_draw_glyph_string (struct glyph_string *s)
|
||||
struct android_gc_values xgcv;
|
||||
android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv);
|
||||
android_set_foreground (s->gc, s->face->overline_color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x,
|
||||
s->y + dy, decoration_width, h);
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
s->x, s->y + dy, decoration_width, h);
|
||||
android_set_foreground (s->gc, xgcv.foreground);
|
||||
}
|
||||
}
|
||||
@ -3044,8 +3490,9 @@ android_draw_glyph_string (struct glyph_string *s)
|
||||
struct android_gc_values xgcv;
|
||||
android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv);
|
||||
android_set_foreground (s->gc, s->face->strike_through_color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x,
|
||||
glyph_y + dy, decoration_width, h);
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc,
|
||||
s->x, glyph_y + dy, decoration_width,
|
||||
h);
|
||||
android_set_foreground (s->gc, xgcv.foreground);
|
||||
}
|
||||
}
|
||||
@ -3125,7 +3572,7 @@ static void
|
||||
android_clear_frame_area (struct frame *f, int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f),
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f),
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
@ -3154,25 +3601,25 @@ android_clear_under_internal_border (struct frame *f)
|
||||
struct android_gc *gc = f->output_data.android->normal_gc;
|
||||
|
||||
android_set_foreground (gc, color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, margin,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, 0, margin,
|
||||
width, border);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, 0,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, 0, 0,
|
||||
border, height);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, width - border,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, width - border,
|
||||
0, border, height);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, 0,
|
||||
height - border, width, border);
|
||||
android_set_foreground (gc, FRAME_FOREGROUND_PIXEL (f));
|
||||
}
|
||||
else
|
||||
{
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f), 0, 0,
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f), 0, 0,
|
||||
border, height);
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f), 0,
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f), 0,
|
||||
margin, width, border);
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f), width - border,
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f), width - border,
|
||||
0, border, height);
|
||||
android_clear_area (FRAME_ANDROID_WINDOW (f), 0,
|
||||
android_clear_area (FRAME_ANDROID_DRAWABLE (f), 0,
|
||||
height - border, width, border);
|
||||
}
|
||||
}
|
||||
@ -3221,7 +3668,7 @@ android_draw_hollow_cursor (struct window *w, struct glyph_row *row)
|
||||
}
|
||||
/* Set clipping, draw the rectangle, and reset clipping again. */
|
||||
android_clip_to_row (w, row, TEXT_AREA, gc);
|
||||
android_draw_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, y, wd, h - 1);
|
||||
android_draw_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, x, y, wd, h - 1);
|
||||
android_reset_clip_rectangles (f, gc);
|
||||
}
|
||||
|
||||
@ -3295,7 +3742,7 @@ android_draw_bar_cursor (struct window *w, struct glyph_row *row, int width,
|
||||
if ((cursor_glyph->resolved_level & 1) != 0)
|
||||
x += cursor_glyph->pixel_width - width;
|
||||
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, x,
|
||||
WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
|
||||
width, row->height);
|
||||
}
|
||||
@ -3318,7 +3765,7 @@ android_draw_bar_cursor (struct window *w, struct glyph_row *row, int width,
|
||||
if ((cursor_glyph->resolved_level & 1) != 0
|
||||
&& cursor_glyph->pixel_width > w->phys_cursor_width - 1)
|
||||
x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x,
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f), gc, x,
|
||||
cursor_start_y,
|
||||
w->phys_cursor_width - 1, width);
|
||||
}
|
||||
@ -3387,7 +3834,7 @@ android_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
face->foreground);
|
||||
|
||||
android_draw_line (FRAME_ANDROID_WINDOW (f),
|
||||
android_draw_line (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x, y0, x, y1);
|
||||
}
|
||||
@ -3415,17 +3862,17 @@ android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
|
||||
{
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
color_first);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0, y0, 1, y1 - y0);
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0 + 1, y0, x1 - x0 - 2, y1 - y0);
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
color_last);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x1 - 1, y0, 1, y1 - y0);
|
||||
}
|
||||
@ -3435,16 +3882,16 @@ android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
|
||||
{
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
color_first);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0, y0, x1 - x0, 1);
|
||||
android_set_foreground (f->output_data.android->normal_gc, color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0, y0 + 1, x1 - x0, y1 - y0 - 2);
|
||||
android_set_foreground (f->output_data.android->normal_gc,
|
||||
color_last);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0, y1 - 1, x1 - x0, 1);
|
||||
}
|
||||
@ -3453,7 +3900,7 @@ android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
|
||||
/* In any other case do not draw the first and last pixels
|
||||
differently. */
|
||||
android_set_foreground (f->output_data.android->normal_gc, color);
|
||||
android_fill_rectangle (FRAME_ANDROID_WINDOW (f),
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (f),
|
||||
f->output_data.android->normal_gc,
|
||||
x0, y0, x1 - x0, y1 - y0);
|
||||
}
|
||||
|
@ -134,6 +134,18 @@ struct android_display_info
|
||||
Time last_mouse_movement_time;
|
||||
};
|
||||
|
||||
/* Structure representing a single tool (finger or stylus) pressed
|
||||
onto a frame. */
|
||||
|
||||
struct android_touch_point
|
||||
{
|
||||
/* The next tool on this list. */
|
||||
struct android_touch_point *next;
|
||||
|
||||
/* The tool ID and the last known X and Y positions. */
|
||||
int tool_id, x, y;
|
||||
};
|
||||
|
||||
struct android_output
|
||||
{
|
||||
/* Graphics contexts for the default font. */
|
||||
@ -201,6 +213,10 @@ struct android_output
|
||||
input. */
|
||||
bool_bf complete : 1;
|
||||
|
||||
/* True that indicates whether or not a buffer flip is required
|
||||
because the frame contents have been dirtied. */
|
||||
bool_bf need_buffer_flip : 1;
|
||||
|
||||
/* Relief GCs, colors etc. */
|
||||
struct relief {
|
||||
struct android_gc *gc;
|
||||
@ -214,6 +230,10 @@ struct android_output
|
||||
/* Focus state. Only present for consistency with X; it is actually
|
||||
a boolean. */
|
||||
int focus_state;
|
||||
|
||||
/* List of all tools (either styluses or fingers) pressed onto the
|
||||
frame. */
|
||||
struct android_touch_point *touch_points;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -240,6 +260,14 @@ enum
|
||||
#define FRAME_ANDROID_NEED_BUFFER_FLIP(f) \
|
||||
((f)->output_data.android->need_buffer_flip)
|
||||
|
||||
/* Return the drawable used for rendering to frame F and mark the
|
||||
frame as needing a buffer flip later. There's no easy way to run
|
||||
code after any drawing command, but code can be run whenever
|
||||
someone asks for the handle necessary to draw. */
|
||||
#define FRAME_ANDROID_DRAWABLE(f) \
|
||||
(((f))->output_data.android->need_buffer_flip = true, \
|
||||
FRAME_ANDROID_WINDOW ((f)))
|
||||
|
||||
/* Return whether or not the frame F has been completely drawn. Used
|
||||
while handling async input. */
|
||||
#define FRAME_ANDROID_COMPLETE_P(f) \
|
||||
|
50
src/dired.c
50
src/dired.c
@ -44,6 +44,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include "msdos.h" /* for fstatat */
|
||||
#endif
|
||||
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
typedef DIR emacs_dir;
|
||||
#define emacs_readdir readdir
|
||||
#define emacs_closedir closedir
|
||||
#else
|
||||
|
||||
#include "android.h"
|
||||
|
||||
/* The Android emulation of dirent stuff is required to be able to
|
||||
list the /assets special directory. */
|
||||
typedef struct android_dir emacs_dir;
|
||||
#define emacs_readdir android_readdir
|
||||
#define emacs_closedir android_closedir
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
extern int is_slow_fs (const char *);
|
||||
#endif
|
||||
@ -78,19 +93,30 @@ dirent_type (struct dirent *dp)
|
||||
#endif
|
||||
}
|
||||
|
||||
static DIR *
|
||||
static emacs_dir *
|
||||
open_directory (Lisp_Object dirname, Lisp_Object encoded_dirname, int *fdp)
|
||||
{
|
||||
char *name = SSDATA (encoded_dirname);
|
||||
DIR *d;
|
||||
emacs_dir *d;
|
||||
int fd, opendir_errno;
|
||||
|
||||
#ifdef DOS_NT
|
||||
/* Directories cannot be opened. The emulation assumes that any
|
||||
file descriptor other than AT_FDCWD corresponds to the most
|
||||
recently opened directory. This hack is good enough for Emacs. */
|
||||
#if defined DOS_NT || (defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
/* On DOS_NT, directories cannot be opened. The emulation assumes
|
||||
that any file descriptor other than AT_FDCWD corresponds to the
|
||||
most recently opened directory. This hack is good enough for
|
||||
Emacs.
|
||||
|
||||
This code is also used on Android for a different reason: a
|
||||
special `assets' directory outside the normal file system is used
|
||||
to open assets inside the Android application package, and must
|
||||
be listed using the opendir-like interface provided in
|
||||
android.h. */
|
||||
fd = 0;
|
||||
#ifndef HAVE_ANDROID
|
||||
d = opendir (name);
|
||||
#else
|
||||
d = android_opendir (name);
|
||||
#endif
|
||||
opendir_errno = errno;
|
||||
#else
|
||||
fd = emacs_open (name, O_RDONLY | O_DIRECTORY, 0);
|
||||
@ -125,7 +151,7 @@ directory_files_internal_w32_unwind (Lisp_Object arg)
|
||||
static void
|
||||
directory_files_internal_unwind (void *d)
|
||||
{
|
||||
closedir (d);
|
||||
emacs_closedir (d);
|
||||
}
|
||||
|
||||
/* Return the next directory entry from DIR; DIR's name is DIRNAME.
|
||||
@ -133,12 +159,12 @@ directory_files_internal_unwind (void *d)
|
||||
Signal any unrecoverable errors. */
|
||||
|
||||
static struct dirent *
|
||||
read_dirent (DIR *dir, Lisp_Object dirname)
|
||||
read_dirent (emacs_dir *dir, Lisp_Object dirname)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
errno = 0;
|
||||
struct dirent *dp = readdir (dir);
|
||||
struct dirent *dp = emacs_readdir (dir);
|
||||
if (dp || errno == 0)
|
||||
return dp;
|
||||
if (! (errno == EAGAIN || errno == EINTR))
|
||||
@ -190,7 +216,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
||||
Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
|
||||
|
||||
int fd;
|
||||
DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd);
|
||||
emacs_dir *d = open_directory (dirfilename, encoded_dirfilename, &fd);
|
||||
|
||||
/* Unfortunately, we can now invoke expand-file-name and
|
||||
file-attributes on filenames, both of which can throw, so we must
|
||||
@ -300,7 +326,7 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
||||
list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list);
|
||||
}
|
||||
|
||||
closedir (d);
|
||||
emacs_closedir (d);
|
||||
#ifdef WINDOWSNT
|
||||
if (attrs)
|
||||
Vw32_get_true_file_attributes = w32_save;
|
||||
@ -514,7 +540,7 @@ file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
|
||||
}
|
||||
}
|
||||
int fd;
|
||||
DIR *d = open_directory (dirname, encoded_dir, &fd);
|
||||
emacs_dir *d = open_directory (dirname, encoded_dir, &fd);
|
||||
record_unwind_protect_ptr (directory_files_internal_unwind, d);
|
||||
|
||||
/* Loop reading directory entries. */
|
||||
|
@ -3175,6 +3175,7 @@ redraw_frame (struct frame *f)
|
||||
its redisplay done. */
|
||||
mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
|
||||
set_window_update_flags (XWINDOW (FRAME_ROOT_WINDOW (f)), true);
|
||||
|
||||
f->garbaged = false;
|
||||
}
|
||||
|
||||
@ -6053,7 +6054,7 @@ FILE = nil means just close any termscript file currently open. */)
|
||||
if (tty->termscript != 0)
|
||||
{
|
||||
block_input ();
|
||||
fclose (tty->termscript);
|
||||
emacs_fclose (tty->termscript);
|
||||
tty->termscript = 0;
|
||||
unblock_input ();
|
||||
}
|
||||
|
42
src/fileio.c
42
src/fileio.c
@ -277,7 +277,7 @@ void
|
||||
fclose_unwind (void *arg)
|
||||
{
|
||||
FILE *stream = arg;
|
||||
fclose (stream);
|
||||
emacs_fclose (stream);
|
||||
}
|
||||
|
||||
/* Restore point, having saved it as a marker. */
|
||||
@ -2989,6 +2989,12 @@ If there is no error, returns nil. */)
|
||||
|
||||
encoded_filename = ENCODE_FILE (absname);
|
||||
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
/* FILE may be some kind of special Android file. */
|
||||
if (android_file_access_p (SSDATA (encoded_filename), R_OK))
|
||||
return Qnil;
|
||||
#endif
|
||||
|
||||
if (faccessat (AT_FDCWD, SSDATA (encoded_filename), R_OK, AT_EACCESS) != 0)
|
||||
report_file_error (SSDATA (string), filename);
|
||||
|
||||
@ -3205,7 +3211,11 @@ file_accessible_directory_p (Lisp_Object file)
|
||||
There are three exceptions: "", "/", and "//". Leave "" alone,
|
||||
as it's invalid. Append only "." to the other two exceptions as
|
||||
"/" and "//" are distinct on some platforms, whereas "/", "///",
|
||||
"////", etc. are all equivalent. */
|
||||
"////", etc. are all equivalent.
|
||||
|
||||
Android has a special directory named "/assets". There is no "."
|
||||
directory there, but appending a "/" is sufficient to check
|
||||
whether or not it is a directory. */
|
||||
if (! len)
|
||||
dir = data;
|
||||
else
|
||||
@ -3215,11 +3225,27 @@ file_accessible_directory_p (Lisp_Object file)
|
||||
special cases "/" and "//", and it's a safe optimization
|
||||
here. After appending '.', append another '/' to work around
|
||||
a macOS bug (Bug#30350). */
|
||||
static char const appended[] = "/./";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
if (!strncmp ("/assets/", data,
|
||||
sizeof "/assets" - 1))
|
||||
{
|
||||
static char const appended[] = "/";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
static char const appended[] = "/./";
|
||||
char *buf = SAFE_ALLOCA (len + sizeof appended);
|
||||
memcpy (buf, data, len);
|
||||
strcpy (buf + len, &appended[data[len - 1] == '/']);
|
||||
dir = buf;
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ok = file_access_p (dir, F_OK);
|
||||
@ -5973,7 +5999,7 @@ do_auto_save_unwind (void *arg)
|
||||
if (stream != NULL)
|
||||
{
|
||||
block_input ();
|
||||
fclose (stream);
|
||||
emacs_fclose (stream);
|
||||
unblock_input ();
|
||||
}
|
||||
}
|
||||
|
@ -4956,8 +4956,8 @@ const char *const lispy_function_keys[] =
|
||||
[66] = "return",
|
||||
[67] = "backspace",
|
||||
[82] = "menu",
|
||||
[92] = "page-up",
|
||||
[93] = "page-down",
|
||||
[92] = "prior",
|
||||
[93] = "next",
|
||||
};
|
||||
|
||||
#elif defined HAVE_NTGUI
|
||||
@ -11219,7 +11219,7 @@ This may include sensitive information such as passwords. */)
|
||||
if (dribble)
|
||||
{
|
||||
block_input ();
|
||||
fclose (dribble);
|
||||
emacs_fclose (dribble);
|
||||
unblock_input ();
|
||||
dribble = 0;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <float.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
@ -5077,6 +5078,7 @@ extern int emacs_open (const char *, int, int);
|
||||
extern int emacs_open_noquit (const char *, int, int);
|
||||
extern int emacs_pipe (int[2]);
|
||||
extern int emacs_close (int);
|
||||
extern int emacs_fclose (FILE *);
|
||||
extern ptrdiff_t emacs_read (int, void *, ptrdiff_t);
|
||||
extern ptrdiff_t emacs_read_quit (int, void *, ptrdiff_t);
|
||||
extern ptrdiff_t emacs_write (int, void const *, ptrdiff_t);
|
||||
|
@ -1141,7 +1141,7 @@ close_infile_unwind (void *arg)
|
||||
{
|
||||
struct infile *prev_infile = arg;
|
||||
eassert (infile && infile != prev_infile);
|
||||
fclose (infile->stream);
|
||||
emacs_fclose (infile->stream);
|
||||
infile = prev_infile;
|
||||
}
|
||||
|
||||
|
35
src/sfnt.c
35
src/sfnt.c
@ -3072,8 +3072,8 @@ sfnt_curve_is_flat (struct sfnt_point control0,
|
||||
|
||||
/* 2.0 is a constant describing the area covered at which point the
|
||||
curve is considered "flat". */
|
||||
return (abs (sfnt_mul_fixed (g.x, h.x)
|
||||
- sfnt_mul_fixed (g.y, h.y))
|
||||
return (abs (sfnt_mul_fixed (g.x, h.y)
|
||||
- sfnt_mul_fixed (g.y, h.x))
|
||||
<= 0400000);
|
||||
}
|
||||
|
||||
@ -3261,9 +3261,11 @@ sfnt_prepare_raster (struct sfnt_raster *raster,
|
||||
struct sfnt_glyph_outline *outline)
|
||||
{
|
||||
raster->width
|
||||
= sfnt_ceil_fixed (outline->xmax - outline->xmin) >> 16;
|
||||
= (sfnt_ceil_fixed (outline->xmax)
|
||||
- sfnt_floor_fixed (outline->xmin)) >> 16;
|
||||
raster->height
|
||||
= sfnt_ceil_fixed (outline->ymax - outline->ymin) >> 16;
|
||||
= (sfnt_ceil_fixed (outline->ymax)
|
||||
- sfnt_floor_fixed (outline->ymin)) >> 16;
|
||||
raster->refcount = 0;
|
||||
|
||||
/* Align the raster to a SFNT_POLY_ALIGNMENT byte boundary. */
|
||||
@ -3292,10 +3294,10 @@ sfnt_step_edge (struct sfnt_edge *edge)
|
||||
}
|
||||
|
||||
/* Build a list of edges for each contour in OUTLINE, applying
|
||||
OUTLINE->xmin and OUTLINE->ymin as the offset to each edge. Call
|
||||
EDGE_PROC with DCONTEXT and the resulting edges as arguments. It
|
||||
is OK to modify the edges given to EDGE_PROC. Align all edges to
|
||||
the sub-pixel grid. */
|
||||
OUTLINE->xmin and floor (OUTLINE->ymin) as the offset to each edge.
|
||||
Call EDGE_PROC with DCONTEXT and the resulting edges as arguments.
|
||||
It is OK to modify the edges given to EDGE_PROC. Align all edges
|
||||
to the sub-pixel grid. */
|
||||
|
||||
static void
|
||||
sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
|
||||
@ -3303,13 +3305,18 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
|
||||
{
|
||||
struct sfnt_edge *edges;
|
||||
size_t i, edge, next_vertex;
|
||||
sfnt_fixed dx, dy, bot, step_x;
|
||||
sfnt_fixed dx, dy, bot, step_x, ymin, xmin;
|
||||
int inc_x;
|
||||
size_t top, bottom, y;
|
||||
|
||||
edges = alloca (outline->outline_used * sizeof *edges);
|
||||
edge = 0;
|
||||
|
||||
/* ymin and xmin must be the same as the offset used to set offy and
|
||||
offx in rasters. */
|
||||
ymin = sfnt_floor_fixed (outline->ymin);
|
||||
xmin = sfnt_floor_fixed (outline->xmin);
|
||||
|
||||
for (i = 0; i < outline->outline_used; ++i)
|
||||
{
|
||||
/* Set NEXT_VERTEX to the next point (vertex) in this contour.
|
||||
@ -3356,12 +3363,12 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline *outline,
|
||||
top = next_vertex;
|
||||
}
|
||||
|
||||
bot = (outline->outline[bottom].y - outline->ymin);
|
||||
edges[edge].top = (outline->outline[top].y - outline->ymin);
|
||||
bot = (outline->outline[bottom].y - ymin);
|
||||
edges[edge].top = (outline->outline[top].y - ymin);
|
||||
|
||||
/* Record the edge. Rasterization happens from bottom to
|
||||
up, so record the X at the bottom. */
|
||||
edges[edge].x = (outline->outline[bottom].x - outline->xmin);
|
||||
edges[edge].x = (outline->outline[bottom].x - xmin);
|
||||
dx = (outline->outline[top].x - outline->outline[bottom].x);
|
||||
dy = abs (outline->outline[top].y
|
||||
- outline->outline[bottom].y);
|
||||
@ -4585,7 +4592,7 @@ main (int argc, char **argv)
|
||||
/* Time this important bit. */
|
||||
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
|
||||
outline = sfnt_build_glyph_outline (glyph, head,
|
||||
45,
|
||||
12,
|
||||
sfnt_test_get_glyph,
|
||||
sfnt_test_free_glyph,
|
||||
&dcontext);
|
||||
@ -4652,7 +4659,7 @@ main (int argc, char **argv)
|
||||
|
||||
if (hmtx && head)
|
||||
{
|
||||
if (!sfnt_lookup_glyph_metrics (code, 36,
|
||||
if (!sfnt_lookup_glyph_metrics (code, 12,
|
||||
&metrics,
|
||||
hmtx, hhea,
|
||||
head, maxp))
|
||||
|
@ -42,19 +42,6 @@ static Lisp_Object font_cache;
|
||||
|
||||
|
||||
|
||||
static unsigned int
|
||||
sfntfont_android_saturate32 (unsigned int a, unsigned int b)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
c = a + b;
|
||||
|
||||
if (c < a)
|
||||
c = -1;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Scale each of the four packed bytes in P in the low 16 bits of P by
|
||||
SCALE. Return the result.
|
||||
|
||||
@ -107,8 +94,9 @@ sfntfont_android_blend (unsigned int src, unsigned int dst)
|
||||
src = src & ~0x00ff00ff;
|
||||
src |= (src_rb >> 16 | src_rb << 16);
|
||||
|
||||
/* Saturating is unnecessary but helps find bugs. */
|
||||
return sfntfont_android_saturate32 (both, src);
|
||||
/* This addition need not be saturating because both has already
|
||||
been multiplied by 255 - a. */
|
||||
return both + src;
|
||||
}
|
||||
|
||||
#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
|
||||
@ -128,8 +116,9 @@ sfntfont_android_blendrgb (unsigned int src, unsigned int dst)
|
||||
|
||||
both = ag_part | rb_part;
|
||||
|
||||
/* Saturating is unnecessary but helps find bugs. */
|
||||
return sfntfont_android_saturate32 (both, src);
|
||||
/* This addition need not be saturating because both has already
|
||||
been multiplied by 255 - a. */
|
||||
return both + src;
|
||||
}
|
||||
|
||||
/* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE
|
||||
@ -162,6 +151,10 @@ sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
|
||||
|
||||
src_y = i + (rect->y - text_rectangle->y);
|
||||
|
||||
if (src_y > text_rectangle->height)
|
||||
/* Huh? */
|
||||
return;
|
||||
|
||||
src_row = (unsigned int *) ((buffer + src_y * stride));
|
||||
dst_row = (unsigned int *) (dest + ((i + rect->y)
|
||||
* bitmap_info->stride));
|
||||
@ -343,7 +336,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||
}
|
||||
|
||||
/* Lock the bitmap. It must be unlocked later. */
|
||||
bitmap_data = android_lock_bitmap (FRAME_ANDROID_WINDOW (s->f),
|
||||
bitmap_data = android_lock_bitmap (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
&bitmap_info, &bitmap);
|
||||
|
||||
/* If locking the bitmap fails, just discard the data that was
|
||||
@ -385,7 +378,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||
ANDROID_DELETE_LOCAL_REF (bitmap);
|
||||
|
||||
/* Damage the window by the text rectangle. */
|
||||
android_damage_window (FRAME_ANDROID_WINDOW (s->f),
|
||||
android_damage_window (FRAME_ANDROID_DRAWABLE (s->f),
|
||||
&text_rectangle);
|
||||
|
||||
/* Release the temporary scanline buffer. */
|
||||
@ -495,13 +488,19 @@ init_sfntfont_android (void)
|
||||
version of Android the device is running. */
|
||||
if (android_get_device_api_level () >= 15)
|
||||
Vsfnt_default_family_alist
|
||||
= list2 (Fcons (build_string ("Monospace"),
|
||||
= list3 (Fcons (build_string ("Monospace"),
|
||||
build_string ("Droid Sans Mono")),
|
||||
/* Android doesn't come with a Monospace Serif font, so
|
||||
this will have to do. */
|
||||
Fcons (build_string ("Monospace Serif"),
|
||||
build_string ("Droid Sans Mono")),
|
||||
Fcons (build_string ("Sans Serif"),
|
||||
build_string ("Roboto")));
|
||||
else
|
||||
Vsfnt_default_family_alist
|
||||
= list2 (Fcons (build_string ("Monospace"),
|
||||
= list3 (Fcons (build_string ("Monospace"),
|
||||
build_string ("Droid Sans Mono")),
|
||||
Fcons (build_string ("Monospace Serif"),
|
||||
build_string ("Droid Sans Mono")),
|
||||
Fcons (build_string ("Sans Serif"),
|
||||
build_string ("Droid Sans")));
|
||||
|
@ -1982,6 +1982,9 @@ sfntfont_text_extents (struct font *font, const unsigned int *code,
|
||||
|
||||
total_width = 0;
|
||||
|
||||
/* First clear the metrics array. */
|
||||
memset (metrics, 0, sizeof *metrics);
|
||||
|
||||
/* Get the metrcs one by one, then sum them up. */
|
||||
for (i = 0; i < nglyphs; ++i)
|
||||
{
|
||||
@ -2059,7 +2062,7 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
|
||||
struct sfnt_glyph_metrics metrics;
|
||||
|
||||
length = to - from;
|
||||
font = s->face->font;
|
||||
font = s->font;
|
||||
info = (struct sfnt_font_info *) font;
|
||||
|
||||
rasters = alloca (length * sizeof *rasters);
|
||||
|
17
src/sysdep.c
17
src/sysdep.c
@ -2335,7 +2335,8 @@ emacs_backtrace (int backtrace_limit)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_NTGUI
|
||||
#if !defined HAVE_NTGUI && !(defined HAVE_ANDROID \
|
||||
&& !defined ANDROID_STUBIFY)
|
||||
void
|
||||
emacs_abort (void)
|
||||
{
|
||||
@ -2568,6 +2569,20 @@ emacs_close (int fd)
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrapper around fclose. On Android, this calls `android_fclose' to
|
||||
clear information associated with the FILE's file descriptor if
|
||||
necessary. */
|
||||
|
||||
int
|
||||
emacs_fclose (FILE *stream)
|
||||
{
|
||||
#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
|
||||
return fclose (stream);
|
||||
#else
|
||||
return android_fclose (stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Maximum number of bytes to read or write in a single system call.
|
||||
This works around a serious bug in Linux kernels before 2.6.16; see
|
||||
<https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
|
||||
|
10
src/term.c
10
src/term.c
@ -2354,8 +2354,8 @@ A suspended tty may be resumed by calling `resume-tty' on it. */)
|
||||
|
||||
#ifndef MSDOS
|
||||
if (f != t->display_info.tty->output)
|
||||
fclose (t->display_info.tty->output);
|
||||
fclose (f);
|
||||
emacs_fclose (t->display_info.tty->output);
|
||||
emacs_fclose (f);
|
||||
#endif
|
||||
|
||||
t->display_info.tty->input = 0;
|
||||
@ -4632,12 +4632,12 @@ delete_tty (struct terminal *terminal)
|
||||
{
|
||||
delete_keyboard_wait_descriptor (fileno (tty->input));
|
||||
if (tty->input != stdin)
|
||||
fclose (tty->input);
|
||||
emacs_fclose (tty->input);
|
||||
}
|
||||
if (tty->output && tty->output != stdout && tty->output != tty->input)
|
||||
fclose (tty->output);
|
||||
emacs_fclose (tty->output);
|
||||
if (tty->termscript)
|
||||
fclose (tty->termscript);
|
||||
emacs_fclose (tty->termscript);
|
||||
|
||||
xfree (tty->old_tty);
|
||||
xfree (tty->Wcm);
|
||||
|
@ -83,5 +83,5 @@ AM_V_RC = @$(info $ RC $@)
|
||||
|
||||
# These are used for the Android port.
|
||||
AM_V_JAVAC = @$(info $ JAVAC $@)
|
||||
AM_V_DX = @$(info $ DX $@)
|
||||
AM_V_D8 = @$(info $ D8 $@)
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user