Update Android port

* .gitignore: Update with new files.  Do not ignore std*.in.h.
* INSTALL.android: Explain how to build Emacs with external
dependencies.

* Makefile.in (xcompile, cross): Rename to `cross'.
(clean_dirs): Clean cross, not xcompile.

* README: Document new directories.

* build-aux/ndk-build-helper-1.mk (build_kind, NDK_SO_NAMES):
* build-aux/ndk-build-helper-2.mk (build_kind, NDK_SO_NAMES):
* build-aux/ndk-build-helper-3.mk (build_kind):
* build-aux/ndk-build-helper-4.mk:
* build-aux/ndk-build-helper.mk (NDK_BUILD_DIR, my-dir):
* build-aux/ndk-module-extract.awk: New files.
* configure.ac: Set up libgif, libwebp, and libpng for
ndk-build.
* cross/ndk-build/Makefile.in (srcdir, NDK_BUILD_ANDROID_MK):
* cross/ndk-build/ndk-build-executable.mk:
* cross/ndk-build/ndk-build-shared-library.mk (eq, objname):
* cross/ndk-build/ndk-build-static-library.mk (eq, objname):
* cross/ndk-build/ndk-build.in (NDK_BUILD_MODULES):
* cross/ndk-build/ndk-build.mk.in (NDK_BUILD_MODULES)
(NDK_BUILD_SHARED):
* cross/ndk-build/ndk-clear-vars.mk:
* cross/ndk-build/ndk-prebuilt-shared-library.mk:
* cross/ndk-build/ndk-prebuilt-static-library.mk: New files.
* doc/emacs/android.texi (Android, Android Environment):
Document clipboard support on Android.
* doc/emacs/emacs.texi (Top): Update menus.
* etc/MACHINES: Document Android.
* java/AndroidManifest.xml.in: Respect new
`--with-android-debug' option.
* java/Makefile.in (CROSS_BINS, CROSS_LIBS): Adjust for rename.
Include ndk-build.mk.:(emacs.apk-in): Depend on shared
libraries.  Then, package shared libraries.
* java/org/gnu/emacs/EmacsClipboard.java (EmacsClipboard): New
class.
* java/org/gnu/emacs/EmacsFontDriver.java: Update comment to say
this is unused.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
function `sendExpose'.
* java/org/gnu/emacs/EmacsSdk11Clipboard.java
(EmacsSdk11Clipboard):
* java/org/gnu/emacs/EmacsSdk8Clipboard.java
(EmacsSdk8Clipboard): New classes.
* java/org/gnu/emacs/EmacsView.java (EmacsView, handleDirtyBitmap)
(onDetachedFromWindow): When window is reattached, expose the
frame.

* lib/Makefile.in (VPATH):
(ALL_CFLAGS): Adjust for rename.

* lisp/term/android-win.el (android-clipboard-exists-p)
(android-get-clipboard, android-set-clipboard)
(android-clipboard-owner-p, android-primary-selection)
(android-get-clipboard-1, android-get-primary)
(android-selection-bounds, android-encode-select-string)
(gui-backend-get-selection, gui-backend-selection-exists-p)
(gui-backend-selection-owner-p, gui-backend-set-selection): New
functions.

* m4/ndk-build.m4: New file.
* src/Makefile.in (GIF_CFLAGS, ANDROID_LDFLAGS): New variables.
(EMACS_CFLAGS): Add GIF_CFLAGS.  Include
ndk-build.mk.
(libemacs.so): Depend on and link with required
libraries.

* src/android.c (android_check_compressed_file): New function.
(android_open): Work around Android platform bug.
(sendExpose): New function.
(android_readdir): Set d_type if this is a directory.

* src/androidgui.h (enum android_event_type)
(struct android_expose_event, union android_event): Add expose
events.

* src/androidselect.c (struct android_emacs_clipboard)
(android_init_emacs_clipboard, Fandroid_clipboard_owner_p)
(Fandroid_set_clipboard, Fandroid_get_clipboard)
(Fandroid_clipboard_exists_p, init_androidselect)
(syms_of_androidselect): New file.

* src/androidterm.c (handle_one_android_event): Handle
exposures.
* src/androidterm.h: Update prototypes.
* src/emacs.c (android_emacs_init): Initialize androidselect.
This commit is contained in:
Po Lu 2023-01-24 10:34:40 +08:00
parent 9d3aacedf0
commit 4de6b18793
41 changed files with 2406 additions and 71 deletions

64
.gitignore vendored
View file

@ -96,36 +96,40 @@ src/lisp.mk
src/verbose.mk
# Stuff built during cross compilation
xcompile/lib/alloca.h
xcompile/lib/assert.h
xcompile/lib/byteswap.h
xcompile/lib/dirent.h
xcompile/lib/errno.h
xcompile/lib/execinfo.h
xcompile/lib/fcntl.h
xcompile/lib/getopt.h
xcompile/lib/getopt-cdefs.h
xcompile/lib/gmp.h
xcompile/lib/ieee754.h
xcompile/lib/inttypes.h
xcompile/lib/libgnu.a
xcompile/lib/limits.h
xcompile/lib/malloc/*.gl.h
xcompile/lib/signal.h
xcompile/lib/std*.h
xcompile/!lib/std*.in.h
xcompile/!lib/stdio-impl.h
xcompile/lib/string.h
xcompile/lib/sys/
xcompile/lib/time.h
xcompile/lib/unistd.h
xcompile/lib/config.h
xcompile/lib/gnulib.mk
xcompile/src/*
xcompile/lib-src/*
xcompile/sys/*
xcompile/config.status
xcompile/*.bak
cross/lib/alloca.h
cross/lib/assert.h
cross/lib/byteswap.h
cross/lib/dirent.h
cross/lib/errno.h
cross/lib/execinfo.h
cross/lib/fcntl.h
cross/lib/getopt.h
cross/lib/getopt-cdefs.h
cross/lib/gmp.h
cross/lib/ieee754.h
cross/lib/inttypes.h
cross/lib/libgnu.a
cross/lib/limits.h
cross/lib/malloc/*.gl.h
cross/lib/signal.h
cross/lib/std*.h
!cross/lib/std*.in.h
!cross/lib/stdio-impl.h
cross/lib/string.h
cross/lib/sys/
cross/lib/time.h
cross/lib/unistd.h
cross/lib/config.h
cross/lib/gnulib.mk
cross/src/*
cross/lib-src/*
cross/sys/*
cross/config.status
cross/*.bak
cross/ndk-build/Makefile
cross/ndk-build/ndk-build.mk
cross/ndk-build/*.o
# Lisp-level sources built by 'make'.
*cus-load.el

View file

@ -62,7 +62,7 @@ medium) and installed on-device.
BUILDING WITH OLD NDK VERSIONS
Building Emacs with an old version of the Android NDK requires special
setup. This is because there is no separate C compiler binary for
setup. This is because there is no separate C compiler binary for
each version of Android in those versions of the NDK.
Before running `configure', you must identify three variables:
@ -94,7 +94,339 @@ Emacs is known to build for Android 2.2 (API version 8) or later, and
run on Android 2.3 or later. It is supposed to run on Android 2.2 as
well.
DEBUG AND RELEASE BUILDS
Android makes a distinction between ``debug'' and ``release'' builds
of applications. With ``release'' builds, the system will apply
stronger optimizations to the application at the cost of being unable
to debug them with the steps in etc/DEBUG.
Emacs is built as a debuggable package by default, but:
./configure --without-android-debug
will create a release build of Emacs instead. This may be useful when
running Emacs on resource constrained machines.
If you are building an Emacs package for redistribution, we urge you
to provide both debug and release versions.
BUILDING WITH THIRD PARTY LIBRARIES
The Android NDK does not support the usual ways of locating third
party libraries, especially not via `pkg-config'. Instead, it uses
its own system called `ndk-build'. The one exception to this rule is
zlib, which is considered a part of the Android OS itself and is
available on all devices running Android.
Android also requires that each application include its own
dependencies, as the system makes no guarantee about the existence of
any particular library.
Emacs is not built with the `ndk-build' system. Instead, it is built
with Autoconf and Make.
However, it supports building and including dependencies which use the
similarly Make-based `ndk-build' system.
To use dependencies built through `ndk-build', you must specify a list
of directories within which Emacs will search for ``Android.mk''
files, like so:
./configure "--with-ndk-path=directory1 directory2"
Emacs will then read the ``Android.mk'' file in each directory, and
automatically build and use those modules.
Google, Inc. has adapted many common Emacs dependencies to use the
`ndk-build' system. Here is a non-exhaustive list of what is known to
work:
libpng - https://android.googlesource.com/platform/external/libpng
libwebp - https://android.googlesource.com/platform/external/webp
giflib - https://android.googlesource.com/platform/external/giflib
(You must add LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH) before
its Android.mk includes $(BUILD_STATIC_LIBRARY))
We anticipate that most untested non-trivial ndk-build dependencies
will need adjustments in Emacs to work, as the Emacs build system
which emulates ndk-build is in an extremely early state.
NDK BUILD SYSTEM IMPLEMENTATION
Emacs implements ndk-build itself, because the version that comes with
the Android NDK is not easy to use from another Makefile, and keeps
accumulating incompatible changes.
The Emacs implementation of ndk-build consists of one m4 file:
m4/ndk-build.m4
four Makefiles in build-aux, run during configure:
build-aux/ndk-build-helper-1.mk
build-aux/ndk-build-helper-2.mk
build-aux/ndk-build-helper-3.mk
build-aux/ndk-build-helper.mk
one awk script in build-awx, run during configure:
build-aux/ndk-module-extract.awk
six Makefiles in cross/ndk-build,
cross/ndk-build/ndk-build-shared-library.mk
cross/ndk-build/ndk-build-static-library.mk
cross/ndk-build/ndk-build-executable.mk
cross/ndk-build/ndk-clear-vars.mk
cross/ndk-build/ndk-prebuilt-shared-library.mk
cross/ndk-build/ndk-prebuilt-static-library.mk
and finally, two more Makefiles in cross/ndk-build, generated by
configure:
cross/ndk-build/Makefile (generated from cross/ndk-build/Makefile.in)
cross/ndk-build/ndk-build.mk (generated from cross/ndk-build/ndk-build.mk.in)
m4/ndk-build.m4 is a collection of macros which are used by the
configure script to set up the ndk-build system, look for modules, add
the appropriate options to LIBS and CFLAGS, and generate the Makefiles
necessary to build the rest of Emacs.
Immediately after determining the list of directories in which to look
for ``Android.mk'' files, the version and type of Android system being
built for, configure calls:
ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build])
This expands to a sequence of shell script that enumerates all of the
Android.mk files specified in "$with_ndk_path", sets up some shell
functions used by the rest of the ndk-build code run by the configure
script, and teaches the ndk-build system that the Makefiles to be
generated are found in the directory "cross/ndk-build/Makefile".
When configure is cross-compiling for Android, the macro
EMACS_CHECK_MODULES will expand to the macro ndk_CHECK_MODULES,
instead of pkg-config.m4's PKG_CHECK_MODULES. Thus, the following
code:
EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0])
will actually expand to:
ndk_CHECK_MODULES([PNG], [libpng >= 1.0.0], [HAVE_PNG=yes],
[HAVE_PNG=no])
which in turn expands to a sequence shell script that first invokes:
make -f build-aux/ndk-build-helper.mk
for each ``Android.mk'' file found by ndk_INIT, with the following
variables given to Make:
EMACS_SRCDIR=. # the source directory (in which configure is running)
EMACS_ABI=$ndk_ABI # this is the $android_abi given to ndk_INIT
ANDROID_MAKEFILE="/opt/android/libpng/Android.mk"
ANDROID_MODULE_DIRECTORY="/opt/android/libpng"
NDK_BUILD_DIR="$ndk_DIR" # this is the directory given as to ndk_INIT
build-aux/ndk-build-helper.mk will then evaluate the contents
$(ANDROID_MAKEFILE), the ``Android.mk'' file, for the first time. The
purpose of this evaluation is to establish a list of packages (or
modules) provided by the ``Android.mk'' file, and the corresponding
Makefile targets and compiler and linker flags required to build and
link to those tagets.
Before doing so, build-aux/ndk-build-helper.mk will define several
variables and functions required by all ``Android.mk'' files. The
most important of these are:
my-dir # the directory containing the Android.mk file.
BUILD_SHARED_LIBRARY # build-aux/ndk-build-helper-1.mk
BUILD_STATIC_LIBRARY # build-aux/ndk-build-helper-2.mk
BUILD_EXECUTABLE # build-aux/ndk-build-helper-3.mk
CLEAR_VARS # build-aux/ndk-build-helper-4.mk
Then, ``Android.mk'' will include $(CLEAN_VARS) (to clear variables
previously set), set several variables describing each module to the
ndk-build system, and include one of $(BUILD_SHARED_LIBRARY),
$(BUILD_STATIC_LIBRARY) and $(BUILD_EXECUTABLE).
Each one of those three scripts will then read from the variables set
by ``Android.mk'', resolve dependencies, and print out some text
describing the module to Emacs. For example, the shared library
module "libpng" results in the following text being printed:
Building shared
libpng
/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c
-I/opt/android/libpng
-L/opt/emacs/cross/ndk-build -l:libpng_emacs.so
libpng_emacs.so
End
The output is arranged as follows:
- The first line consists of the word ``Building'', followed by
either ``shared'', ``static'', or ``executable'', depending on
what type of module being built.
- The second line consists of the name of the module currently being
built.
- The third line consists of all of the source code files comprising
the module.
- The fourth line consists of the text that has to be added to
CFLAGS in order to find the includes associated with the module.
- The fifth line consists of the text that has to be added to LIBS
in order to link with this module and all of its dependencies.
- The sixth line consists of the Make targets (more on this later)
that will build the final shared object or library archive of this
module, along with all of its dependencies.
The output from Make is given to an awk script,
build-aux/ndk-module-extract.awk. This is responsible for parsing the
that output and filtering out modules other than what is being built:
awk -f build-aux/ndk-module-extract.awk MODULE=libpng
eventually generating this section of shell script:
module_name=libpng
module_kind=shared
module_src="/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c"
module_includes="-I/opt/android/libpng"
module_cflags=""
module_ldflags=" -L/opt/emacs/cross/ndk-build -l:libpng_emacs.so"
module_target="libpng_emacs.so"
which is then evaluated by `configure'. Once the variable
`module_name' is set, configure apends the remaining
$(module_includes), $(module_cflags) and $(module_ldflags) to the
module's CFLAGS and LIBS variables, and appends the list of Makefile
targets specified to the variable NDK_BUILD_MODULES.
Finally, immediately before generating src/Makefile.android, configure
expands:
ndk_CONFIG_FILES
to generate $ndk_DIR/Makefile and $ndk_DIR/ndk-build.mk.
Now, the $ndk_DIR directory is set up to build all modules upon which
depends, and $ndk_DIR/ndk-build.mk includes a list of files required
to link Emacs, along with the rules to chdir into $ndk_DIR in order to
build them.
$ndk_DIR/ndk-build.mk is included by cross/src/Makefile
(Makefile.android) and java/Makefile. It defines three different
variables:
NDK_BUILD_MODULES the file names of all modules to be built.
NDK_BUILD_STATIC absolute names of all library archives
to be built.
NDK_BUILD_SHARED absolute names of all shared libraries to
be built.
and then proceeds to define rules to build each of the modules in
$(NDK_BUILD_MODULES).
cross/src/Makefile arranges to have all dependencies of Emacs not
already built built before linking ``libemacs.so'' with them.
java/Makefile additionally arranges to have all shared object
dependencies built before the application package is built, which is
normally redundant because they should have already been built before
linking ``libemacs.so''.
Building the modules is performed through $ndk_DIR/Makefile, which
contains the actual implementation of the ``ndk-build'' build system.
First, it defines certain variables constant within the ``ndk-build''
build system, such as the files included by ``Android.mk'' to build
shared or static libraries, and CLEAR_VARS. The most important of
these are:
CLEAR_VARS cross/ndk-build/ndk-clear-vars.mk
BUILD_EXECUTABLE cross/ndk-build/ndk-build-executable.mk
BUILD_SHARED_LIBRARY cross/ndk-build/ndk-build-shared-library.mk
BUILD_STATIC_LIBRARY cross/ndk-build/ndk-build-static-library.mk
PREBUILT_SHARED_LIBRARY cross/ndk-build/ndk-prebuilt-shared-library.mk
PREBUILT_STATIC_LIBRARY cross/ndk-build/ndk-prebuilt-static-library.mk
Then, it loads each Emacs dependency's ``Android.mk'' file. For each
module defined there, ``Android.mk'' includes $(CLEAR_VARS) to unset
all variables specific to each module, and then includes
$(BUILD_SHARED_LIBRARY) or $(BUILD_STATIC_LIBRARY) for each shared or
static library module.
This results in cross/ndk-build/ndk-build-shared-library.mk or
cross/ndk-build/ndk-build-static-library being included, just like the
Makefiles in build-aux were inside the configure script.
Each one of those two scripts then defines rules to build all of the
object files associated with the module, and then link or archive
them. The name under which the module is linked is the same as the
Make target found on the sixth line of output from
build-aux/ndk-build-helper.mk.
However, none of the Makefiles in
cross/ndk-build/ndk-build-shared-library.mk perform any kind of
dependency resolution! Instead, they only define rules to build
individual modules, leaving dependency resolution up to the Makefiles
in the `build-aux' directory.
libpng is a very simple module, providing only a single shared object
module. This module is named libpng_emacs.so and is eventually built
and packaged into the library directory of the Emacs application
package. Now, let us look at a more complex module, libwebp:
When built with libwebp, Emacs depends on a single library,
libwebpdemux. This library is named ``libwebpdemux'' on Unix systems,
and that is the name by which it is found with pkg-config.
However, the library's module is only named ``webpdemux'' on Android.
When ndk_CHECK_MODULES begins to look for a module, it first tries to
see if its name is found in the variable `ndk_package_map', which was
set inside ndk_INIT. In this case, it finds the following word:
libwebpdemux:webpdemux
and immediately replaces ``libwebpdemux'' with ``webpdemux''.
Then, it locates the ``Android.mk'' file containing a static library
module named webpdemux and gives the output from
build-aux/ndk-build-helper.mk to the awk script, resulting in:
module_name=webpdemux
module_kind=static
module_src="/opt/android/webp/src/demux/anim_decode.c /opt/android/webp/src/demux/demux.c"
module_includes="-I/opt/android/webp/src"
module_cflags=""
module_ldflags=" cross/ndk-build/libwebpdemux.a cross/ndk-build/libwebp.a cross/ndk-build/libwebpdecoder_static.a "
module_target="libwebpdemux.a libwebp.a libwebpdecoder_static.a"
The attentive reader will notice that in addition to the
``libwebpdemux.a'' archive associated with the ``webpdemux'' library,
Emacs has been made to link with two additional libraries. This is
because the ``webpdemux'' module specifies a dependency on the
``webp'' module (defined in the same Android.mk).
build-aux/ndk-build-helper.mk resolved that dependency, noticing that
it in turn specified another dependency on ``webpdecoder_static'',
which in turn was added to the linker command line and list of targets
to build.
As a result, all three dependencies will be built and linked to Emacs,
instead of just the single ``webpdemux'' dependency that was
specified.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify

View file

@ -539,7 +539,7 @@ lib lib-src lisp nt: Makefile
java: lisp info
$(MAKE) -C $@ all
xcompile: src
cross: src
$(MAKE) -C $@ all
trampolines: src lisp
@ -1012,7 +1012,7 @@ mostlyclean: $(mostlyclean_dirs:=_mostlyclean)
### with them.
###
### Delete '.dvi' files here if they are not part of the distribution.
clean_dirs = $(mostlyclean_dirs) java xcompile nextstep admin/charsets \
clean_dirs = $(mostlyclean_dirs) java cross nextstep admin/charsets \
admin/unidata
$(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean)))

3
README
View file

@ -95,6 +95,9 @@ There are several subdirectories:
'admin' holds files used by Emacs developers, and Unicode data files.
'build-aux' holds auxiliary files used during the build.
'm4' holds Autoconf macros used for generating the configure script.
'java' holds the Java code for the Emacs port to Android.
'cross' holds Makefiles and an additional copy of gnulib used to build
Emacs for Android devices.
Building Emacs on non-Posix platforms requires tools that aren't part
of the standard distribution of the OS. The platform-specific README

View file

@ -0,0 +1,92 @@
# ndk-build-helper-1.mk -- Helper for ndk-build.m4.
# 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/>.
# Print out information now defined. Important details include:
# - list of source files to compile.
# - module export include directories.
# - module export CFLAGS.
# - module export LDFLAGS.
# - module name.
build_kind = shared
NDK_SO_NAMES =
NDK_A_NAMES =
# Record this module's dependencies. This information is used later
# on to recurse over libraries.
NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES)
$(info Building $(build_kind))
$(info $(LOCAL_MODULE))
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)?,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir)))
$(info $(LOCAL_EXPORT_CFLAGS))
ifeq ($(LOCAL_MODULE_FILENAME),)
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
NDK_SO_NAMES = $(LOCAL_MODULE)_emacs.so
else
NDK_SO_NAMES = lib$(LOCAL_MODULE)_emacs.so
endif
else
NDK_SO_NAMES = $(LOCAL_MODULE_FILENAME).so
endif
define add-a-name
ifeq ($(findstring lib,$(1)),lib)
NDK_A_NAME = $(1).a
else
NDK_A_NAME = lib$(1).a
endif
ifeq ($$(NDK_A_NAMES:$$(NDK_A_NAME)=),$$(NDK_A_NAMES))
NDK_A_NAMES := $$(NDK_A_NAMES) $$(NDK_A_NAME)
# Now recurse over this module's dependencies.
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
endif
endef
define add-so-name
ifeq ($(findstring lib,$(1)),lib)
NDK_SO_NAME = $(1)_emacs.so
else
NDK_SO_NAME = lib$(1)_emacs.so
endif
ifeq ($$(NDK_SO_NAMES:$$(NDK_SO_NAME)=),$$(NDK_SO_NAMES))
NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME)
# Now recurse over this module's dependencies.
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
endif
endef
# Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and
# LOCAL_SHARED_LIBRARIES.
SYSTEM_LIBRARIES = z libz libc c
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module))))
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module))))
$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname)))
$(info $(NDK_SO_NAMES))
$(info End)

View file

@ -0,0 +1,87 @@
# ndk-build-helper-2.mk -- Helper for ndk-build.m4.
# 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/>.
# Say a static library is being built
build_kind = static
NDK_SO_NAMES =
NDK_A_NAMES =
# Record this module's dependencies. This information is used later
# on to recurse over libraries.
NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES)
$(info Building $(build_kind))
$(info $(LOCAL_MODULE))
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)/,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir)))
$(info $(LOCAL_EXPORT_CFLAGS))
ifeq ($(LOCAL_MODULE_FILENAME),)
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
NDK_A_NAMES = $(LOCAL_MODULE).a
else
NDK_A_NAMES = lib$(LOCAL_MODULE).a
endif
else
NDK_A_NAMES = $(LOCAL_MODULE_FILENAME).a
endif
define add-a-name
ifeq ($(findstring lib,$(1)),lib)
NDK_A_NAME = $(1).a
else
NDK_A_NAME = lib$(1).a
endif
ifeq ($$(NDK_A_NAMES:$$(NDK_A_NAME)=),$$(NDK_A_NAMES))
NDK_A_NAMES := $$(NDK_A_NAMES) $$(NDK_A_NAME)
# Now recurse over this module's dependencies.
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
endif
endef
define add-so-name
ifeq ($(findstring lib,$(1)),lib)
NDK_SO_NAME = $(1)_emacs.so
else
NDK_SO_NAME = lib$(1)_emacs.so
endif
ifeq ($$(NDK_SO_NAMES:$$(NDK_SO_NAME)=),$$(NDK_SO_NAMES))
NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME)
# Now recurse over this module's dependencies.
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module))))
$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module))))
endif
endef
# Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and
# LOCAL_SHARED_LIBRARIES.
SYSTEM_LIBRARIES = z libz
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module))))
$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module))))
$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) $(and $(NDK_SO_NAMES), -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname))))
$(info $(NDK_A_NAMES))
$(info End)

View file

@ -0,0 +1,28 @@
# ndk-build-helper-3.mk -- Helper for ndk-build.m4.
# 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/>.
# Say a static library is being built
build_kind = executable
$(info Building $(build_kind))
$(info $(LOCAL_MODULE))
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY),$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir)))
$(info $(LOCAL_EXPORT_CFLAGS))
$(info $(LOCAL_EXPORT_LDFLAGS))
$(info End)

View file

@ -0,0 +1,38 @@
# 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/>.
undefine LOCAL_MODULE
undefine LOCAL_MODULE_FILENAME
undefine LOCAL_SRC_FILES
undefine LOCAL_CPP_EXTENSION
undefine LOCAL_CPP_FEATURES
undefine LOCAL_C_INCLUDES
undefine LOCAL_CFLAGS
undefine LOCAL_CPPFLAGS
undefine LOCAL_STATIC_LIBRARIES
undefine LOCAL_SHARED_LIBRARIES
undefine LOCAL_WHOLE_STATIC_LIBRARIES
undefine LOCAL_LDLIBS
undefine LOCAL_LDFLAGS
undefine LOCAL_ALLOW_UNDEFINED_SYMBOLS
undefine LOCAL_ARM_MODE
undefine LOCAL_ARM_NEON
undefine LOCAL_DISABLE_FORMAT_STRING_CHECKS
undefine LOCAL_EXPORT_CFLAGS
undefine LOCAL_EXPORT_CPPFLAGS
undefine LOCAL_EXPORT_C_INCLUDES
undefine LOCAL_EXPORT_LDFLAGS
undefine LOCAL_EXPORT_LDLIBS

View file

@ -0,0 +1,52 @@
# ndk-build-helper.mk -- Helper for ndk-build.m4.
# 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/>.
# This Makefile sets up enough to parse an Android-style Android.mk
# file and return useful information about its contents.
# See the text under ``NDK BUILD SYSTEM IMPLEMENTATION'' in
# INSTALL.android for more details.
# Make NDK_BUILD_DIR absolute.
NDK_BUILD_DIR := $(absname $(NDK_BUILD_DIR))
# my-dir is a function that returns the Android module directory.
my-dir = $(ANDROID_MODULE_DIRECTORY)
# all-subdir-makefiles is a function which returns all Android.mk
# files within this directory.
all-subdir-makefiles = $(shell find . -name "Android.mk")
# These functions are not implemented.
parent-makefile =
grand-parent-makefile =
import-module =
# Print out module information every time BUILD_SHARED_LIBRARY is
# called.
BUILD_SHARED_LIBRARY=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-1.mk
BUILD_STATIC_LIBRARY=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-2.mk
BUILD_EXECUTABLE=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-3.mk
CLEAR_VARS=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-4.mk
# Now include Android.mk.
include $(ANDROID_MAKEFILE)
# Dummy target.
all:

View file

@ -0,0 +1,64 @@
/^Building.+$/ {
kind = $2
}
// {
if (!match ($0, /^End$/) && !match ($0, /^Building.+$/))
{
if (kind)
{
if (ldflags_found)
target = $0
else if (cflags_found)
{
ldflags = $0
ldflags_found = 1
}
else if (includes_found)
{
cflags = $0
cflags_found = 1
}
else if (src_found)
{
includes = $0
includes_found = 1
}
else if (name_found)
{
src = $0
src_found = 1;
}
else
{
name = $0
name_found = 1
}
}
}
}
/^End$/ {
if (name == MODULE && (kind == "shared" || kind == "static"))
{
printf "module_name=%s\n", name
printf "module_kind=%s\n", kind
printf "module_src=\"%s\"\n", src
printf "module_includes=\"%s\"\n", includes
printf "module_cflags=\"%s\"\n", cflags
printf "module_ldflags=\"%s\"\n", ldflags
printf "module_target=\"%s\"\n", target
}
src = ""
name = ""
kind = ""
includes = ""
cflags = ""
ldflags = ""
name_found = ""
src_found = ""
includes_found = ""
cflags_found = ""
ldflags_found = ""
}

View file

@ -166,6 +166,13 @@ fi
AC_CANONICAL_HOST
AC_CANONICAL_BUILD
if test "$XCONFIGURE" = "android"; then
# Initialize the Android NDK build system. Make sure to use the
# passed through NDK path.
with_ndk_path="$android_ndk_path"
ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build])
fi
case $host in
*-mingw*)
@ -544,6 +551,7 @@ OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-b
OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input])
OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary])
OPTION_DEFAULT_OFF([android],[cross-compile Android application package])
OPTION_DEFAULT_ON([android-debug],[don't build Emacs as a debug package on Android])
AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
[use a file notification library (LIB one of: yes, inotify, kqueue, gfile, w32, no)])],
@ -1033,8 +1041,14 @@ package will likely install on older systems but crash on startup.])
mv -f confdefs.h _confdefs.h
mv -f config.log _config.log
# Figure out what --with-FOO options to pass through.
passthrough="$passthrough --with-png=$with_png"
passthrough="$passthrough --with-webp=$with_webp"
passthrough="$passthrough --with-gif=$with_gif"
AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \
ANDROID_SDK="$android_sdk" $0], [],
ANDROID_SDK="$android_sdk" android_abi=$android_abi \
android_ndk_path="$with_ndk_path" $0 $passthrough], [],
[AC_MSG_ERROR([Failed to cross-configure Emacs for android.])])
# Now set ANDROID to yes.
@ -1048,6 +1062,14 @@ package will likely install on older systems but crash on startup.])
AC_MSG_NOTICE([Generating src/config.h.android])
mv -f src/config.h src/config.h.android
# Tell AndroidManifest.xml whether or not Emacs should be built
# debug.
ANDROID_DEBUGGABLE=false
if test "$with_android_debug" = "yes"; then
ANDROID_DEBUGGABLE=true
fi
AC_SUBST([ANDROID_DEBUGGABLE])
# Move confdefs.h back now that the recursive call to configure is
# complete.
mv -f _confdefs.h confdefs.h
@ -1083,15 +1105,21 @@ if test "$ANDROID" = "yes"; then
with_xpm=no
with_jpeg=no
with_tiff=no
with_gif=no
with_png=no
# Some of these dependencies are now supported within Android, so
# they can be enabled.
if test "$XCONFIGURE" != "android"; then
with_png=no
with_webp=no
with_gif=no
fi
with_xml2=no
with_rsvg=no
with_webp=no
with_sqlite3=no
with_lcms2=no
with_libsystemd=no
with_cairo=no
with_xml2=no
with_imagemagick=no
with_json=no
with_tree_sitter=no
@ -2218,10 +2246,13 @@ dnl EMACS_CHECK_MODULES accepts optional 3rd and 4th arguments that
dnl can take the place of the default HAVE_GSTUFF=yes and HAVE_GSTUFF=no
dnl actions.
AC_DEFUN([EMACS_CHECK_MODULES],
[PKG_CHECK_MODULES([$1], [$2],
[$1_CFLAGS=`AS_ECHO(["$$1_CFLAGS"]) | sed -e "$edit_cflags"`
m4_default([$3], [HAVE_$1=yes])],
[m4_default([$4], [HAVE_$1=no])])])
[AS_IF([test -n "$ndk_INITIALIZED"],
[ndk_CHECK_MODULES([$1], [$2], m4_default([$3], [HAVE_$1=yes]),
m4_default([$4],[HAVE_$1=no]))],
[PKG_CHECK_MODULES([$1], [$2],
[$1_CFLAGS=`AS_ECHO(["$$1_CFLAGS"]) | sed -e "$edit_cflags"`
m4_default([$3], [HAVE_$1=yes])],
[m4_default([$4], [HAVE_$1=no])])])])
HAVE_SOUND=no
if test "${with_sound}" != "no"; then
@ -2394,6 +2425,7 @@ window_system=none
ANDROID_OBJ=
ANDROID_LIBS=
ANDROID_CFLAGS=
REALLY_ANDROID=
CM_OBJ="cm.o"
if test "${ANDROID}" = "yes"; then
@ -2423,18 +2455,31 @@ for Android, but all API calls need to be stubbed out])
# Link with libraries required for Android support.
ANDROID_LIBS="-landroid -llog -ljnigraphics"
# This is required to make the system load emacs.apk's libpng
# (among others) instead of the system's own. But it doesn't work
# on all Android versions yet, so for now just suffix shared
# libraries with _emacs.
# ANDROID_LDFLAGS="-Wl,-rpath,'\$\$ORIGIN'"
# Link with the sfnt font library and sfntfont.o, along with
# sfntfont-android.o.
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
# Build androidselect.o.
ANDROID_OBJ="$ANDROID_OBJ androidselect.o"
# Check for some functions not always present in the NDK.
AC_CHECK_DECLS([android_get_device_api_level])
# Say this build is really for Android.
REALLY_ANDROID=yes
fi
fi
AC_SUBST(ANDROID)
AC_SUBST(ANDROID_OBJ)
AC_SUBST(ANDROID_LIBS)
AC_SUBST(ANDROID_LDFLAGS)
AC_SUBST(ANDROID_CFLAGS)
if test "${with_pgtk}" = "yes"; then
@ -3265,7 +3310,8 @@ HAVE_WEBP=no
if test "${with_webp}" != "no"; then
if test "${HAVE_X11}" = "yes" || test "${opsys}" = "mingw32" \
|| test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
|| test "${HAVE_BE_APP}" = "yes" || test "${HAVE_PGTK}" = "yes"; then
|| test "${HAVE_BE_APP}" = "yes" || test "${HAVE_PGTK}" = "yes" \
|| test "${REALLY_ANDROID}" = "yes"; then
WEBP_REQUIRED=0.6.0
WEBP_MODULE="libwebpdemux >= $WEBP_REQUIRED"
@ -4506,7 +4552,8 @@ HAVE_JPEG=no
LIBJPEG=
if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
|| test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes" \
|| test "$window_system" = "pgtk"; then
|| test "$window_system" = "pgtk" \
|| test "${REALLY_ANDROID}" = "yes"; then
if test "${with_jpeg}" != "no"; then
AC_CACHE_CHECK([for jpeglib 6b or later],
[emacs_cv_jpeglib],
@ -4852,7 +4899,8 @@ if test "${with_png}" != no; then
AC_CHECK_HEADER([png.h], [HAVE_PNG=yes])
elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
|| test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes" \
|| test "$window_system" = "pgtk"; then
|| test "$window_system" = "pgtk" \
|| test "${REALLY_ANDROID}" = "yes"; then
EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0])
if test $HAVE_PNG = yes; then
LIBPNG=$PNG_LIBS
@ -4951,6 +4999,7 @@ AC_SUBST([LIBTIFF])
### Use -lgif or -lungif if available, unless '--with-gif=no'.
### mingw32 doesn't use -lgif/-lungif, since it loads the library dynamically.
HAVE_GIF=no
GIF_CFLAGS=
LIBGIF=
if test "${opsys}" = "mingw32"; then
if test "${with_gif}" != "no"; then
@ -4963,6 +5012,7 @@ if test "${opsys}" = "mingw32"; then
elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \
|| test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \
|| test "${HAVE_BE_APP}" = "yes" || test "$window_system" = "pgtk" \
|| test "${REALLY_ANDROID}" = "yes" \
&& test "${with_gif}" != "no"; then
AC_CHECK_HEADER([gif_lib.h],
# EGifPutExtensionLast only exists from version libungif-4.1.0b1.
@ -4982,12 +5032,20 @@ elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \
test "$HAVE_GIF" = yes && LIBGIF=-lungif
fi
# Finally, try ndk-build on Android.
if test "$REALLY_ANDROID" = "yes"; then
ndk_SEARCH_MODULE([libgif], [GIF], [HAVE_GIF=yes],
[HAVE_GIF=no])
test "$HAVE_GIF" = yes && LIBGIF="$GIF_LIBS"
fi
if test "${HAVE_GIF}" = "yes"; then
AC_DEFINE([HAVE_GIF], [1],
[Define to 1 if you have a gif (or ungif) library.])
fi
fi
AC_SUBST([LIBGIF])
AC_SUBST([GIF_CFLAGS])
dnl Check for required libraries.
MISSING=
@ -7291,7 +7349,7 @@ if test "$ANDROID" = "yes"; then
fi
if test "$XCOMPILE" = "yes"; then
SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES xcompile/Makefile"
SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES cross/Makefile"
fi
dnl The admin/ directory used to be excluded from tarfiles.
@ -7377,11 +7435,15 @@ fi
# Make java/Makefile
ARCH_INDEPENDENT_CONFIG_FILES([java/Makefile])
ARCH_INDEPENDENT_CONFIG_FILES([xcompile/Makefile])
ARCH_INDEPENDENT_CONFIG_FILES([cross/Makefile])
# Make java/AndroidManifest.xml
ARCH_INDEPENDENT_CONFIG_FILES([java/AndroidManifest.xml])
# Make ndk-build Makefiles. This is only done inside the recursive
# configure.
ndk_CONFIG_FILES
AC_OUTPUT
if test ! "$with_mailutils"; then

115
cross/ndk-build/Makefile.in Normal file
View file

@ -0,0 +1,115 @@
### @configure_input@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
srcdir = @srcdir@
# This is a list of Android.mk files which provide targets.
NDK_BUILD_ANDROID_MK = @NDK_BUILD_ANDROID_MK@
NDK_BUILD_ARCH = @NDK_BUILD_ARCH@
NDK_BUILD_ABI = @NDK_BUILD_ABI@
NDK_BUILD_SDK = @NDK_BUILD_SDK@
NDK_BUILD_CC = @NDK_BUILD_CC@
NDK_BUILD_AR = @NDK_BUILD_AR@
# This is a list of targets to build.
NDK_BUILD_MODULES = @NDK_BUILD_MODULES@
# This is set by the Android in tree build system and is used by some
# libraries to look for the NDK. Its value is unimportant.
NDK_ROOT = /tmp/
# Finally, here are rules common to Emacs.
.PHONY: all
all: $(NDK_BUILD_MODULES)
define uniqify
$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1)))
endef
# Remove duplicate files.
NDK_BUILD_ANDROID_MK := $(call uniqify,$(NDK_BUILD_ANDROID_MK))
define subr-1
# Define ndk-build functions.
define my-dir
$(dir $(abspath $(1)))
endef
# NDK-defined include variables.
CLEAR_VARS = $(srcdir)/ndk-clear-vars.mk
BUILD_EXECUTABLE = $(srcdir)/ndk-build-executable.mk
BUILD_SHARED_LIBRARY = $(srcdir)/ndk-build-shared-library.mk
BUILD_STATIC_LIBRARY = $(srcdir)/ndk-build-static-library.mk
PREBUILT_SHARED_LIBRARY = $(srcdir)/ndk-prebuilt-shared-library.mk
PREBUILT_STATIC_LIBRARY = $(srcdir)/ndk-prebuilt-static-library.mk
# Target information variables.
TARGET_ARCH = $(NDK_BUILD_ARCH)
TARGET_PLATFORM = android-$(NDK_BUILD_SDK)
TARGET_ARCH_ABI = $(NDK_BUILD_ABI)
TARGET_ABI = $(TARGET_PLATFORM)-$(TARGET_ABI)
# Module description variables. These are defined by Android.mk.
LOCAL_PATH :=
LOCAL_MODULE :=
LOCAL_MODULE_FILENAME :=
LOCAL_SRC_FILES :=
LOCAL_CPP_EXTENSION :=
LOCAL_CPP_FEATURES :=
LOCAL_C_INCLUDES :=
LOCAL_CFLAGS :=
LOCAL_CPPFLAGS :=
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
LOCAL_WHOLE_STATIC_LIBRARIES :=
LOCAL_LDLIBS :=
LOCAL_LDFLAGS :=
LOCAL_ALLOW_UNDEFINED_SYMBOLS :=
LOCAL_ARM_MODE :=
LOCAL_ARM_NEON :=
LOCAL_DISABLE_FORMAT_STRING_CHECKS :=
LOCAL_EXPORT_CFLAGS :=
LOCAL_EXPORT_CPPFLAGS :=
LOCAL_EXPORT_C_INCLUDES :=
LOCAL_EXPORT_LDFLAGS :=
LOCAL_EXPORT_LDLIBS :=
# Now load Android.mk.
include $(1)
endef
# Now define rules for each Android.mk file.
$(foreach android_mk,$(NDK_BUILD_ANDROID_MK),$(eval $(call subr-1,$(android_mk))))
.PHONY: clean mostlyclean
clean mostlyclean:
rm -rf *.o *.so *.a
.PHONY: extraclean dist-clean maintainer-clean
extraclean dist-clean maintainer-clean:
rm -rf Makefile

View file

@ -0,0 +1,22 @@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
# Building executables is not supported

View file

@ -0,0 +1,83 @@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))
objname = $(1)-$(subst /,_,$(2).o)
define single-object-target
ifeq (x$(suffix $(1)),x.c)
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1)
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE))
else
ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),)
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1)
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE))
else
$$(error Unsupported suffix: $(suffix $(1)))
endif
endif
ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1)))
endef
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES)))
NDK_CFLAGS_$(LOCAL_MODULE) ::= -fPIC -iquote $(LOCAL_EXPORT_CFLAGS) $(LOCAL_PATH) $(LOCAL_CFLAGS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS)
ALL_OBJECT_FILES_$(LOCAL_MODULE) :=
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
NDK_CFLAGS ::= -marm
else
ifeq ($(NDK_BUILD_ARCH),arm)
NDK_CFLAGS ::= -mthumb
endif
endif
LOCAL_MODULE_FILENAME := $(strip $(LOCAL_MODULE_FILENAME))
ifndef LOCAL_MODULE_FILENAME
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE)_emacs
else
LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE)_emacs
endif
endif
# Since a shared library is being built, suffix the library with
# _emacs. Otherwise, libraries already on the system will be found
# first, with potentially nasty consequences.
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).so
# Then define rules to build all objects.
ALL_SOURCE_FILES = $(LOCAL_SRC_FILES)
$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source))))
# Now define the rule to build the shared library.
$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE))
$(NDK_BUILD_CC) $^ -o $@ -shared $(NDK_LDFLAGS$(LOCAL_MODULE))

View file

@ -0,0 +1,83 @@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))
objname = $(1)-$(subst /,_,$(2).o)
define single-object-target
ifeq (x$(suffix $(1)),x.c)
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1)
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE))
else
ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),)
$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1)
$(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE))
else
$$(error Unsupported suffix: $(suffix $(1)))
endif
endif
ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1)))
endef
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES)))
NDK_CFLAGS_$(LOCAL_MODULE) ::= -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH))
NDK_ASFLAGS_$(LOCAL_MODULE) ::= $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH))
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS)
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
NDK_CFLAGS ::= -marm
else
ifeq ($(NDK_BUILD_ARCH),arm)
NDK_CFLAGS ::= -mthumb
endif
endif
LOCAL_MODULE_FILENAME := $(strip $(LOCAL_MODULE_FILENAME))
ifndef LOCAL_MODULE_FILENAME
ifeq ($(findstring lib,$(LOCAL_MODULE)),lib)
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE)
else
LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE)
endif
endif
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).a
# Then define rules to build all objects.
ALL_SOURCE_FILES = $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH))
# This defines all dependencies.
ALL_OBJECT_FILES$(LOCAL_MODULE) =
$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source))))
# Now define the rule to build the library.
$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE))
$(NDK_BUILD_AR) r $@ $^

View file

@ -0,0 +1,44 @@
### @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/>.
# This file is included all over the place to build prerequisites.
NDK_BUILD_MODULES = @NDK_BUILD_MODULES@
NDK_BUILD_SHARED =
NDK_BUILD_STATIC =
define subr-1
.PHONY $(top_builddir)/cross/ndk-build/$(0)
$(top_builddir)/cross/ndk-build/$(0):
$(MAKE) -C $(top_builddir)/cross/ndk-build $(0)
ifeq ($(suffix $(0)),.so)
NDK_BUILD_SHARED += $(top_builddir)/cross/ndk-build/$(0)
else
ifeq ($(suffix $(0)),.a)
NDK_BUILD_STATIC += $(top_builddir)/cross/ndk-build/$(0)
endif
endif
endef
# Generate rules for each module.
$(foreach module,$(NDK_BUILD_MODULES),$(eval $(call subr-1,$(module))))

View file

@ -0,0 +1,43 @@
### @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/>.
# This file is included all over the place to build prerequisites.
NDK_BUILD_MODULES = @NDK_BUILD_MODULES@
NDK_BUILD_SHARED =
NDK_BUILD_STATIC =
define subr-1
$(top_builddir)/cross/ndk-build/$(1):
$(MAKE) -C $(top_builddir)/cross/ndk-build $(1)
ifeq ($(suffix $(1)),.so)
NDK_BUILD_SHARED += $(top_builddir)/cross/ndk-build/$(1)
else
ifeq ($(suffix $(1)),.a)
NDK_BUILD_STATIC += $(top_builddir)/cross/ndk-build/$(1)
endif
endif
endef
# Generate rules for each module.
$(foreach module,$(NDK_BUILD_MODULES),$(eval $(call subr-1,$(module))))

View file

@ -0,0 +1,47 @@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
undefine LOCAL_MODULE
undefine LOCAL_MODULE_FILENAME
undefine LOCAL_SRC_FILES
undefine LOCAL_CPP_EXTENSION
undefine LOCAL_CPP_FEATURES
undefine LOCAL_C_INCLUDES
undefine LOCAL_CFLAGS
undefine LOCAL_CPPFLAGS
undefine LOCAL_STATIC_LIBRARIES
undefine LOCAL_SHARED_LIBRARIES
undefine LOCAL_WHOLE_STATIC_LIBRARIES
undefine LOCAL_LDLIBS
undefine LOCAL_LDFLAGS
undefine LOCAL_ALLOW_UNDEFINED_SYMBOLS
undefine LOCAL_ARM_MODE
undefine LOCAL_ARM_NEON
undefine LOCAL_DISABLE_FORMAT_STRING_CHECKS
undefine LOCAL_EXPORT_CFLAGS
undefine LOCAL_EXPORT_CPPFLAGS
undefine LOCAL_EXPORT_C_INCLUDES
undefine LOCAL_EXPORT_LDFLAGS
undefine LOCAL_EXPORT_LDLIBS
undefine LOCAL_SRC_FILES_$(NDK_BUILD_ARCH)
undefine LOCAL_ASFLAGS_$(NDK_BUILD_ARCH)
undefine LOCAL_CFLAGS_$(NDK_BUILD_ARCH)

View file

@ -0,0 +1,24 @@
### @configure_input@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
$(warn Prebuilt shared libraries are not supported)

View file

@ -0,0 +1,24 @@
### @configure_input@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
$(warn Prebuilt static libraries are not supported)

View file

@ -18,6 +18,7 @@ about using such devices with Emacs, @pxref{Other Input Devices}.
* Android Startup:: Starting up Emacs on Android.
* Android File System:: The Android file system.
* Android Environment:: Running Emacs under Android.
* Android Windowing:: The Android window system.
* Android Fonts:: Font selection under Android.
@end menu
@ -299,7 +300,8 @@ settings application. Consult the manufacturer of your device for
more details, as how to do this varies by device.
@end itemize
@section Android windowing
@node Android Windowing
@section The Android window system
Android has an unusual window system; there, all windows are
maximized or full-screen, and only one window can be displayed at a
@ -372,6 +374,31 @@ The @code{fullscreen} frame parameter is always @code{maximized} for
top-level frames.
@end itemize
@cindex selections, android
@cindex android clipboard
Emacs does not implement all selection related features supported
under the X Window System on Android. For example, only the
@code{CLIPBOARD} and @code{PRIMARY} selections (@pxref{Cut and Paste})
are supported, and plain text is the only supported data type.
In addition, the Android system itself places certain restrictions
on what selection data Emacs can access:
@itemize @bullet
@item
On Android 2.3 and earlier, the function @code{gui-selection-owner-p}
always returns @code{nil} for the clipboard selection.
@item
On Android 3.0 and later, Emacs can only access clipboard data when
one of its frames has the input focus.
@end itemize
Since the Android system itself has no concept of a primary
selection, Emacs provides an emulation instead. This means there is
no way to transfer the contents of the primary selection to another
application via cut-and-paste.
@node Android Fonts
@section Font backends and selection under Android
@cindex fonts, android

View file

@ -1264,6 +1264,7 @@ Emacs and Android
* Android Startup:: Starting up Emacs on Android.
* Android File System:: The Android file system.
* Android Environment:: Running Emacs under Android.
* Android Windowing:: The Android window system.
* Android Fonts:: Font selection under Android.
Emacs and unconventional input devices

View file

@ -131,6 +131,14 @@ the list at the end of this file.
The earliest release of Haiku that will successfully compile Emacs
is R1/Beta2. For windowing support, R1/Beta3 or later is required.
** Android
Emacs is known to run on all Android versions from 2.3 onwards.
It should work with Android 2.2 as well, but only the build
has been tested, and actually running the built Emacs has not.
See the file INSTALL.android for detailed installation instructions.
* Obsolete platforms

View file

@ -60,12 +60,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
android:hardwareAccelerated="true"
android:supportsRtl="true"
android:theme="@android:style/Theme"
android:debuggable="true"
android:debuggable="@ANDROID_DEBUGGABLE@"
android:extractNativeLibs="true">
<activity android:name="org.gnu.emacs.EmacsActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -76,10 +77,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
<activity android:name="org.gnu.emacs.EmacsMultitaskActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/>
<activity android:autoRemoveFromRecents="true"
android:label="Emacs options"
android:exported="true"
android:name=".EmacsPreferencesActivity">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />

View file

@ -81,21 +81,24 @@ APK_NAME = emacs-$(version)-$(ANDROID_MIN_SDK)-$(ANDROID_ABI).apk
all: $(APK_NAME)
# Binaries to cross-compile.
CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \
../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
../xcompile/lib-src/ebrowse ../xcompile/lib-src/emacsclient
CROSS_BINS = ../cross/src/android-emacs ../cross/lib-src/ctags \
../cross/lib-src/hexl ../cross/lib-src/movemail \
../cross/lib-src/ebrowse ../cross/lib-src/emacsclient
# Libraries to cross-compile.
CROSS_LIBS = ../xcompile/src/libemacs.so
CROSS_LIBS = ../cross/src/libemacs.so
# Third party libraries to compile.
include $(top_builddir)/cross/ndk-build/ndk-build.mk
.PHONY: $(CROSS_BINS) $(CROSS_LIBS)
../xcompile/src/android-emacs ../xcompile/src/libemacs.so:
make -C ../xcompile src/$(notdir $@)
../cross/src/android-emacs ../cross/src/libemacs.so:
make -C ../cross src/$(notdir $@)
../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
make -C ../xcompile lib-src/$(notdir $@)
../cross/lib-src/hexl ../cross/lib-src/movemail \
../cross/lib-src/ctags ../cross/lib-src/ebrowse &:
make -C ../cross lib-src/$(notdir $@)
# This is needed to generate the ``.directory-tree'' file used by the
# Android emulations of readdir and faccessat.
@ -104,7 +107,7 @@ $(libsrc)/asset-directory-tool:
$(MAKE) -C $(libsrc) $(notdir $@)
emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \
AndroidManifest.xml
AndroidManifest.xml $(NDK_BUILD_SHARED)
# Make the working directory for this stuff
rm -rf install_temp
mkdir -p install_temp/lib/$(ANDROID_ABI)
@ -145,11 +148,13 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \
cp -f $$file install_temp/lib/$(ANDROID_ABI); \
fi \
done
$(foreach module,$(NDK_BUILD_SHARED), \
cp -f $(module) install_temp/lib/$(ANDROID_ABI))
# Package everything. Specifying the assets on this command line is
# necessary for AAssetManager_getNextFileName to work on old versions
# of Android.
$(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml \
-A install_temp/assets
$(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f \
-M AndroidManifest.xml -A install_temp/assets
pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
rm -rf install_temp
@ -196,3 +201,4 @@ clean:
find . -name '*.class' -delete
maintainer-clean distclean bootstrap-clean: clean
rm -f Makefile ndk-build.mk

View file

@ -0,0 +1,44 @@
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
package org.gnu.emacs;
import android.os.Build;
/* This class provides helper code for accessing the clipboard,
abstracting between the different interfaces on API 8 and 11. */
public abstract class EmacsClipboard
{
public abstract void setClipboard (byte[] bytes);
public abstract int ownsClipboard ();
public abstract boolean clipboardExists ();
public abstract byte[] getClipboard ();
/* Create the correct kind of clipboard for this system. */
public static EmacsClipboard
makeClipboard ()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
return new EmacsSdk11Clipboard ();
else
return new EmacsSdk8Clipboard ();
}
};

View file

@ -23,6 +23,9 @@
import android.os.Build;
/* This code is mostly unused. See sfntfont-android.c for the code
that is actually used. */
public abstract class EmacsFontDriver
{
/* Font weights. */

View file

@ -132,6 +132,10 @@ public static native long sendWheel (short window, int x, int y,
/* Send an ANDROID_CONTEXT_MENU event. */
public static native long sendContextMenu (short window, int menuEventID);
/* Send an ANDROID_EXPOSE event. */
public static native long sendExpose (short window, int x, int y,
int width, int height);
static
{
System.loadLibrary ("emacs");

View file

@ -0,0 +1,156 @@
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
package org.gnu.emacs;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.ClipData;
import android.util.Log;
import java.io.UnsupportedEncodingException;
/* This class implements EmacsClipboard for Android 3.0 and later
systems. */
public class EmacsSdk11Clipboard extends EmacsClipboard
implements ClipboardManager.OnPrimaryClipChangedListener
{
private static final String TAG = "EmacsSdk11Clipboard";
private ClipboardManager manager;
private boolean ownsClipboard;
private int clipboardChangedCount;
private int monitoredClipboardChangedCount;
public
EmacsSdk11Clipboard ()
{
String what;
Context context;
what = Context.CLIPBOARD_SERVICE;
context = EmacsService.SERVICE;
manager
= (ClipboardManager) context.getSystemService (what);
manager.addPrimaryClipChangedListener (this);
}
@Override
public synchronized void
onPrimaryClipChanged ()
{
Log.d (TAG, ("onPrimaryClipChanged: "
+ monitoredClipboardChangedCount
+ " " + clipboardChangedCount));
/* Increment monitoredClipboardChangeCount. If it is now greater
than clipboardChangedCount, then Emacs no longer owns the
clipboard. */
monitoredClipboardChangedCount++;
if (monitoredClipboardChangedCount > clipboardChangedCount)
{
ownsClipboard = false;
/* Reset both values back to 0. */
monitoredClipboardChangedCount = 0;
clipboardChangedCount = 0;
}
}
/* Set the clipboard text to CLIPBOARD, a string in UTF-8
encoding. */
@Override
public synchronized void
setClipboard (byte[] bytes)
{
ClipData data;
String string;
try
{
string = new String (bytes, "UTF-8");
data = ClipData.newPlainText ("Emacs", string);
manager.setPrimaryClip (data);
ownsClipboard = true;
/* onPrimaryClipChanged will be called again. Use this
variable to keep track of how many times the clipboard has
been changed. */
++clipboardChangedCount;
}
catch (UnsupportedEncodingException exception)
{
Log.w (TAG, "setClipboard: " + exception);
}
}
/* Return whether or not Emacs owns the clipboard. Value is 1 if
Emacs does, 0 if Emacs does not, and -1 if that information is
unavailable. */
@Override
public synchronized int
ownsClipboard ()
{
return ownsClipboard ? 1 : 0;
}
/* Return whether or not clipboard content currently exists. */
@Override
public boolean
clipboardExists ()
{
return manager.hasPrimaryClip ();
}
/* Return the current content of the clipboard, as plain text, or
NULL if no content is available. */
@Override
public byte[]
getClipboard ()
{
ClipData clip;
CharSequence text;
Context context;
clip = manager.getPrimaryClip ();
if (clip == null || clip.getItemCount () < 1)
return null;
context = EmacsService.SERVICE;
try
{
text = clip.getItemAt (0).coerceToText (context);
return text.toString ().getBytes ("UTF-8");
}
catch (UnsupportedEncodingException exception)
{
Log.w (TAG, "getClipboard: " + exception);
}
return null;
}
};

View file

@ -0,0 +1,116 @@
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
package org.gnu.emacs;
/* Importing the entire package avoids the deprecation warning. */
import android.text.*;
import android.content.Context;
import android.util.Log;
import java.io.UnsupportedEncodingException;
/* This class implements EmacsClipboard for Android 2.2 and other
similarly old systems. */
@SuppressWarnings ("deprecation")
public class EmacsSdk8Clipboard extends EmacsClipboard
{
private static final String TAG = "EmacsSdk8Clipboard";
private ClipboardManager manager;
public
EmacsSdk8Clipboard ()
{
String what;
Context context;
what = Context.CLIPBOARD_SERVICE;
context = EmacsService.SERVICE;
manager
= (ClipboardManager) context.getSystemService (what);
}
/* Set the clipboard text to CLIPBOARD, a string in UTF-8
encoding. */
@Override
public void
setClipboard (byte[] bytes)
{
try
{
manager.setText (new String (bytes, "UTF-8"));
}
catch (UnsupportedEncodingException exception)
{
Log.w (TAG, "setClipboard: " + exception);
}
}
/* Return whether or not Emacs owns the clipboard. Value is 1 if
Emacs does, 0 if Emacs does not, and -1 if that information is
unavailable. */
@Override
public int
ownsClipboard ()
{
return -1;
}
/* Return whether or not clipboard content currently exists. */
@Override
public boolean
clipboardExists ()
{
return manager.hasText ();
}
/* Return the current content of the clipboard, as plain text, or
NULL if no content is available. */
@Override
public byte[]
getClipboard ()
{
String string;
CharSequence text;
text = manager.getText ();
if (text == null)
return null;
string = text.toString ();
try
{
return string.getBytes ("UTF-8");
}
catch (UnsupportedEncodingException exception)
{
Log.w (TAG, "getClipboard: " + exception);
}
return null;
}
};

View file

@ -99,6 +99,9 @@ public class EmacsView extends ViewGroup
yet responded to. 0 if there is no such outstanding event. */
public long pendingConfigure;
/* Whether or not this view is attached to a window. */
public boolean isAttachedToWindow;
public
EmacsView (EmacsWindow window)
{
@ -140,6 +143,9 @@ public class EmacsView extends ViewGroup
if (measuredWidth == 0 || measuredHeight == 0)
return;
if (!isAttachedToWindow)
return;
/* If bitmap is the same width and height as the measured width
and height, there is no need to do anything. Avoid allocating
the extra bitmap. */
@ -547,6 +553,8 @@ else if (child.getVisibility () != GONE)
public synchronized void
onDetachedFromWindow ()
{
isAttachedToWindow = false;
synchronized (this)
{
/* Recycle the bitmap and call GC. */
@ -559,6 +567,21 @@ else if (child.getVisibility () != GONE)
}
}
@Override
public synchronized void
onAttachedToWindow ()
{
isAttachedToWindow = true;
/* Dirty the bitmap, as it was destroyed when onDetachedFromWindow
was called. */
bitmapDirty = true;
/* Now expose the view contents again. */
EmacsNative.sendExpose (this.window.handle, 0, 0,
measuredWidth, measuredHeight);
}
public void
showOnScreenKeyboard ()
{

View file

@ -21,7 +21,7 @@ srcdir = @srcdir@
VPATH = @srcdir@
# This is not empty if this is a Makefile that will be copied to
# xcompile/lib.
# cross/lib.
XCONFIGURE = @XCONFIGURE@
# This is required to make sure symbol visibility is correct and
@ -64,7 +64,7 @@ endif
ifeq ($(XCONFIGURE),android)
# The next line is necessary to override -I$(srcdir), which will end
# up pulling in lots of headers from the host.
ALL_CFLAGS += -I$(top_srcdir)/xcompile -I.
ALL_CFLAGS += -I$(top_srcdir)/cross -I.
endif
DEPDIR = deps

View file

@ -59,5 +59,111 @@ DISPLAY is ignored on Android."
;; arguments on.
(ignore))
;;; Selection support.
(declare-function android-clipboard-exists-p "androidselect.c")
(declare-function android-get-clipboard "androidselect.c")
(declare-function android-set-clipboard "androidselect.c")
(declare-function android-clipboard-owner-p "androidselect.c")
(defvar android-primary-selection nil
"The last string placed in the primary selection.
Nil if there was no such string.
Android does not have a primary selection of its own, so Emacs
emulates one inside Lisp.")
(defun android-get-clipboard-1 (data-type)
"Return the clipboard data.
DATA-TYPE is a selection conversion target; only STRING and
TARGETS are supported."
(or (and (eq data-type 'STRING)
(android-get-clipboard))
(and (eq data-type 'TARGETS)
(android-clipboard-exists-p)
[TARGETS STRING])))
(defun android-get-primary (data-type)
"Return the last string placed in the primary selection, or nil.
Return nil if DATA-TYPE is anything other than STRING or TARGETS."
(when android-primary-selection
(or (and (eq data-type 'STRING)
android-primary-selection)
(and (eq data-type 'TARGETS)
[TARGETS]))))
(defun android-selection-bounds (value)
"Return bounds of selection value VALUE.
The return value is a list (BEG END BUF) if VALUE is a cons of
two markers or an overlay. Otherwise, it is nil."
(cond ((bufferp value)
(with-current-buffer value
(when (mark t)
(list (mark t) (point) value))))
((and (consp value)
(markerp (car value))
(markerp (cdr value)))
(when (and (marker-buffer (car value))
(buffer-name (marker-buffer (car value)))
(eq (marker-buffer (car value))
(marker-buffer (cdr value))))
(list (marker-position (car value))
(marker-position (cdr value))
(marker-buffer (car value)))))
((overlayp value)
(when (overlay-buffer value)
(list (overlay-start value)
(overlay-end value)
(overlay-buffer value))))))
(defun android-encode-select-string (value)
"Turn VALUE into a string suitable for placing in the clipboard.
VALUE should be something suitable for passing to
`gui-set-selection'."
(unless (stringp value)
(when-let ((bounds (android-selection-bounds value)))
(setq value (ignore-errors
(with-current-buffer (nth 2 bounds)
(buffer-substring (nth 0 bounds)
(nth 1 bounds)))))))
value)
(cl-defmethod gui-backend-get-selection (type data-type
&context (window-system android))
(cond ((eq type 'CLIPBOARD)
(android-get-clipboard-1 data-type))
((eq type 'PRIMARY)
(android-get-primary data-type))))
(cl-defmethod gui-backend-selection-exists-p (selection
&context (window-system android))
(cond ((eq selection 'CLIPBOARD)
(android-clipboard-exists-p))
((eq selection 'PRIMARY)
(not (null android-primary-selection)))))
(cl-defmethod gui-backend-selection-owner-p (selection
&context (window-system android))
(cond ((eq selection 'CLIPBOARD)
(let ((ownership (android-clipboard-owner-p)))
;; If ownership is `lambda', then Emacs couldn't determine
;; whether or not it owns the clipboard.
(and (not (eq ownership 'lambda)) ownership)))
((eq selection 'PRIMARY)
;; Emacs always owns its own primary selection as long as it
;; exists.
(not (null android-primary-selection)))))
(cl-defmethod gui-backend-set-selection (type value
&context (window-system android))
;; First, try to turn value into a string.
;; Don't set anything if that did not work.
(when-let ((string (android-encode-select-string value)))
(cond ((eq type 'CLIPBOARD)
(android-set-clipboard string))
((eq type 'PRIMARY)
(setq android-primary-selection string)))))
(provide 'android-win)
;; android-win.el ends here.

213
m4/ndk-build.m4 Normal file
View file

@ -0,0 +1,213 @@
dnl Copyright (C) 2023 Free Software Foundation, Inc.
dnl This file is part of GNU Emacs.
dnl GNU Emacs is free software: you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation, either version 3 of the License, or
dnl (at your option) any later version.
dnl GNU Emacs is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl You should have received a copy of the GNU General Public License
dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
# Support for building Emacs with dependencies using the Android NDK
# build system.
AC_ARG_WITH([ndk_path],
[AS_HELP_STRING([--with-ndk-path],
[find Android libraries in these directories])])
# ndk_INIT(ABI, API, DIR)
# --------
# Initialize the Android NDK. ABI is the ABI being built for.
# API is the API version being built for.
# As a side effect, set the variable ndk_INITIALIZED to true.
# DIR should be a directory containing the Makefile.in actually
# implementing the Android NDK build system.
AC_DEFUN_ONCE([ndk_INIT],
[
# Look for Android.mk files.
ndk_module_files=
for file in $with_ndk_path; do
if test -f $file/Android.mk; then
ndk_module_files="$ndk_module_files$file/Android.mk "
fi
done
ndk_ABI=$1
ndk_MODULES=
ndk_MAKEFILES=
ndk_INITIALIZED=yes
ndk_API=$2
ndk_DIR=$3
case "$ndk_ABI" in
*arm64* )
ndk_ARCH=arm64
;;
*arm* )
ndk_ARCH=arm
;;
*x86_64* )
ndk_ARCH=x86_64
;;
*x86* )
ndk_ARCH=x86
;;
* )
AC_MSG_ERROR([Failed to determine Android device architecture])
;;
esac
# This is a map between pkg-config style package names and Android
# ones.
ndk_package_map="libwebpdemux:webpdemux libxml-2.0:libxml2"
# Replace ndk_module with the appropriate Android module name if it is
# found in ndk_package_map.
ndk_replace_pkg_config_package () {
for ndk_stuff in $ndk_package_map; do
ndk_key=${ndk_stuff%%:*}
ndk_value=${ndk_stuff#*:}
if test "$ndk_key" = "$ndk_module"; then
ndk_module="$ndk_value"
break
fi
done
}
# Parse a pkg-config style list of modules. Place the resulting list
# in ndk_modules.
ndk_parse_pkg_config_string () {
ndk_input=[$]1
ndk_modules=
while test -n "$ndk_input"; do
ndk_str=$(printf "$ndk_input" | cut -f1 -d' ')
ndk_input="$(printf "$ndk_input" | cut -s -f2- -d' ')"
if test "$ndk_str" = ">=" || test "$ndk_str" = "<=" \
|| test "$ndk_str" = ">" || test "$ndk_str" = "<"; then
ndk_input="$(printf "$ndk_input" | cut -s -f2- -d' ')"
else
ndk_modules="$ndk_modules$ndk_str "
fi
done
}
# Look for a suitable ar in the same directory as the C compiler.
ndk_where_cc=$(which $CC)
ndk_ar_search_path=$PATH
# First, try to find $host_alias-ar in PATH.
AC_PATH_PROGS([AR], [$host_alias-ar], [], [$ndk_ar_search_path])
if test -z "$AR"; then
# Next, try finding either that or llvm-ar in the directory holding
# CC.
ndk_ar_search_path="$(dirname $ndk_where_cc):$ndk_ar_search_path"
AC_PATH_PROGS([AR], [$host_alias-ar llvm-ar], [], [$ndk_ar_search_path])
fi
# These variables have now been found.
])
# ndk_SEARCH_MODULE(MODULE, NAME, ACTION-IF-FOUND, [ACTION-IF-NOT-FOUND])
# --------------------------------------------------------------------
# Search for a module named MODULE in `with_ndk_path'. Add the file
# name of the module's Android.mk file to the variable ndk_MODULES.
# Set NAME_CFLAGS and NAME_LIBS to the appropriate values. Then,
# call ACTION-IF-FOUND, or ACTION-IF-NOT-FOUND upon failure.
AC_DEFUN([ndk_SEARCH_MODULE],
[
module_name=
ndk_module=$1
ndk_replace_pkg_config_package
AC_MSG_CHECKING([for Android.mk that builds $ndk_module])
for ndk_android_mk in $ndk_module_files; do
# Read this Android.mk file. Set NDK_ROOT to /tmp: the Android in
# tree build system sets it to a meaning value, but build files just
# use it to test whether or not the NDK is being used.
ndk_commands=$(make -s -f build-aux/ndk-build-helper.mk EMACS_SRCDIR=. \
EMACS_ABI=$ndk_ABI ANDROID_MAKEFILE="$ndk_android_mk" \
ANDROID_MODULE_DIRECTORY=$(dirname "$ndk_android_mk") \
NDK_BUILD_DIR="$ndk_DIR" NDK_ROOT="/tmp" \
| awk -f build-aux/ndk-module-extract.awk \
MODULE="$ndk_module")
AS_IF([test -n "${ndk_commands//\n }"], [eval "$ndk_commands"])
if test -n "$module_name"; then
break
fi
done
if test -z "$module_name"; then
AC_MSG_RESULT([no])
$4
else
$2[]_CFLAGS="[$]$2[]_CFLAGS $module_cflags $module_includes"
$2[]_LIBS="[$]$2[]_LIBS $module_ldflags"
ndk_MAKEFILES="$ndk_MAKEFILES $ndk_android_mk"
ndk_MODULES="$ndk_MODULES $module_target"
AC_MSG_RESULT([yes])
$3
fi
])
# ndk_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
# --------------------------------------------------------------
# Just like `PKG_CHECK_MODULES'. However, it uses the ndk-build
# system instead.
AC_DEFUN([ndk_CHECK_MODULES],
[
ndk_modules=
ndk_parse_pkg_config_string "$2"
ndk_found=no
for module in $ndk_modules; do
ndk_SEARCH_MODULE([$module], [$1], [ndk_found=yes], [ndk_found=no])
done
AS_IF([test "$ndk_found" = "yes"],[$3],[$4])
])
# ndk_CONFIG_FILES
# -------------------------------------------------------------
# Write out the NDK build Makefile with the appropriate variables
# set if the NDK has been initialized.
AC_DEFUN_ONCE([ndk_CONFIG_FILES],
[
if test "$ndk_INITIALIZED" = "yes"; then
NDK_BUILD_ANDROID_MK="$ndk_MAKEFILES"
NDK_BUILD_ARCH=$ndk_ARCH
NDK_BUILD_ABI=$ndk_ABI
NDK_BUILD_SDK=$ndk_API
NDK_BUILD_CC=$CC
NDK_BUILD_AR=$AR
NDK_BUILD_MODULES="$ndk_MODULES"
AC_SUBST([NDK_BUILD_ANDROID_MK])
AC_SUBST([NDK_BUILD_ARCH])
AC_SUBST([NDK_BUILD_ABI])
AC_SUBST([NDK_BUILD_SDK])
AC_SUBST([NDK_BUILD_CC])
AC_SUBST([NDK_BUILD_AR])
AC_SUBST([NDK_BUILD_MODULES])
AC_CONFIG_FILES([$ndk_DIR/Makefile])
AC_CONFIG_FILES([$ndk_DIR/ndk-build.mk])
fi
])

View file

@ -35,7 +35,7 @@ abs_top_srcdir=@abs_top_srcdir@
VPATH = $(srcdir)
# This is not empty if this is a Makefile that will be copied to
# xcompile/src.
# cross/src.
XCONFIGURE = @XCONFIGURE@
ifneq ($(XCONFIGURE),)
@ -138,6 +138,8 @@ LIB_PTHREAD=@LIB_PTHREAD@
LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@
GIF_CFLAGS=@GIF_CFLAGS@
XCB_LIBS=@XCB_LIBS@
XFT_LIBS=@XFT_LIBS@
XRENDER_LIBS=@XRENDER_LIBS@
@ -384,6 +386,7 @@ HAIKU_CFLAGS = @HAIKU_CFLAGS@
ANDROID_OBJ = @ANDROID_OBJ@
ANDROID_LIBS = @ANDROID_LIBS@
ANDROID_LDFLAGS = @ANDROID_LDFLAGS@
ANDROID_CFLAGS = @ANDROID_CFLAGS@
DUMPING=@DUMPING@
@ -428,7 +431,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \
$(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
$(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) \
$(ANDROID_CFLAGS)
$(ANDROID_CFLAGS) $(GIF_CFLAGS)
ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \
$(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \
@ -745,10 +748,18 @@ ifeq ($(XCONFIGURE),android)
## is not dumped here. Instead, it dumps itself the first time it
## starts on the user's device.
# Include ndk-build.mk in order to build Emacs dependencies.
old_top_builddir := $(top_builddir)
top_builddir := $(old_top_builddir)/..
include $(old_top_builddir)/ndk-build/ndk-build.mk
top_builddir := $(old_top_builddir)
libemacs.so: $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \
$(MAKE_PDUMPER_FINGERPRINT)
$(MAKE_PDUMPER_FINGERPRINT) $(NDK_BUILD_SHARED) \
$(NDK_BUILD_STATIC)
$(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) \
$(LDFLAGS) -shared $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(LIBES)
$(ANDROID_LDFLAGS) $(LDFLAGS) -shared $(ALLOBJS) \
$(LIBEGNU_ARCHIVE) $(LIBES)
$(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@
# There is also a binary named `android-emacs' which simply calls

View file

@ -1086,6 +1086,39 @@ android_hack_asset_fd (AAsset *asset)
return fd;
}
/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
archive compressed data.
If they are not, rewind the file descriptor to offset 0.
If either operation fails, return -1 and close FD. Else, value is
FD. */
static int
android_check_compressed_file (int fd)
{
char bytes[2];
if (read (fd, bytes, 2) != 2)
goto lseek_back;
if (bytes[0] != 'P' || bytes[1] != 'K')
goto lseek_back;
/* This could be compressed data! */
return -1;
lseek_back:
/* Seek back to offset 0. If this fails, return -1. */
if (lseek (fd, 0, SEEK_SET) != 0)
{
close (fd);
return -1;
}
return fd;
}
/* `open' and such are modified even though they exist on Android,
because Emacs treats "/assets/" as a special directory that must
contain all assets in the application package. */
@ -1095,7 +1128,7 @@ android_open (const char *filename, int oflag, int mode)
{
const char *name;
AAsset *asset;
int fd;
int fd, oldfd;
off_t out_start, out_length;
bool fd_hacked;
@ -1118,8 +1151,12 @@ android_open (const char *filename, int oflag, int mode)
return -1;
}
/* If given AASSET_MODE_BUFFER (which is what Emacs probably
does, given that a file descriptor is not always available),
the framework fails to uncompress the data before it returns
a file descriptor. */
asset = AAssetManager_open (asset_manager, name,
AASSET_MODE_BUFFER);
AASSET_MODE_STREAMING);
if (!asset)
{
@ -1132,6 +1169,11 @@ android_open (const char *filename, int oflag, int mode)
fd = AAsset_openFileDescriptor (asset, &out_start,
&out_length);
/* The platform sometimes returns a file descriptor to ZIP
compressed data. Detect that and fall back to creating a
shared memory file descriptor. */
fd = android_check_compressed_file (fd);
if (fd == -1)
{
/* The asset can't be accessed for some reason. Try to
@ -1152,7 +1194,13 @@ android_open (const char *filename, int oflag, int mode)
which will close the original file descriptor. */
if (!fd_hacked)
fd = fcntl (fd, F_DUPFD_CLOEXEC);
{
oldfd = fd;
fd = fcntl (oldfd, F_DUPFD_CLOEXEC);
/* Close the original file descriptor. */
close (oldfd);
}
if (fd >= ANDROID_MAX_ASSET_FD || fd < 0)
{
@ -1978,6 +2026,25 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
return event_serial;
}
extern JNIEXPORT jlong JNICALL
NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object,
jshort window, jint x, jint y,
jint width, jint height)
{
union android_event event;
event.xexpose.type = ANDROID_EXPOSE;
event.xexpose.serial = ++event_serial;
event.xexpose.window = window;
event.xexpose.x = x;
event.xexpose.y = y;
event.xexpose.width = width;
event.xexpose.height = height;
android_write_event (&event);
return event_serial;
}
#ifdef __clang__
#pragma clang diagnostic pop
#else
@ -4222,7 +4289,14 @@ android_readdir (struct android_dir *dir)
dirent.d_ino = 0;
dirent.d_off = 0;
dirent.d_reclen = sizeof dirent;
dirent.d_type = DT_UNKNOWN;
/* If this is not a directory, return DT_UNKNOWN. Otherwise,
return DT_DIR. */
if (android_is_directory (dir->asset_dir))
dirent.d_type = DT_DIR;
else
dirent.d_type = DT_UNKNOWN;
/* Note that dir->asset_dir is actually a NULL terminated
string. */

View file

@ -234,6 +234,7 @@ enum android_event_type
ANDROID_ICONIFIED,
ANDROID_DEICONIFIED,
ANDROID_CONTEXT_MENU,
ANDROID_EXPOSE,
};
struct android_any_event
@ -332,6 +333,15 @@ struct android_button_event
unsigned int button;
};
struct android_expose_event
{
enum android_event_type type;
unsigned long serial;
android_window window;
int x, y;
int width, height;
};
struct android_touch_event
{
/* Type of the event. */
@ -415,6 +425,7 @@ union android_event
struct android_crossing_event xcrossing;
struct android_motion_event xmotion;
struct android_button_event xbutton;
struct android_expose_event xexpose;
/* This has no parallel in X, since the X model of having
monotonically increasing touch IDs can't work on Android. */

249
src/androidselect.c Normal file
View file

@ -0,0 +1,249 @@
/* Communication module for Android terminals.
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/>. */
#include <config.h>
#include <assert.h>
#include "lisp.h"
#include "blockinput.h"
#include "coding.h"
#include "android.h"
#include "androidterm.h"
/* Selection support on Android is confined to copying and pasting of
plain text from the clipboard. There is no primary selection.
While newer versions of Android are supposed to have the necessary
interfaces for transferring other kinds of selection data, doing so
is too complicated, and involves registering ``content providers''
and all kinds of other stuff. */
/* Structure describing the EmacsClipboard class. */
struct android_emacs_clipboard
{
jclass class;
jmethodID set_clipboard;
jmethodID owns_clipboard;
jmethodID clipboard_exists;
jmethodID get_clipboard;
jmethodID make_clipboard;
};
/* Methods associated with the EmacsClipboard class. */
static struct android_emacs_clipboard clipboard_class;
/* Reference to the EmacsClipboard object. */
static jobject clipboard;
static void
android_init_emacs_clipboard (void)
{
jclass old;
clipboard_class.class
= (*android_java_env)->FindClass (android_java_env,
"org/gnu/emacs/EmacsClipboard");
eassert (clipboard_class.class);
old = clipboard_class.class;
clipboard_class.class
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
old);
ANDROID_DELETE_LOCAL_REF (old);
if (!clipboard_class.class)
emacs_abort ();
#define FIND_METHOD(c_name, name, signature) \
clipboard_class.c_name \
= (*android_java_env)->GetMethodID (android_java_env, \
clipboard_class.class, \
name, signature); \
assert (clipboard_class.c_name);
FIND_METHOD (set_clipboard, "setClipboard", "([B)V");
FIND_METHOD (owns_clipboard, "ownsClipboard", "()I");
FIND_METHOD (clipboard_exists, "clipboardExists", "()Z");
FIND_METHOD (get_clipboard, "getClipboard", "()[B");
clipboard_class.make_clipboard
= (*android_java_env)->GetStaticMethodID (android_java_env,
clipboard_class.class,
"makeClipboard",
"()Lorg/gnu/emacs/"
"EmacsClipboard;");
assert (clipboard_class.make_clipboard);
#undef FIND_METHOD
}
DEFUN ("android-clipboard-owner-p", Fandroid_clipboard_owner_p,
Sandroid_clipboard_owner_p, 0, 0, 0,
doc: /* Return whether or not Emacs owns the clipboard.
Alternatively, return the symbol `lambda' if that could not be
determined. */)
(void)
{
jint rc;
block_input ();
rc = (*android_java_env)->CallIntMethod (android_java_env,
clipboard,
clipboard_class.owns_clipboard);
android_exception_check ();
unblock_input ();
/* If rc is 0 or 1, then Emacs knows whether or not it owns the
clipboard. If rc is -1, then Emacs does not. */
if (rc < 0)
return Qlambda;
return rc ? Qt : Qnil;
}
DEFUN ("android-set-clipboard", Fandroid_set_clipboard,
Sandroid_set_clipboard, 1, 1, 0,
doc: /* Set the clipboard text to STRING. */)
(Lisp_Object string)
{
jarray bytes;
CHECK_STRING (string);
string = ENCODE_UTF_8 (string);
bytes = (*android_java_env)->NewByteArray (android_java_env,
SBYTES (string));
android_exception_check ();
(*android_java_env)->SetByteArrayRegion (android_java_env, bytes,
0, SBYTES (string),
(jbyte *) SDATA (string));
(*android_java_env)->CallVoidMethod (android_java_env,
clipboard,
clipboard_class.set_clipboard,
bytes);
android_exception_check ();
ANDROID_DELETE_LOCAL_REF (bytes);
return Qnil;
}
DEFUN ("android-get-clipboard", Fandroid_get_clipboard,
Sandroid_get_clipboard, 0, 0, 0,
doc: /* Return the current contents of the clipboard.
Value is a multibyte string containing decoded clipboard
text.
Alternatively, return nil if the clipboard is empty. */)
(void)
{
Lisp_Object string;
jarray bytes;
jmethodID method;
size_t length;
jbyte *data;
method = clipboard_class.get_clipboard;
bytes
= (*android_java_env)->CallObjectMethod (android_java_env,
clipboard,
method);
if (!bytes)
{
android_exception_check ();
return Qnil;
}
length = (*android_java_env)->GetArrayLength (android_java_env,
bytes);
data = (*android_java_env)->GetByteArrayElements (android_java_env,
bytes, NULL);
android_exception_check ();
string = make_unibyte_string ((char *) data, length);
(*android_java_env)->ReleaseByteArrayElements (android_java_env,
bytes, data,
JNI_ABORT);
ANDROID_DELETE_LOCAL_REF (bytes);
/* Now decode the resulting string. */
return code_convert_string_norecord (string, Qutf_8, Qnil);
}
DEFUN ("android-clipboard-exists-p", Fandroid_clipboard_exists_p,
Sandroid_clipboard_exists_p, 0, 0, 0,
doc: /* Return whether or not clipboard contents exist. */)
(void)
{
jboolean rc;
jmethodID method;
method = clipboard_class.clipboard_exists;
rc = (*android_java_env)->CallBooleanMethod (android_java_env,
clipboard,
method);
android_exception_check ();
return rc ? Qt : Qnil;
}
void
init_androidselect (void)
{
jobject tem;
jmethodID make_clipboard;
android_init_emacs_clipboard ();
make_clipboard = clipboard_class.make_clipboard;
tem
= (*android_java_env)->CallStaticObjectMethod (android_java_env,
clipboard_class.class,
make_clipboard);
if (!tem)
emacs_abort ();
clipboard = (*android_java_env)->NewGlobalRef (android_java_env, tem);
if (!clipboard)
emacs_abort ();
ANDROID_DELETE_LOCAL_REF (tem);
}
void
syms_of_androidselect (void)
{
defsubr (&Sandroid_clipboard_owner_p);
defsubr (&Sandroid_set_clipboard);
defsubr (&Sandroid_get_clipboard);
defsubr (&Sandroid_clipboard_exists_p);
}

View file

@ -818,6 +818,28 @@ handle_one_android_event (struct android_display_info *dpyinfo,
goto OTHER;
case ANDROID_EXPOSE:
f = any;
if (f)
{
if (!FRAME_VISIBLE_P (f))
{
f->output_data.android->has_been_visible = true;
SET_FRAME_GARBAGED (f);
}
if (!FRAME_GARBAGED_P (f))
{
expose_frame (f, event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
show_back_buffer (f);
}
}
goto OTHER;
case ANDROID_BUTTON_PRESS:
case ANDROID_BUTTON_RELEASE:
/* If we decide we want to generate an event to be seen

View file

@ -432,6 +432,15 @@ extern void sfntfont_android_shrink_scanline_buffer (void);
extern void init_sfntfont_android (void);
extern void syms_of_sfntfont_android (void);
/* Defined in androidselect.c */
#ifndef ANDROID_STUBIFY
extern void init_androidselect (void);
extern void syms_of_androidselect (void);
#endif
#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))

View file

@ -2409,6 +2409,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
syms_of_fontset ();
#if !defined ANDROID_STUBIFY
syms_of_androidfont ();
syms_of_androidselect ();
syms_of_sfntfont ();
syms_of_sfntfont_android ();
#endif /* !ANDROID_STUBIFY */
@ -2514,6 +2515,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
init_androidfont ();
init_androidselect ();
init_sfntfont ();
init_sfntfont_android ();
#endif