aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2023-01-19 22:19:06 +0800
committerPo Lu2023-01-19 22:19:06 +0800
commita496509cedb17109d0e6297a74e2ff8ed526333c (patch)
tree46f3db2be263de7074675a5188796e25f21d4888 /java
parent6253e7e74249c7cdfa86723f0b91a1d207cb143e (diff)
downloademacs-a496509cedb17109d0e6297a74e2ff8ed526333c.tar.gz
emacs-a496509cedb17109d0e6297a74e2ff8ed526333c.zip
Update Android port
* .gitignore: Add new files. * INSTALL.android: Explain how to build Emacs for ancient versions of Android. * admin/merge-gnulib (GNULIB_MODULES): Add getdelim. * build-aux/config.guess (timestamp, version): * build-aux/config.sub (timestamp, version): Autoupdate. * configure.ac (BUILD_DETAILS, ANDROID_MIN_SDK): (ANDROID_STUBIFY): Allow specifying CFLAGS via ANDROID_CFLAGS. Add new configure tests for Android API version when not explicitly specified. * doc/emacs/android.texi (Android): Add reference to ``Other Input Devices''. (Android File System): Remove restrictions on directory-files on the assets directory. * doc/emacs/emacs.texi (Top): Add Other Input Devices to menu. * doc/emacs/input.texi (Other Input Devices): New node. * doc/lispref/commands.texi (Touchscreen Events): Document changes to touchscreen input events. * doc/lispref/frames.texi (Pop-Up Menus): Likewise. * etc/NEWS: Announce changes. * java/Makefile.in: Use lib-src/asset-directory-tool to generate an `directory-tree' file placed in /assets. * java/debug.sh: Large adjustments to support Android 2.2 and later. * java/org/gnu/emacs/EmacsContextMenu.java (inflateMenuItems): * java/org/gnu/emacs/EmacsCopyArea.java (perform): * java/org/gnu/emacs/EmacsDialog.java (toAlertDialog): * java/org/gnu/emacs/EmacsDrawLine.java (perform): * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (perform): * java/org/gnu/emacs/EmacsFillRectangle.java (perform): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): (destroyHandle): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (draw): Avoid redundant canvas saves and restores. * java/org/gnu/emacs/EmacsService.java (run): * java/org/gnu/emacs/EmacsView.java (EmacsView): (handleDirtyBitmap): * java/org/gnu/emacs/EmacsWindow.java (changeWindowBackground) (EmacsWindow): Make compatible with Android 2.2 and later. * lib-src/Makefile.in (DONT_INSTALL): Add asset-directory-tool on Android.:(asset-directory-tool{EXEEXT}): New target. * lib-src/asset-directory-tool.c (struct directory_tree, xmalloc) (main_1, main_2, main): New file. * lib, m4: Merge from gnulib. This will be reverted before merging to master. * lisp/button.el (button-map): (push-button): * lisp/frame.el (display-popup-menus-p): Improve touchscreen support. * lisp/subr.el (event-start): (event-end): Handle touchscreen events. * lisp/touch-screen.el (touch-screen-handle-timeout): (touch-screen-handle-point-update): (touch-screen-handle-point-up): (touch-screen-track-tap): (touch-screen-track-drag): (touch-screen-drag-mode-line-1): (touch-screen-drag-mode-line): New functions. ([mode-line touchscreen-begin]): ([bottom-divider touchscreen-begin]): Bind new events. * lisp/wid-edit.el (widget-event-point): (widget-keymap): (widget-event-start): (widget-button--check-and-call-button): (widget-button-click): Improve touchscreen support. * src/alloc.c (make_lisp_symbol): Avoid ICE on Android NDK GCC. (mark_pinned_symbols): Likewise. * src/android.c (struct android_emacs_window): New struct. (window_class): New variable. (android_run_select_thread): Add workaround for Android platform bug. (android_extract_long, android_scan_directory_tree): New functions. (android_file_access_p): Use those functions instead. (android_init_emacs_window): New function. (android_init_emacs_gc_class): Update signature of `markDirty'. (android_change_gc, android_set_clip_rectangles): Tell the GC whether or not clip rects were dirtied. (android_swap_buffers): Do not look up method every time. (struct android_dir): Adjust for new directory tree lookup. (android_opendir, android_readdir, android_closedir): Likewise. (android_four_corners_bilinear): Fix coding style. (android_ftruncate): New function. * src/android.h: Update prototypes. Replace ftruncate with android_ftruncate when necessary. * src/androidterm.c (handle_one_android_event): Pacify GCC. Fix touch screen tool bar bug. * src/emacs.c (using_utf8): Fix compilation error. * src/fileio.c (Ffile_system_info): Return Qnil when fsusage.o is not built. * src/filelock.c (BOOT_TIME_FILE): Fix definition for Android. * src/frame.c (Fx_parse_geometry): Fix uninitialized variable uses. * src/keyboard.c (lispy_function_keys): Fix `back'. * src/menu.c (x_popup_menu_1): Handle touch screen events. (Fx_popup_menu): Document changes. * src/sfnt.c (main): Improve tests. * src/sfntfont-android.c (sfntfont_android_put_glyphs): Fix minor problem. (init_sfntfont_android): Check for HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL. * src/sfntfont.c (struct sfnt_font_desc): New fields `adstyle' and `languages'. (sfnt_parse_style): Append tokens to adstyle. (sfnt_parse_languages): New function. (sfnt_enum_font_1): Parse supported languages and adstyle. (sfntfont_list_1): Handle new fields. (sfntfont_text_extents): Fix uninitialized variable use. (syms_of_sfntfont, mark_sfntfont): Adjust accordingly.
Diffstat (limited to 'java')
-rw-r--r--java/Makefile.in37
-rwxr-xr-xjava/debug.sh155
-rw-r--r--java/org/gnu/emacs/EmacsContextMenu.java20
-rw-r--r--java/org/gnu/emacs/EmacsCopyArea.java11
-rw-r--r--java/org/gnu/emacs/EmacsDialog.java3
-rw-r--r--java/org/gnu/emacs/EmacsDrawLine.java11
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java45
-rw-r--r--java/org/gnu/emacs/EmacsDrawable.java2
-rw-r--r--java/org/gnu/emacs/EmacsFillPolygon.java11
-rw-r--r--java/org/gnu/emacs/EmacsFillRectangle.java12
-rw-r--r--java/org/gnu/emacs/EmacsGC.java33
-rw-r--r--java/org/gnu/emacs/EmacsPixmap.java77
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java11
-rw-r--r--java/org/gnu/emacs/EmacsService.java7
-rw-r--r--java/org/gnu/emacs/EmacsView.java34
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java80
16 files changed, 343 insertions, 206 deletions
diff --git a/java/Makefile.in b/java/Makefile.in
index c539fb0f1fb..22c912fdce5 100644
--- a/java/Makefile.in
+++ b/java/Makefile.in
@@ -21,6 +21,10 @@ top_builddir = @top_builddir@
21top_srcdir = @top_srcdir@ 21top_srcdir = @top_srcdir@
22version = @version@ 22version = @version@
23 23
24# This is the host lib-src and lib, not the cross compiler's lib-src.
25libsrc = ../lib-src
26EXEEXT = @EXEEXT@
27
24-include ${top_builddir}/src/verbose.mk 28-include ${top_builddir}/src/verbose.mk
25 29
26SHELL = @SHELL@ 30SHELL = @SHELL@
@@ -29,14 +33,25 @@ AAPT = @AAPT@
29D8 = @D8@ 33D8 = @D8@
30ZIPALIGN = @ZIPALIGN@ 34ZIPALIGN = @ZIPALIGN@
31JARSIGNER = @JARSIGNER@ 35JARSIGNER = @JARSIGNER@
36JARSIGNER_FLAGS =
32ANDROID_JAR = @ANDROID_JAR@ 37ANDROID_JAR = @ANDROID_JAR@
33ANDROID_ABI = @ANDROID_ABI@ 38ANDROID_ABI = @ANDROID_ABI@
39ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@
34 40
35WARN_JAVAFLAGS = -Xlint:deprecation 41WARN_JAVAFLAGS = -Xlint:deprecation
36JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \ 42JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
37 $(WARN_JAVAFLAGS) 43 $(WARN_JAVAFLAGS)
38 44
39SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 45# Android 4.3 and earlier require Emacs to be signed with a different
46# digital signature algorithm.
47
48ifneq (,$(ANDROID_SDK_18_OR_EARLIER))
49JARSIGNER_FLAGS = -sigalg MD5withRSA -digestalg SHA1
50else
51JARSIGNER_FLAGS =
52endif
53
54SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 $(JARSIGNER_FLAGS)
40 55
41JAVA_FILES = $(shell find . -type f -name *.java) 56JAVA_FILES = $(shell find . -type f -name *.java)
42CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class) 57CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
@@ -82,7 +97,14 @@ CROSS_LIBS = ../xcompile/src/libemacs.so
82../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &: 97../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
83 make -C ../xcompile lib-src/$(notdir $@) 98 make -C ../xcompile lib-src/$(notdir $@)
84 99
85emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml 100# This is needed to generate the ``.directory-tree'' file used by the
101# Android emulations of readdir and faccessat.
102
103$(libsrc)/asset-directory-tool:
104 $(MAKE) -C $(libsrc) $(notdir $@)
105
106emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \
107 AndroidManifest.xml
86# Make the working directory for this stuff 108# Make the working directory for this stuff
87 rm -rf install_temp 109 rm -rf install_temp
88 mkdir -p install_temp/lib/$(ANDROID_ABI) 110 mkdir -p install_temp/lib/$(ANDROID_ABI)
@@ -106,6 +128,9 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
106 rm -rf $${subdir}/[mM]akefile*[.-]in ; \ 128 rm -rf $${subdir}/[mM]akefile*[.-]in ; \
107 rm -rf $${subdir}/Makefile; \ 129 rm -rf $${subdir}/Makefile; \
108 done 130 done
131# Generate the directory tree for those directories.
132 $(libsrc)/asset-directory-tool install_temp/assets \
133 install_temp/assets/directory-tree
109# Install architecture dependents to lib/$(ANDROID_ABI). This 134# Install architecture dependents to lib/$(ANDROID_ABI). This
110# perculiar naming scheme is required to make Android preserve these 135# perculiar naming scheme is required to make Android preserve these
111# binaries upon installation. 136# binaries upon installation.
@@ -120,10 +145,12 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
120 cp -f $$file install_temp/lib/$(ANDROID_ABI); \ 145 cp -f $$file install_temp/lib/$(ANDROID_ABI); \
121 fi \ 146 fi \
122 done 147 done
123# Package everything. 148# Package everything. Specifying the assets on this command line is
124 $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml 149# necessary for AAssetManager_getNextFileName to work on old versions
150# of Android.
151 $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml \
152 -A install_temp/assets
125 pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd 153 pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
126 pushd install_temp; $(AAPT) add ../$@ `find assets -type f`; popd
127 rm -rf install_temp 154 rm -rf install_temp
128 155
129# Makefile itself. 156# Makefile itself.
diff --git a/java/debug.sh b/java/debug.sh
index aa80aeeebcd..7008664c049 100755
--- a/java/debug.sh
+++ b/java/debug.sh
@@ -93,7 +93,7 @@ while [ $# -gt 0 ]; do
93 shift 93 shift
94done 94done
95 95
96if [ -z $devices ]; then 96if [ -z "$devices" ]; then
97 echo "No devices are available." 97 echo "No devices are available."
98 exit 1 98 exit 1
99fi 99fi
@@ -117,25 +117,43 @@ if [ -z $app_data_dir ]; then
117 echo "Is it installed?" 117 echo "Is it installed?"
118fi 118fi
119 119
120echo "Found application data directory at $app_data_dir..." 120echo "Found application data directory at" "$app_data_dir"
121 121
122# Find which PIDs are associated with org.gnu.emacs 122# Generate an awk script to extract PIDs from Android ps output. It
123package_uid=`adb -s $device shell run-as $package id -u` 123# is enough to run `ps' as the package user on newer versions of
124 124# Android, but that doesn't work on Android 2.3.
125if [ -z $package_uid ]; then 125cat << EOF > tmp.awk
126 echo "Failed to obtain UID of packages named $package" 126BEGIN {
127 exit 1 127 pid = 0;
128fi 128 pid_column = 2;
129 129}
130# First, run ps -u $package_uid -o PID,CMD to fetch the list of 130
131# process IDs. 131{
132package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD` 132 # Remove any trailing carriage return from the input line.
133 133 gsub ("\r", "", \$NF)
134# Next, remove lines matching "ps" itself. 134
135package_pids=`awk -- '{ 135 # If this is line 1, figure out which column contains the PID.
136 if (!match ($0, /(PID|ps)/)) 136 if (NR == 1)
137 print $1 137 {
138}' <<< $package_pids` 138 for (n = 1; n <= NF; ++n)
139 {
140 if (\$n == "PID")
141 pid_column=n;
142 }
143 }
144 else if (\$NF == "$package")
145 print \$pid_column
146}
147EOF
148
149# Make sure that file disappears once this script exits.
150trap "rm -f $(pwd)/tmp.awk" 0
151
152# First, run ps to fetch the list of process IDs.
153package_pids=`adb -s $device shell ps`
154
155# Next, extract the list of PIDs currently running.
156package_pids=`awk -f tmp.awk <<< $package_pids`
139 157
140if [ "$attach_existing" != "yes" ]; then 158if [ "$attach_existing" != "yes" ]; then
141 # Finally, kill each existing process. 159 # Finally, kill each existing process.
@@ -149,19 +167,20 @@ if [ "$attach_existing" != "yes" ]; then
149 echo "Starting activity $activity and attaching debugger" 167 echo "Starting activity $activity and attaching debugger"
150 168
151 # Exit if the activity could not be started. 169 # Exit if the activity could not be started.
152 adb -s $device shell am start -D "$package/$activity" 170 adb -s $device shell am start -D -n "$package/$activity"
153 if [ ! $? ]; then 171 if [ ! $? ]; then
154 exit 1; 172 exit 1;
155 fi 173 fi
156 174
175 # Sleep for a bit. Otherwise, the process may not have started
176 # yet.
177 sleep 1
178
157 # Now look for processes matching the package again. 179 # Now look for processes matching the package again.
158 package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD` 180 package_pids=`adb -s $device shell ps`
159 181
160 # Next, remove lines matching "ps" itself. 182 # Next, remove lines matching "ps" itself.
161 package_pids=`awk -- '{ 183 package_pids=`awk -f tmp.awk <<< $package_pids`
162 if (!match ($0, /(PID|ps)/))
163 print $1
164}' <<< $package_pids`
165fi 184fi
166 185
167pid=$package_pids 186pid=$package_pids
@@ -170,10 +189,10 @@ num_pids=`wc -w <<< "$package_pids"`
170if [ $num_pids -gt 1 ]; then 189if [ $num_pids -gt 1 ]; then
171 echo "More than one process was started:" 190 echo "More than one process was started:"
172 echo "" 191 echo ""
173 adb -s $device shell run-as $package ps -u $package_uid | awk -- '{ 192 adb -s $device shell run-as $package ps | awk -- "{
174 if (!match ($0, /ps/)) 193 if (!match (\$0, /ps/) && match (\$0, /$package/))
175 print $0 194 print \$0
176 }' 195 }"
177 echo "" 196 echo ""
178 printf "Which one do you want to attach to? " 197 printf "Which one do you want to attach to? "
179 read pid 198 read pid
@@ -182,10 +201,12 @@ elif [ -z $package_pids ]; then
182 exit 1 201 exit 1
183fi 202fi
184 203
185# This isn't necessary when attaching gdb to an existing process. 204# If either --jdb was specified or debug.sh is not connecting to an
205# existing process, then store a suitable JDB invocation in
206# jdb_command. GDB will then run JDB to unblock the application from
207# the wait dialog after startup.
208
186if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then 209if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
187 # Start JDB to make the wait dialog disappear.
188 echo "Attaching JDB to unblock the application."
189 adb -s $device forward --remove-all 210 adb -s $device forward --remove-all
190 adb -s $device forward "tcp:$jdb_port" "jdwp:$pid" 211 adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
191 212
@@ -203,20 +224,42 @@ if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
203 $jdb_command 224 $jdb_command
204 exit 1 225 exit 1
205 fi 226 fi
227fi
206 228
207 exec 4<> /tmp/file-descriptor-stamp 229if [ -n "$jdb_command" ]; then
230 echo "Starting JDB to unblock application."
208 231
209 # Now run JDB with IO redirected to file descriptor 4 in a subprocess. 232 # Start JDB to unblock the application.
210 $jdb_command <&4 >&4 & 233 coproc JDB { $jdb_command; }
211 234
212 character= 235 # Tell JDB to first suspend all threads.
213 # Next, wait until the prompt is found. 236 echo "suspend" >&${JDB[1]}
214 while read -n1 -u 4 character; do 237
215 if [ "$character" = ">" ]; then 238 # Tell JDB to print a magic string once the program is
216 echo "JDB attached successfully" 239 # initialized.
217 break; 240 echo "print \"__verify_jdb_has_started__\"" >&${JDB[1]}
241
242 # Now wait for JDB to give the string back.
243 line=
244 while :; do
245 read -u ${JDB[0]} line
246 if [ ! $? ]; then
247 echo "Failed to read JDB output"
248 exit 1
218 fi 249 fi
250
251 case "$line" in
252 *__verify_jdb_has_started__*)
253 # Android only polls for a Java debugger every 200ms, so
254 # the debugger must be connected for at least that long.
255 echo "Pausing 1 second for the program to continue."
256 sleep 1
257 break
258 ;;
259 esac
219 done 260 done
261
262 # Note that JDB does not exit until GDB is fully attached!
220fi 263fi
221 264
222# See if gdbserver has to be uploaded 265# See if gdbserver has to be uploaded
@@ -234,18 +277,19 @@ fi
234 277
235echo "Attaching gdbserver to $pid on $device..." 278echo "Attaching gdbserver to $pid on $device..."
236exec 5<> /tmp/file-descriptor-stamp 279exec 5<> /tmp/file-descriptor-stamp
280rm -f /tmp/file-descriptor-stamp
237 281
238if [ -z "$gdbserver" ]; then 282if [ -z "$gdbserver" ]; then
239 adb -s $device shell run-as $package $gdbserver_bin --once \ 283 adb -s $device shell run-as $package $gdbserver_bin --once \
240 "+debug.$package_uid.socket" --attach $pid >&5 & 284 "+debug.$package.socket" --attach $pid >&5 &
241 gdb_socket="localfilesystem:$app_data_dir/debug.$package_uid.socket" 285 gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
242else 286else
243 # Normally the program cannot access $gdbserver_bin when it is 287 # Normally the program cannot access $gdbserver_bin when it is
244 # placed in /data/local/tmp. 288 # placed in /data/local/tmp.
245 adb -s $device shell $gdbserver_bin --once \ 289 adb -s $device shell $gdbserver_bin --once \
246 "+/data/local/tmp/debug.$package_uid.socket" \ 290 "+/data/local/tmp/debug.$package.socket" \
247 --attach $pid >&5 & 291 --attach $pid >&5 &
248 gdb_socket="localfilesystem:/data/local/tmp/debug.$package_uid.socket" 292 gdb_socket="localfilesystem:/data/local/tmp/debug.$package.socket"
249fi 293fi
250 294
251# Wait until gdbserver successfully runs. 295# Wait until gdbserver successfully runs.
@@ -256,7 +300,7 @@ while read -u 5 line; do
256 break; 300 break;
257 ;; 301 ;;
258 *error* | *Error* | failed ) 302 *error* | *Error* | failed )
259 echo $line 303 echo "GDB error:" $line
260 exit 1 304 exit 1
261 ;; 305 ;;
262 * ) 306 * )
@@ -264,19 +308,18 @@ while read -u 5 line; do
264 esac 308 esac
265done 309done
266 310
267if [ "$attach_existing" != "yes" ]; then 311# Now that GDB is attached, tell the Java debugger to resume execution
268 # Send EOF to JDB to make it go away. This will also cause 312# and then exit.
269 # Android to allow Emacs to continue executing. 313
270 echo "Making JDB go away..." 314if [ -n "$jdb_command" ]; then
271 echo "exit" >&4 315 echo "resume" >&${JDB[1]}
272 read -u 4 line 316 echo "exit" >&${JDB[1]}
273 echo "JDB has gone away with $line"
274fi 317fi
275 318
276# Forward the gdb server port here. 319# Forward the gdb server port here.
277adb -s $device forward "tcp:$gdb_port" $gdb_socket 320adb -s $device forward "tcp:$gdb_port" $gdb_socket
278if [ ! $? ]; then 321if [ ! $? ]; then
279 echo "Failed to forward $app_data_dir/debug.$package_uid.socket" 322 echo "Failed to forward $app_data_dir/debug.$package.socket"
280 echo "to $gdb_port! Perhaps you need to specify a different port" 323 echo "to $gdb_port! Perhaps you need to specify a different port"
281 echo "with --port?" 324 echo "with --port?"
282 exit 1; 325 exit 1;
@@ -284,4 +327,4 @@ fi
284 327
285# Finally, start gdb with any extra arguments needed. 328# Finally, start gdb with any extra arguments needed.
286cd "$oldpwd" 329cd "$oldpwd"
287gdb --eval-command "" --eval-command "target remote localhost:$gdb_port" $gdbargs 330gdb --eval-command "target remote localhost:$gdb_port" $gdbargs
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
index 00e204c9949..ac67ebe4aa0 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -168,10 +168,22 @@ public class EmacsContextMenu
168 { 168 {
169 if (item.subMenu != null) 169 if (item.subMenu != null)
170 { 170 {
171 /* This is a submenu. Create the submenu and add the 171 try
172 contents of the menu to it. */ 172 {
173 submenu = menu.addSubMenu (item.itemName); 173 /* This is a submenu. On versions of Android which
174 item.subMenu.inflateMenuItems (submenu); 174 support doing so, create the submenu and add the
175 contents of the menu to it. */
176 submenu = menu.addSubMenu (item.itemName);
177 }
178 catch (UnsupportedOperationException exception)
179 {
180 /* This version of Android has a restriction
181 preventing submenus from being added to submenus.
182 Inflate everything into the parent menu
183 instead. */
184 item.subMenu.inflateMenuItems (menu);
185 continue;
186 }
175 187
176 /* This is still needed to set wasSubmenuSelected. */ 188 /* This is still needed to set wasSubmenuSelected. */
177 menuItem = submenu.getItem (); 189 menuItem = submenu.getItem ();
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java
index 5d72a7860c8..7a97d706794 100644
--- a/java/org/gnu/emacs/EmacsCopyArea.java
+++ b/java/org/gnu/emacs/EmacsCopyArea.java
@@ -66,19 +66,11 @@ public class EmacsCopyArea
66 66
67 paint = gc.gcPaint; 67 paint = gc.gcPaint;
68 68
69 canvas = destination.lockCanvas (); 69 canvas = destination.lockCanvas (gc);
70 70
71 if (canvas == null) 71 if (canvas == null)
72 return; 72 return;
73 73
74 canvas.save ();
75
76 if (gc.real_clip_rects != null)
77 {
78 for (i = 0; i < gc.real_clip_rects.length; ++i)
79 canvas.clipRect (gc.real_clip_rects[i]);
80 }
81
82 /* A copy must be created or drawBitmap could end up overwriting 74 /* A copy must be created or drawBitmap could end up overwriting
83 itself. */ 75 itself. */
84 srcBitmap = source.getBitmap (); 76 srcBitmap = source.getBitmap ();
@@ -189,7 +181,6 @@ public class EmacsCopyArea
189 maskBitmap.recycle (); 181 maskBitmap.recycle ();
190 } 182 }
191 183
192 canvas.restore ();
193 destination.damageRect (rect); 184 destination.damageRect (rect);
194 } 185 }
195} 186}
diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java
index 5bc8efa5978..7d88a23c58f 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -168,9 +168,6 @@ public class EmacsDialog implements DialogInterface.OnDismissListener
168 button = buttons.get (1); 168 button = buttons.get (1);
169 dialog.setButton (DialogInterface.BUTTON_NEUTRAL, 169 dialog.setButton (DialogInterface.BUTTON_NEUTRAL,
170 button.name, button); 170 button.name, button);
171 buttonView
172 = dialog.getButton (DialogInterface.BUTTON_NEUTRAL);
173 buttonView.setEnabled (button.enabled);
174 } 171 }
175 172
176 if (size >= 3) 173 if (size >= 3)
diff --git a/java/org/gnu/emacs/EmacsDrawLine.java b/java/org/gnu/emacs/EmacsDrawLine.java
index 8941d4c217f..827feb96dfb 100644
--- a/java/org/gnu/emacs/EmacsDrawLine.java
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -49,19 +49,11 @@ public class EmacsDrawLine
49 Math.min (y, y2 + 1), 49 Math.min (y, y2 + 1),
50 Math.max (x2 + 1, x), 50 Math.max (x2 + 1, x),
51 Math.max (y2 + 1, y)); 51 Math.max (y2 + 1, y));
52 canvas = drawable.lockCanvas (); 52 canvas = drawable.lockCanvas (gc);
53 53
54 if (canvas == null) 54 if (canvas == null)
55 return; 55 return;
56 56
57 canvas.save ();
58
59 if (gc.real_clip_rects != null)
60 {
61 for (i = 0; i < gc.real_clip_rects.length; ++i)
62 canvas.clipRect (gc.real_clip_rects[i]);
63 }
64
65 paint.setStyle (Paint.Style.STROKE); 57 paint.setStyle (Paint.Style.STROKE);
66 58
67 if (gc.clip_mask == null) 59 if (gc.clip_mask == null)
@@ -71,7 +63,6 @@ public class EmacsDrawLine
71 63
72 /* DrawLine with clip mask not implemented; it is not used by 64 /* DrawLine with clip mask not implemented; it is not used by
73 Emacs. */ 65 Emacs. */
74 canvas.restore ();
75 drawable.damageRect (rect); 66 drawable.damageRect (rect);
76 } 67 }
77} 68}
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
index c29d413f66e..695a8c6ea44 100644
--- a/java/org/gnu/emacs/EmacsDrawRectangle.java
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -23,6 +23,7 @@ import android.graphics.Bitmap;
23import android.graphics.Canvas; 23import android.graphics.Canvas;
24import android.graphics.Paint; 24import android.graphics.Paint;
25import android.graphics.Rect; 25import android.graphics.Rect;
26import android.graphics.RectF;
26 27
27import android.util.Log; 28import android.util.Log;
28 29
@@ -36,51 +37,31 @@ public class EmacsDrawRectangle
36 Paint maskPaint, paint; 37 Paint maskPaint, paint;
37 Canvas maskCanvas; 38 Canvas maskCanvas;
38 Bitmap maskBitmap; 39 Bitmap maskBitmap;
40 Rect rect;
39 Rect maskRect, dstRect; 41 Rect maskRect, dstRect;
40 Canvas canvas; 42 Canvas canvas;
41 Bitmap clipBitmap; 43 Bitmap clipBitmap;
42 Rect clipRect;
43 44
44 /* TODO implement stippling. */ 45 /* TODO implement stippling. */
45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 46 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
46 return; 47 return;
47 48
48 canvas = drawable.lockCanvas (); 49 canvas = drawable.lockCanvas (gc);
49 50
50 if (canvas == null) 51 if (canvas == null)
51 return; 52 return;
52 53
53 canvas.save ();
54
55 if (gc.real_clip_rects != null)
56 {
57 for (i = 0; i < gc.real_clip_rects.length; ++i)
58 canvas.clipRect (gc.real_clip_rects[i]);
59 }
60
61 /* Clip to the clipRect because some versions of Android draw an
62 overly wide line. */
63 clipRect = new Rect (x, y, x + width + 1,
64 y + height + 1);
65 canvas.clipRect (clipRect);
66
67 paint = gc.gcPaint; 54 paint = gc.gcPaint;
55 paint.setStyle (Paint.Style.STROKE);
56 rect = new Rect (x, y, x + width, y + height);
68 57
69 if (gc.clip_mask == null) 58 if (gc.clip_mask == null)
70 { 59 /* Use canvas.drawRect with a RectF. That seems to reliably
71 /* canvas.drawRect just doesn't work on Android, producing 60 get PostScript behavior. */
72 different results on various devices. Do a 5 point 61 canvas.drawRect (new RectF (x + 0.5f, y + 0.5f,
73 PolyLine instead. */ 62 x + width + 0.5f,
74 canvas.drawLine ((float) x, (float) y, (float) x + width, 63 y + height + 0.5f),
75 (float) y, paint); 64 paint);
76 canvas.drawLine ((float) x + width, (float) y,
77 (float) x + width, (float) y + height,
78 paint);
79 canvas.drawLine ((float) x + width, (float) y + height,
80 (float) x, (float) y + height, paint);
81 canvas.drawLine ((float) x, (float) y + height,
82 (float) x, (float) y, paint);
83 }
84 else 65 else
85 { 66 {
86 /* Drawing with a clip mask involves calculating the 67 /* Drawing with a clip mask involves calculating the
@@ -137,7 +118,7 @@ public class EmacsDrawRectangle
137 maskBitmap.recycle (); 118 maskBitmap.recycle ();
138 } 119 }
139 120
140 canvas.restore (); 121 drawable.damageRect (new Rect (x, y, x + width + 1,
141 drawable.damageRect (clipRect); 122 y + height + 1));
142 } 123 }
143} 124}
diff --git a/java/org/gnu/emacs/EmacsDrawable.java b/java/org/gnu/emacs/EmacsDrawable.java
index 6a6199ff214..f2f8885e976 100644
--- a/java/org/gnu/emacs/EmacsDrawable.java
+++ b/java/org/gnu/emacs/EmacsDrawable.java
@@ -25,7 +25,7 @@ import android.graphics.Canvas;
25 25
26public interface EmacsDrawable 26public interface EmacsDrawable
27{ 27{
28 public Canvas lockCanvas (); 28 public Canvas lockCanvas (EmacsGC gc);
29 public void damageRect (Rect damageRect); 29 public void damageRect (Rect damageRect);
30 public Bitmap getBitmap (); 30 public Bitmap getBitmap ();
31 public boolean isDestroyed (); 31 public boolean isDestroyed ();
diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java
index 42b73886dff..22e2dd0d8a9 100644
--- a/java/org/gnu/emacs/EmacsFillPolygon.java
+++ b/java/org/gnu/emacs/EmacsFillPolygon.java
@@ -41,21 +41,13 @@ public class EmacsFillPolygon
41 RectF rectF; 41 RectF rectF;
42 int i; 42 int i;
43 43
44 canvas = drawable.lockCanvas (); 44 canvas = drawable.lockCanvas (gc);
45 45
46 if (canvas == null) 46 if (canvas == null)
47 return; 47 return;
48 48
49 paint = gc.gcPaint; 49 paint = gc.gcPaint;
50 50
51 canvas.save ();
52
53 if (gc.real_clip_rects != null)
54 {
55 for (i = 0; i < gc.real_clip_rects.length; ++i)
56 canvas.clipRect (gc.real_clip_rects[i]);
57 }
58
59 /* Build the path from the given array of points. */ 51 /* Build the path from the given array of points. */
60 path = new Path (); 52 path = new Path ();
61 53
@@ -83,7 +75,6 @@ public class EmacsFillPolygon
83 if (gc.clip_mask == null) 75 if (gc.clip_mask == null)
84 canvas.drawPath (path, paint); 76 canvas.drawPath (path, paint);
85 77
86 canvas.restore ();
87 drawable.damageRect (rect); 78 drawable.damageRect (rect);
88 79
89 /* FillPolygon with clip mask not implemented; it is not used by 80 /* FillPolygon with clip mask not implemented; it is not used by
diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java
index 7cc55d3db96..aed0a540c8f 100644
--- a/java/org/gnu/emacs/EmacsFillRectangle.java
+++ b/java/org/gnu/emacs/EmacsFillRectangle.java
@@ -32,7 +32,6 @@ public class EmacsFillRectangle
32 perform (EmacsDrawable drawable, EmacsGC gc, 32 perform (EmacsDrawable drawable, EmacsGC gc,
33 int x, int y, int width, int height) 33 int x, int y, int width, int height)
34 { 34 {
35 int i;
36 Paint maskPaint, paint; 35 Paint maskPaint, paint;
37 Canvas maskCanvas; 36 Canvas maskCanvas;
38 Bitmap maskBitmap; 37 Bitmap maskBitmap;
@@ -45,19 +44,11 @@ public class EmacsFillRectangle
45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 44 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
46 return; 45 return;
47 46
48 canvas = drawable.lockCanvas (); 47 canvas = drawable.lockCanvas (gc);
49 48
50 if (canvas == null) 49 if (canvas == null)
51 return; 50 return;
52 51
53 canvas.save ();
54
55 if (gc.real_clip_rects != null)
56 {
57 for (i = 0; i < gc.real_clip_rects.length; ++i)
58 canvas.clipRect (gc.real_clip_rects[i]);
59 }
60
61 paint = gc.gcPaint; 52 paint = gc.gcPaint;
62 rect = new Rect (x, y, x + width, y + height); 53 rect = new Rect (x, y, x + width, y + height);
63 54
@@ -120,7 +111,6 @@ public class EmacsFillRectangle
120 maskBitmap.recycle (); 111 maskBitmap.recycle ();
121 } 112 }
122 113
123 canvas.restore ();
124 drawable.damageRect (rect); 114 drawable.damageRect (rect);
125 } 115 }
126} 116}
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
index c579625f3f7..bdc27a1ca5b 100644
--- a/java/org/gnu/emacs/EmacsGC.java
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -47,6 +47,14 @@ public class EmacsGC extends EmacsHandleObject
47 public EmacsPixmap clip_mask, stipple; 47 public EmacsPixmap clip_mask, stipple;
48 public Paint gcPaint; 48 public Paint gcPaint;
49 49
50 /* ID incremented every time the clipping rectangles of any GC
51 changes. */
52 private static long clip_serial;
53
54 /* The value of clipRectID after the last time this GCs clip
55 rectangles changed. 0 if there are no clip rectangles. */
56 public long clipRectID;
57
50 static 58 static
51 { 59 {
52 xorAlu = new PorterDuffXfermode (Mode.XOR); 60 xorAlu = new PorterDuffXfermode (Mode.XOR);
@@ -75,23 +83,28 @@ public class EmacsGC extends EmacsHandleObject
75 recompute real_clip_rects. */ 83 recompute real_clip_rects. */
76 84
77 public void 85 public void
78 markDirty () 86 markDirty (boolean clipRectsChanged)
79 { 87 {
80 int i; 88 int i;
81 89
82 if ((ts_origin_x != 0 || ts_origin_y != 0) 90 if (clipRectsChanged)
83 && clip_rects != null)
84 { 91 {
85 real_clip_rects = new Rect[clip_rects.length]; 92 if ((ts_origin_x != 0 || ts_origin_y != 0)
86 93 && clip_rects != null)
87 for (i = 0; i < clip_rects.length; ++i)
88 { 94 {
89 real_clip_rects[i] = new Rect (clip_rects[i]); 95 real_clip_rects = new Rect[clip_rects.length];
90 real_clip_rects[i].offset (ts_origin_x, ts_origin_y); 96
97 for (i = 0; i < clip_rects.length; ++i)
98 {
99 real_clip_rects[i] = new Rect (clip_rects[i]);
100 real_clip_rects[i].offset (ts_origin_x, ts_origin_y);
101 }
91 } 102 }
103 else
104 real_clip_rects = clip_rects;
105
106 clipRectID = ++clip_serial;
92 } 107 }
93 else
94 real_clip_rects = clip_rects;
95 108
96 gcPaint.setStrokeWidth (1f); 109 gcPaint.setStrokeWidth (1f);
97 gcPaint.setColor (foreground | 0xff000000); 110 gcPaint.setColor (foreground | 0xff000000);
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java
index 85931c2abd4..a83d8f25542 100644
--- a/java/org/gnu/emacs/EmacsPixmap.java
+++ b/java/org/gnu/emacs/EmacsPixmap.java
@@ -42,6 +42,14 @@ public class EmacsPixmap extends EmacsHandleObject
42 /* The canvas used to draw to BITMAP. */ 42 /* The canvas used to draw to BITMAP. */
43 public Canvas canvas; 43 public Canvas canvas;
44 44
45 /* Whether or not GC should be explicitly triggered upon
46 release. */
47 private boolean needCollect;
48
49 /* ID used to determine whether or not the GC clip rects
50 changed. */
51 private long gcClipRectID;
52
45 public 53 public
46 EmacsPixmap (short handle, int colors[], int width, 54 EmacsPixmap (short handle, int colors[], int width,
47 int height, int depth) 55 int height, int depth)
@@ -83,18 +91,41 @@ public class EmacsPixmap extends EmacsHandleObject
83 switch (depth) 91 switch (depth)
84 { 92 {
85 case 1: 93 case 1:
86 bitmap = Bitmap.createBitmap (width, height, 94 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
87 Bitmap.Config.ALPHA_8, 95 bitmap = Bitmap.createBitmap (width, height,
88 false); 96 Bitmap.Config.ALPHA_8,
97 false);
98 else
99 bitmap = Bitmap.createBitmap (width, height,
100 Bitmap.Config.ALPHA_8);
89 break; 101 break;
90 102
91 case 24: 103 case 24:
92 bitmap = Bitmap.createBitmap (width, height, 104
93 Bitmap.Config.ARGB_8888, 105 /* Emacs doesn't just use the first kind of `createBitmap'
94 false); 106 because the latter allows specifying that the pixmap is
107 always opaque, which really increases efficiency. */
108 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
109 bitmap = Bitmap.createBitmap (width, height,
110 Bitmap.Config.ARGB_8888);
111 else
112 bitmap = Bitmap.createBitmap (width, height,
113 Bitmap.Config.ARGB_8888,
114 false);
95 break; 115 break;
96 } 116 }
97 117
118 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1)
119 /* On these old versions of Android, Bitmap.recycle frees bitmap
120 contents immediately. */
121 needCollect = false;
122 else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
123 needCollect = (bitmap.getByteCount ()
124 >= 1024 * 512);
125 else
126 needCollect = (bitmap.getAllocationByteCount ()
127 >= 1024 * 512);
128
98 bitmap.eraseColor (0xff000000); 129 bitmap.eraseColor (0xff000000);
99 130
100 this.width = width; 131 this.width = width;
@@ -104,11 +135,32 @@ public class EmacsPixmap extends EmacsHandleObject
104 135
105 @Override 136 @Override
106 public Canvas 137 public Canvas
107 lockCanvas () 138 lockCanvas (EmacsGC gc)
108 { 139 {
140 int i;
141
109 if (canvas == null) 142 if (canvas == null)
110 canvas = new Canvas (bitmap); 143 {
144 canvas = new Canvas (bitmap);
145 canvas.save ();
146 }
111 147
148 /* Now see if clipping has to be redone. */
149 if (gc.clipRectID == gcClipRectID)
150 return canvas;
151
152 /* It does have to be redone. Reapply gc.real_clip_rects. */
153 canvas.restore ();
154 canvas.save ();
155
156 if (gc.real_clip_rects != null)
157 {
158 for (i = 0; i < gc.real_clip_rects.length; ++i)
159 canvas.clipRect (gc.real_clip_rects[i]);
160 }
161
162 /* Save the clip rect ID again. */
163 gcClipRectID = gc.clipRectID;
112 return canvas; 164 return canvas;
113 } 165 }
114 166
@@ -130,15 +182,6 @@ public class EmacsPixmap extends EmacsHandleObject
130 public void 182 public void
131 destroyHandle () 183 destroyHandle ()
132 { 184 {
133 boolean needCollect;
134
135 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
136 needCollect = (bitmap.getByteCount ()
137 >= 1024 * 512);
138 else
139 needCollect = (bitmap.getAllocationByteCount ()
140 >= 1024 * 512);
141
142 bitmap.recycle (); 185 bitmap.recycle ();
143 bitmap = null; 186 bitmap = null;
144 187
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
index c0f24c7433a..a964cadb74c 100644
--- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -510,20 +510,12 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
510 backgroundRect.right = x + backgroundWidth; 510 backgroundRect.right = x + backgroundWidth;
511 backgroundRect.bottom = y + sdk7FontObject.descent; 511 backgroundRect.bottom = y + sdk7FontObject.descent;
512 512
513 canvas = drawable.lockCanvas (); 513 canvas = drawable.lockCanvas (gc);
514 514
515 if (canvas == null) 515 if (canvas == null)
516 return 0; 516 return 0;
517 517
518 canvas.save ();
519 paint = gc.gcPaint; 518 paint = gc.gcPaint;
520
521 if (gc.real_clip_rects != null)
522 {
523 for (i = 0; i < gc.real_clip_rects.length; ++i)
524 canvas.clipRect (gc.real_clip_rects[i]);
525 }
526
527 paint.setStyle (Paint.Style.FILL); 519 paint.setStyle (Paint.Style.FILL);
528 520
529 if (withBackground) 521 if (withBackground)
@@ -538,7 +530,6 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
538 paint.setAntiAlias (true); 530 paint.setAntiAlias (true);
539 canvas.drawText (charsArray, 0, chars.length, x, y, paint); 531 canvas.drawText (charsArray, 0, chars.length, x, y, paint);
540 532
541 canvas.restore ();
542 bounds = new Rect (); 533 bounds = new Rect ();
543 paint.getTextBounds (charsArray, 0, chars.length, bounds); 534 paint.getTextBounds (charsArray, 0, chars.length, bounds);
544 bounds.offset (x, y); 535 bounds.offset (x, y);
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index ca38f93dc98..bcf8d9ff6e8 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -175,7 +175,12 @@ public class EmacsService extends Service
175 { 175 {
176 view.thing = new EmacsView (window); 176 view.thing = new EmacsView (window);
177 view.thing.setVisibility (visibility); 177 view.thing.setVisibility (visibility);
178 view.thing.setFocusedByDefault (isFocusedByDefault); 178
179 /* The following function is only present on Android 26
180 or later. */
181 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
182 view.thing.setFocusedByDefault (isFocusedByDefault);
183
179 notify (); 184 notify ();
180 } 185 }
181 } 186 }
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 6137fd74a7f..82f44acaebe 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -83,6 +83,9 @@ public class EmacsView extends ViewGroup
83 /* The last measured width and height. */ 83 /* The last measured width and height. */
84 private int measuredWidth, measuredHeight; 84 private int measuredWidth, measuredHeight;
85 85
86 /* The serial of the last clip rectangle change. */
87 private long lastClipSerial;
88
86 public 89 public
87 EmacsView (EmacsWindow window) 90 EmacsView (EmacsWindow window)
88 { 91 {
@@ -105,10 +108,6 @@ public class EmacsView extends ViewGroup
105 on Android? */ 108 on Android? */
106 setChildrenDrawingOrderEnabled (true); 109 setChildrenDrawingOrderEnabled (true);
107 110
108 /* Get rid of the foreground and background tint. */
109 setBackgroundTintList (null);
110 setForegroundTintList (null);
111
112 /* Get rid of the default focus highlight. */ 111 /* Get rid of the default focus highlight. */
113 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) 112 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
114 setDefaultFocusHighlightEnabled (false); 113 setDefaultFocusHighlightEnabled (false);
@@ -145,6 +144,11 @@ public class EmacsView extends ViewGroup
145 144
146 /* And canvases. */ 145 /* And canvases. */
147 canvas = new Canvas (bitmap); 146 canvas = new Canvas (bitmap);
147 canvas.save ();
148
149 /* Since the clip rectangles have been cleared, clear the clip
150 rectangle ID. */
151 lastClipSerial = 0;
148 152
149 /* Copy over the contents of the old bitmap. */ 153 /* Copy over the contents of the old bitmap. */
150 if (oldBitmap != null) 154 if (oldBitmap != null)
@@ -177,11 +181,31 @@ public class EmacsView extends ViewGroup
177 } 181 }
178 182
179 public synchronized Canvas 183 public synchronized Canvas
180 getCanvas () 184 getCanvas (EmacsGC gc)
181 { 185 {
186 int i;
187
182 if (bitmapDirty || bitmap == null) 188 if (bitmapDirty || bitmap == null)
183 handleDirtyBitmap (); 189 handleDirtyBitmap ();
184 190
191 if (canvas == null)
192 return null;
193
194 /* Update clip rectangles if necessary. */
195 if (gc.clipRectID != lastClipSerial)
196 {
197 canvas.restore ();
198 canvas.save ();
199
200 if (gc.real_clip_rects != null)
201 {
202 for (i = 0; i < gc.real_clip_rects.length; ++i)
203 canvas.clipRect (gc.real_clip_rects[i]);
204 }
205
206 lastClipSerial = gc.clipRectID;
207 }
208
185 return canvas; 209 return canvas;
186 } 210 }
187 211
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index f5b50f11f14..c5b1522086c 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -164,7 +164,7 @@ public class EmacsWindow extends EmacsHandleObject
164 { 164 {
165 /* scratchGC is used as the argument to a FillRectangles req. */ 165 /* scratchGC is used as the argument to a FillRectangles req. */
166 scratchGC.foreground = pixel; 166 scratchGC.foreground = pixel;
167 scratchGC.markDirty (); 167 scratchGC.markDirty (false);
168 } 168 }
169 169
170 public Rect 170 public Rect
@@ -466,9 +466,9 @@ public class EmacsWindow extends EmacsHandleObject
466 466
467 @Override 467 @Override
468 public Canvas 468 public Canvas
469 lockCanvas () 469 lockCanvas (EmacsGC gc)
470 { 470 {
471 return view.getCanvas (); 471 return view.getCanvas (gc);
472 } 472 }
473 473
474 @Override 474 @Override
@@ -512,37 +512,75 @@ public class EmacsWindow extends EmacsHandleObject
512 public void 512 public void
513 onKeyDown (int keyCode, KeyEvent event) 513 onKeyDown (int keyCode, KeyEvent event)
514 { 514 {
515 int state; 515 int state, state_1;
516 516
517 state = event.getModifiers (); 517 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
518 state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); 518 state = event.getModifiers ();
519 else
520 {
521 /* Replace this with getMetaState and manual
522 normalization. */
523 state = event.getMetaState ();
524
525 /* Normalize the state by setting the generic modifier bit if
526 either a left or right modifier is pressed. */
527
528 if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
529 || (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
530 state |= KeyEvent.META_ALT_MASK;
531
532 if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
533 || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
534 state |= KeyEvent.META_CTRL_MASK;
535 }
536
537 /* Ignore meta-state understood by Emacs for now, or Ctrl+C will
538 not be recognized as an ASCII key press event. */
539 state_1
540 = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
519 541
520 EmacsNative.sendKeyPress (this.handle, 542 EmacsNative.sendKeyPress (this.handle,
521 event.getEventTime (), 543 event.getEventTime (),
522 event.getModifiers (), 544 state, keyCode,
523 keyCode, 545 event.getUnicodeChar (state_1));
524 /* Ignore meta-state understood by Emacs 546 lastModifiers = state;
525 for now, or Ctrl+C will not be
526 recognized as an ASCII key press
527 event. */
528 event.getUnicodeChar (state));
529 lastModifiers = event.getModifiers ();
530 } 547 }
531 548
532 public void 549 public void
533 onKeyUp (int keyCode, KeyEvent event) 550 onKeyUp (int keyCode, KeyEvent event)
534 { 551 {
535 int state; 552 int state, state_1;
553
554 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
555 state = event.getModifiers ();
556 else
557 {
558 /* Replace this with getMetaState and manual
559 normalization. */
560 state = event.getMetaState ();
561
562 /* Normalize the state by setting the generic modifier bit if
563 either a left or right modifier is pressed. */
564
565 if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
566 || (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
567 state |= KeyEvent.META_ALT_MASK;
568
569 if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
570 || (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
571 state |= KeyEvent.META_CTRL_MASK;
572 }
536 573
537 state = event.getModifiers (); 574 /* Ignore meta-state understood by Emacs for now, or Ctrl+C will
538 state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); 575 not be recognized as an ASCII key press event. */
576 state_1
577 = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
539 578
540 EmacsNative.sendKeyRelease (this.handle, 579 EmacsNative.sendKeyRelease (this.handle,
541 event.getEventTime (), 580 event.getEventTime (),
542 event.getModifiers (), 581 state, keyCode,
543 keyCode, 582 event.getUnicodeChar (state_1));
544 event.getUnicodeChar (state)); 583 lastModifiers = state;
545 lastModifiers = event.getModifiers ();
546 } 584 }
547 585
548 public void 586 public void