diff options
Diffstat (limited to 'java/org/gnu/emacs/EmacsView.java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java new file mode 100644 index 00000000000..237946d6366 --- /dev/null +++ b/java/org/gnu/emacs/EmacsView.java @@ -0,0 +1,211 @@ +/* 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.view.View; +import android.view.KeyEvent; +import android.view.ViewGroup; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.Paint; +import android.util.Log; + +import android.os.Build; + +/* This is an Android view which has a back and front buffer. When + swapBuffers is called, the back buffer is swapped to the front + buffer, and any damage is invalidated. frontBitmap and backBitmap + are modified and used both from the UI and the Emacs thread. As a + result, there is a lock held during all drawing operations. + + It is also a ViewGroup, as it also lays out children. */ + +public class EmacsView extends ViewGroup +{ + public static final String TAG = "EmacsView"; + + /* The associated EmacsWindow. */ + public EmacsWindow window; + + /* The buffer bitmap. */ + public Bitmap bitmap; + + /* The associated canvases. */ + public Canvas canvas; + + /* The damage region. */ + public Region damageRegion; + + /* The paint. */ + public Paint paint; + + /* The associated surface view. */ + private EmacsSurfaceView surfaceView; + + public + EmacsView (EmacsWindow window) + { + super (EmacsService.SERVICE); + + this.window = window; + this.damageRegion = new Region (); + this.paint = new Paint (); + + /* Create the surface view. */ + this.surfaceView = new EmacsSurfaceView (this); + + setFocusable (FOCUSABLE); + addView (this.surfaceView); + } + + @Override + protected void + onMeasure (int widthMeasureSpec, int heightMeasureSpec) + { + Rect measurements; + int width, height; + + /* Return the width and height of the window regardless of what + the parent says. */ + measurements = window.getGeometry (); + + width = measurements.width (); + height = measurements.height (); + + /* Now apply any extra requirements in widthMeasureSpec and + heightMeasureSpec. */ + + if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.EXACTLY) + width = MeasureSpec.getSize (widthMeasureSpec); + else if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.AT_MOST + && width > MeasureSpec.getSize (widthMeasureSpec)) + width = MeasureSpec.getSize (widthMeasureSpec); + + if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.EXACTLY) + height = MeasureSpec.getSize (heightMeasureSpec); + else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST + && height > MeasureSpec.getSize (heightMeasureSpec)) + height = MeasureSpec.getSize (heightMeasureSpec); + + super.setMeasuredDimension (width, height); + } + + @Override + protected void + onLayout (boolean changed, int left, int top, int right, + int bottom) + { + int count, i; + View child; + Rect windowRect; + + if (changed) + { + window.viewLayout (left, top, right, bottom); + + /* Recreate the front and back buffer bitmaps. */ + bitmap + = Bitmap.createBitmap (right - left, bottom - top, + Bitmap.Config.ARGB_8888); + + /* And canvases. */ + canvas = new Canvas (bitmap); + } + + count = getChildCount (); + + for (i = 0; i < count; ++i) + { + child = getChildAt (i); + + if (child == surfaceView) + /* The child is the surface view, so give it the entire + view. */ + child.layout (left, top, right, bottom); + else if (child.getVisibility () != GONE) + { + if (!(child instanceof EmacsView)) + continue; + + /* What to do: lay out the view precisely according to its + window rect. */ + windowRect = ((EmacsView) child).window.getGeometry (); + child.layout (windowRect.left, windowRect.top, + windowRect.right, windowRect.bottom); + } + } + } + + public void + damageRect (Rect damageRect) + { + damageRegion.union (damageRect); + } + + public void + swapBuffers () + { + Bitmap back; + Canvas canvas; + Rect damageRect; + + if (damageRegion.isEmpty ()) + return; + + if (!surfaceView.isCreated ()) + return; + + if (bitmap == null) + return; + + /* Lock the canvas with the specified damage. */ + damageRect = damageRegion.getBounds (); + canvas = surfaceView.lockCanvas (damageRect); + + /* Return if locking the canvas failed. */ + if (canvas == null) + return; + + /* Copy from the back buffer to the canvas. */ + canvas.drawBitmap (bitmap, damageRect, damageRect, paint); + + /* Unlock the canvas and clear the damage. */ + surfaceView.unlockCanvasAndPost (canvas); + damageRegion.setEmpty (); + } + + @Override + public boolean + onKeyDown (int keyCode, KeyEvent event) + { + window.onKeyDown (keyCode, event); + return true; + } + + @Override + public boolean + onKeyUp (int keyCode, KeyEvent event) + { + window.onKeyUp (keyCode, event); + return true; + } +}; |
