summaryrefslogtreecommitdiff
path: root/java/org/gnu/emacs/EmacsView.java
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-01-13 15:53:08 +0800
committerPo Lu <luangruo@yahoo.com>2023-01-13 15:53:08 +0800
commitf9732131cf3c67e24db74a3d49f256d3c189a7e3 (patch)
treee44e097c0c4c513390f58fa0020c8662943fbac6 /java/org/gnu/emacs/EmacsView.java
parent2fa5583d96fe78ff66d6fd41f18e54e4e20ea7d6 (diff)
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.
Diffstat (limited to 'java/org/gnu/emacs/EmacsView.java')
-rw-r--r--java/org/gnu/emacs/EmacsView.java189
1 files changed, 151 insertions, 38 deletions
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 169a1e42ee3..41acabab97b 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -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 ();
+ synchronized (damageRegion)
+ {
+ if (damageRegion.isEmpty ())
+ return;
- /* 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. */
+ bitmap = getBitmap ();
- synchronized (surfaceView.surfaceChangeLock)
- {
- damageRect = damageRegion.getBounds ();
+ /* 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. */
- if (!surfaceView.isCreated ())
- return;
+ synchronized (surfaceView.surfaceChangeLock)
+ {
+ damageRect = damageRegion.getBounds ();
- if (bitmap == null)
- return;
+ if (!surfaceView.isCreated ())
+ return;
- /* Lock the canvas with the specified damage. */
- canvas = surfaceView.lockCanvas (damageRect);
+ if (bitmap == null)
+ return;
- /* Return if locking the canvas failed. */
- if (canvas == null)
- return;
+ /* Lock the canvas with the specified damage. */
+ canvas = surfaceView.lockCanvas (damageRect);
- /* Copy from the back buffer to the canvas. If damageRect was
- made empty, then draw the entire back buffer. */
+ /* Return if locking the canvas failed. */
+ if (canvas == null)
+ return;
- if (damageRect.isEmpty ())
- canvas.drawBitmap (bitmap, 0f, 0f, paint);
- else
- canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
+ /* Copy from the back buffer to the canvas. If damageRect was
+ made empty, then draw the entire back buffer. */
- /* Unlock the canvas and clear the damage. */
- surfaceView.unlockCanvasAndPost (canvas);
- damageRegion.setEmpty ();
+ 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);
}
};