1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-02-03 14:10:47 -08:00

Update Android port

* configure.ac (ANDROID_MIN_SDK): New variable.
(DX): Remove and replace with D8.
(XCONFIGURE): Check for the minimum version of Android the cross
compiler compiles for.  Generate java/AndroidManifest.xml from
java/AndroidManifest.xml.in.  Allow using Zlib on Android.

* java/AndroidManifest.xml.in: New file.  Use the minimum SDK
detected by configure.

* java/Makefile.in (top_srcdir, version): New variables.
(DX, D8): Replace with D8.
(ANDROID_MIN_SDK, APK_NAME): New variables.
(.PHONY):
(.PRECIOUS):
(classes.dex):
(emacs.apk): Generate $(APK_NAME) instead of `emacs.apk'.

* java/debug.sh: New option --attach-existing.  Attach to an
existing Emacs instance when specified.

* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): New
field `isPaused'.
(invalidateFocus1): Fix infinite recursion.
(detachWindow): Deiconify window.
(attachWindow): Iconify the window if the activity is paused.
(onCreate): Use the ``no title bar'' theme.
(onPause, onResume): New functions.
* java/org/gnu/emacs/EmacsNative.java (sendTouchUp, sendTouchDown)
(sendTouchMove, sendWheel, sendIconified, sendDeiconified): New
functions.
* java/org/gnu/emacs/EmacsSdk7FontDriver.java (Sdk7Typeface):
(list): Remove logging for code that is mostly going to be unused.
* java/org/gnu/emacs/EmacsService.java (ringBell, queryTree)
(getScreenWidth, getScreenHeight, detectMouse): New functions.
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView)
(surfaceChanged, surfaceCreated, surfaceDestroyed): Add extra
debug logging.  Avoid deadlock in surfaceCreated.

* java/org/gnu/emacs/EmacsView.java (EmacsView): Try very hard
to make the SurfaceView respect Z order.  It didn't work.
(handleDirtyBitmap): Copy over the contents from the old bitmap.
(explicitlyDirtyBitmap): New function.
(onLayout): Don't dirty bitmap if unnecessary.
(damageRect, swapBuffers): Don't synchronize so hard.
(onTouchEvent): Call window.onTouchEvent instead.
(moveChildToBack, raise, lower): New functions.

* java/org/gnu/emacs/EmacsWindow.java (Coordinate): New
subclass.
(pointerMap, isMapped, isIconified, dontFocusOnMap)
(dontAcceptFocus): New fields.
(EmacsWindow): Don't immediately register unmapped window.
(viewLayout): Send configure event outside the lock.
(requestViewLayout): Explicitly dirty the bitmap.
(mapWindow): Register the window now.  Respect dontFocusOnMap.
(unmapWindow): Unregister the window now.
(figureChange, onTouchEvent): New functions.
(onSomeKindOfMotionEvent): Handle scroll wheel events.
(reparentTo, makeInputFocus, raise, lower, getWindowGeometry)
(noticeIconified, noticeDeiconified, setDontAcceptFocus)
(setDontFocusOnMap, getDontFocusOnMap): New functions.
* java/org/gnu/emacs/EmacsWindowAttachmentManager.java
(registerWindow, detachWindow): Synchronize.
(noticeIconified, noticeDeiconified): New functions.
(copyWindows): New function.

* lisp/frame.el (frame-geometry, frame-edges)
(mouse-absolute-pixel-position, set-mouse-absolute-pixel-position)
(frame-list-z-order, frame-restack, display-mouse-p)
(display-monitor-attributes-list): Implement on Android.

* lisp/mwheel.el (mouse-wheel-down-event):
(mouse-wheel-up-event):
(mouse-wheel-left-event):
(mouse-wheel-right-event): Define on Android.

* src/android.c (struct android_emacs_service): New methods
`ringBell', `queryTree', `getScreenWidth', `getScreenHeight',
and `detectMouse'.
(struct android_event_queue, android_init_events)
(android_next_event, android_write_event): Remove write limit.
(android_file_access_p): Handle directories correcty.
(android_close): Fix coding style.
(android_fclose): New function.
(android_init_emacs_service): Initialize new methods.
(android_reparent_window): Implement function.
(android_bell, android_set_input_focus, android_raise_window)
(android_lower_window, android_query_tree, android_get_geometry)
(android_get_screen_width, android_get_screen_height)
(android_get_mm_width, android_get_mm_height, android_detect_mouse)
(android_set_dont_focus_on_map, android_set_dont_accept_focus):
New functions.
(struct android_dir): New structure.
(android_opendir, android_readdir, android_closedir): New
functions.
(emacs_abort): Implement here on Android and poke debuggerd into
generating a tombstone.

* src/android.h: Update prototypes.

* src/androidfns.c (android_set_parent_frame): New function.
(android_default_font_parameter): Use sane font size by default.
(Fx_display_pixel_width, Fx_display_pixel_height)
(Fx_display_mm_width, Fx_display_mm_height)
(Fx_display_monitor_attributes_list): Rename to start with
`android-'.  Implement.  Fiddle with documentation to introduce
Android specific nuances.
(Fandroid_display_monitor_attributes_list): New function.
(Fx_frame_geometry, frame_geometry): New function.
(Fandroid_frame_geometry): Implement correctly.
(Fx_frame_list_z_order): Rename to start with `android-'.
(android_frame_list_z_order, Fandroid_frame_list_z_order):
Implement.
(Fx_frame_restack): Rename to start with `android-'.
(Fandroid_frame_restack): ``Implement''.
(Fx_mouse_absolute_pixel_position): Rename to start with
`android-'.
(Fandroid_mouse_absolute_pixel_position): ``Implement''.
(Fx_set_mouse_absolute_pixel_position): Rename to start with
`android-'.
(Fandroid_set_mouse_absolute_pixel_position): ``Implement''.
(Fandroid_detect_mouse): New function.
(android_set_menu_bar_lines): Use FRAME_ANDROID_DRAWABLE when
clearing area.
(android_set_no_focus_on_map, android_set_no_accept_focus): New
functions.
(android_frame_parm_handlers): Register new frame parameter
handlers.
(syms_of_androidfns): Update appropriately.

* src/androidfont.c (androidfont_draw): Use
FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW.

* src/androidgui.h (enum android_event_type): New events.
(struct android_touch_event, struct android_wheel_event)
(struct android_iconify_event): New structures.
(union android_event): Add new events.

* src/androidterm.c (android_clear_frame): Use
FRAME_ANDROID_DRAWABLE instead of FRAME_ANDROID_WINDOW.
(android_flash, android_ring_bell): Implement bell ringing.
(android_toggle_invisible_pointer): Don't TODO function that
can't be implemented.
(show_back_buffer, android_flush_dirty_back_buffer_on): Check if
a buffer flip is required before doing the flip.
(android_lower_frame, android_raise_frame): Implement functions.
(android_update_tools, android_find_tool): New functions.
(handle_one_android_event): Handle new iconification, wheel and
touch events.
(android_read_socket): Implement pending-autoraise-frames.
(android_frame_up_to_date): Implement bell ringing.
(android_buffer_flipping_unblocked_hook): Check if a buffer flip
is required before doing the flip.
(android_focus_frame, android_frame_highlight)
(android_frame_unhighlight): New function.
(android_frame_rehighlight): Implement functions.
(android_iconify_frame): Always display error.
(android_set_alpha): Update commentary.
(android_free_frame_resources): Free frame touch points.
(android_scroll_run, android_flip_and_flush)
(android_clear_rectangle, android_draw_fringe_bitmap)
(android_draw_glyph_string_background, android_fill_triangle)
(android_clear_point, android_draw_relief_rect)
(android_draw_box_rect, android_draw_glyph_string_bg_rect)
(android_draw_image_foreground, android_draw_stretch_glyph_string)
(android_draw_underwave, android_draw_glyph_string_foreground)
(android_draw_composite_glyph_string_foreground)
(android_draw_glyphless_glyph_string_foreground)
(android_draw_glyph_string, android_clear_frame_area)
(android_clear_under_internal_border, android_draw_hollow_cursor)
(android_draw_bar_cursor, android_draw_vertical_window_border)
(android_draw_window_divider): Use FRAME_ANDROID_DRAWABLE
instead of FRAME_ANDROID_WINDOW for drawing operations.

* src/androidterm.h (struct android_touch_point): New structure.
(struct android_output): New fields.
(FRAME_ANDROID_NEED_BUFFER_FLIP): New macro.

* src/dired.c (emacs_readdir, open_directory)
(directory_files_internal_unwind, read_dirent)
(directory_files_internal, file_name_completion): Add
indirection over readdir and opendir.  Use android variants on
Android.

* src/dispnew.c (Fopen_termscript):
* src/fileio.c (fclose_unwind): Use emacs_fclose.
(Faccess_file): Call android_file_access_p.
(file_accessible_directory_p): Append right suffix to Android
assets directory.
(do_auto_save_unwind): Use emacs_fclose.
* src/keyboard.c (lispy_function_keys): Use right function key
for page up and page down.
(Fopen_dribble_file): Use emacs_fclose.

* src/lisp.h: New prototype emacs_fclose.

* src/lread.c (close_infile_unwind): Use emacs_fclose.

* src/sfnt.c (sfnt_curve_is_flat): Fix area-squared computation.
(sfnt_prepare_raster): Compute raster width and height
consistently with outline building.
(sfnt_build_outline_edges): Use the same offsets used to set
offy and offx.
(main): Adjust debug code.

* src/sfntfont-android.c (sfntfont_android_saturate32): Delete
function.
(sfntfont_android_blend, sfntfont_android_blendrgb): Remove
unnecessary debug code.
(sfntfont_android_composite_bitmap): Prevent out of bounds
write.
(sfntfont_android_put_glyphs): Use FRAME_ANDROID_DRAWABLE.
(init_sfntfont_android): Initialize Monospace Serif font to
something sensible.
* src/sfntfont.c (sfntfont_text_extents): Clear glyph metrics
before summing up pcm.
(sfntfont_draw): Use s->font instead of s->face->font.

* src/sysdep.c (emacs_fclose): Wrap around android_fclose on
android.

* src/term.c (Fsuspend_tty):
(delete_tty): Use emacs_fclose.
* src/verbose.mk.in (AM_V_DX): Replace with D8 version.
This commit is contained in:
Po Lu 2023-01-13 15:53:08 +08:00
parent 2fa5583d96
commit f9732131cf
33 changed files with 2815 additions and 351 deletions

View file

@ -87,12 +87,27 @@ public class EmacsView extends ViewGroup
/* Create the surface view. */
this.surfaceView = new EmacsSurfaceView (this);
this.surfaceView.setZOrderMediaOverlay (true);
addView (this.surfaceView);
/* Not sure exactly what this does but it makes things magically
work. Why is something as simple as XRaiseWindow so involved
on Android? */
setChildrenDrawingOrderEnabled (true);
/* Get rid of the foreground and background tint. */
setBackgroundTintList (null);
setForegroundTintList (null);
}
private void
handleDirtyBitmap ()
{
Bitmap oldBitmap;
/* Save the old bitmap. */
oldBitmap = bitmap;
/* Recreate the front and back buffer bitmaps. */
bitmap
= Bitmap.createBitmap (bitmapDirty.width (),
@ -103,12 +118,23 @@ public class EmacsView extends ViewGroup
/* And canvases. */
canvas = new Canvas (bitmap);
/* If Emacs is drawing to the bitmap right now from the
main thread, the image contents are lost until the next
ConfigureNotify and complete garbage. Sorry! */
/* Copy over the contents of the old bitmap. */
if (oldBitmap != null)
canvas.drawBitmap (oldBitmap, 0f, 0f, new Paint ());
bitmapDirty = null;
}
public synchronized void
explicitlyDirtyBitmap (Rect rect)
{
if (bitmapDirty == null
&& (bitmap == null
|| rect.width () != bitmap.getWidth ()
|| rect.height () != bitmap.getHeight ()))
bitmapDirty = rect;
}
public synchronized Bitmap
getBitmap ()
{
@ -168,25 +194,31 @@ public class EmacsView extends ViewGroup
View child;
Rect windowRect;
count = getChildCount ();
if (changed || mustReportLayout)
{
mustReportLayout = false;
window.viewLayout (left, top, right, bottom);
}
if (changed)
if (changed
/* Check that a change has really happened. */
&& (bitmapDirty == null
|| bitmapDirty.width () != right - left
|| bitmapDirty.height () != bottom - top))
bitmapDirty = new Rect (left, top, right, bottom);
count = getChildCount ();
for (i = 0; i < count; ++i)
{
child = getChildAt (i);
Log.d (TAG, "onLayout: " + child);
if (child == surfaceView)
/* The child is the surface view, so give it the entire
view. */
child.layout (left, top, right, bottom);
child.layout (0, 0, right - left, bottom - top);
else if (child.getVisibility () != GONE)
{
if (!(child instanceof EmacsView))
@ -201,59 +233,68 @@ public class EmacsView extends ViewGroup
}
}
public synchronized void
public void
damageRect (Rect damageRect)
{
damageRegion.union (damageRect);
synchronized (damageRegion)
{
damageRegion.union (damageRect);
}
}
/* This method is called from both the UI thread and the Emacs
thread. */
public synchronized void
public void
swapBuffers (boolean force)
{
Canvas canvas;
Rect damageRect;
Bitmap bitmap;
if (damageRegion.isEmpty ())
return;
/* Code must always take damageRegion, and then surfaceChangeLock,
never the other way around! */
bitmap = getBitmap ();
/* Emacs must take the following lock to ensure the access to the
canvas occurs with the surface created. Otherwise, Android
will throttle calls to lockCanvas. */
synchronized (surfaceView.surfaceChangeLock)
synchronized (damageRegion)
{
damageRect = damageRegion.getBounds ();
if (!surfaceView.isCreated ())
if (damageRegion.isEmpty ())
return;
if (bitmap == null)
return;
bitmap = getBitmap ();
/* Lock the canvas with the specified damage. */
canvas = surfaceView.lockCanvas (damageRect);
/* Emacs must take the following lock to ensure the access to the
canvas occurs with the surface created. Otherwise, Android
will throttle calls to lockCanvas. */
/* Return if locking the canvas failed. */
if (canvas == null)
return;
synchronized (surfaceView.surfaceChangeLock)
{
damageRect = damageRegion.getBounds ();
/* Copy from the back buffer to the canvas. If damageRect was
made empty, then draw the entire back buffer. */
if (!surfaceView.isCreated ())
return;
if (damageRect.isEmpty ())
canvas.drawBitmap (bitmap, 0f, 0f, paint);
else
canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
if (bitmap == null)
return;
/* Unlock the canvas and clear the damage. */
surfaceView.unlockCanvasAndPost (canvas);
damageRegion.setEmpty ();
/* Lock the canvas with the specified damage. */
canvas = surfaceView.lockCanvas (damageRect);
/* Return if locking the canvas failed. */
if (canvas == null)
return;
/* Copy from the back buffer to the canvas. If damageRect was
made empty, then draw the entire back buffer. */
if (damageRect.isEmpty ())
canvas.drawBitmap (bitmap, 0f, 0f, paint);
else
canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
/* Unlock the canvas and clear the damage. */
surfaceView.unlockCanvasAndPost (canvas);
damageRegion.setEmpty ();
}
}
}
@ -308,6 +349,78 @@ public class EmacsView extends ViewGroup
public boolean
onTouchEvent (MotionEvent motion)
{
return window.onSomeKindOfMotionEvent (motion);
return window.onTouchEvent (motion);
}
private void
moveChildToBack (View child)
{
int index;
index = indexOfChild (child);
if (index > 0)
{
detachViewFromParent (index);
/* The view at 0 is the surface view. */
attachViewToParent (child, 1,
child.getLayoutParams());
}
}
/* The following two functions must not be called if the view has no
parent, or is parented to an activity. */
public void
raise ()
{
EmacsView parent;
parent = (EmacsView) getParent ();
Log.d (TAG, "raise: parent " + parent);
if (parent.indexOfChild (this)
== parent.getChildCount () - 1)
return;
parent.bringChildToFront (this);
/* Yes, all of this is really necessary! */
parent.requestLayout ();
parent.invalidate ();
requestLayout ();
invalidate ();
/* The surface view must be destroyed and recreated. */
removeView (surfaceView);
addView (surfaceView, 0);
}
public void
lower ()
{
EmacsView parent;
parent = (EmacsView) getParent ();
Log.d (TAG, "lower: parent " + parent);
if (parent.indexOfChild (this) == 1)
return;
parent.moveChildToBack (this);
/* Yes, all of this is really necessary! */
parent.requestLayout ();
parent.invalidate ();
requestLayout ();
invalidate ();
/* The surface view must be removed and attached again. */
removeView (surfaceView);
addView (surfaceView, 0);
}
};