1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-01 08:17:38 +00:00

Update Java part of Android port

* java/org/gnu/emacs/EmacsCopyArea.java (EmacsCopyArea, perform)
(paintTo):
* java/org/gnu/emacs/EmacsDrawLine.java (EmacsDrawLine):
* java/org/gnu/emacs/EmacsDrawPoint.java (EmacsDrawPoint):
* java/org/gnu/emacs/EmacsDrawRectangle.java (EmacsDrawRectangle)
(paintTo):
* java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable):
* java/org/gnu/emacs/EmacsFillPolygon.java (EmacsFillPolygon):
* java/org/gnu/emacs/EmacsFillRectangle.java
(EmacsFillRectangle):
* java/org/gnu/emacs/EmacsFontDriver.java (EmacsFontDriver):
* java/org/gnu/emacs/EmacsGC.java (EmacsGC):
* java/org/gnu/emacs/EmacsNative.java (EmacsNative):
* java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap):
* java/org/gnu/emacs/EmacsSdk23FontDriver.java
(EmacsSdk23FontDriver):
* java/org/gnu/emacs/EmacsSdk7FontDriver.java
(EmacsSdk7FontDriver, textExtents1, textExtents, draw):
* java/org/gnu/emacs/EmacsService.java (EmacsService, copyArea):
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView):
* java/org/gnu/emacs/EmacsView.java (EmacsView, onLayout)
(onFocusChanged):
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow, run)
(resizeWindow, lockCanvas, getBitmap, onKeyDown, onKeyUp)
(onActivityDetached): Move rendering to main thread.  Make
drawing operations completely static.
This commit is contained in:
Po Lu 2023-01-08 15:39:02 +08:00
parent e816e57039
commit 695e26079e
17 changed files with 695 additions and 766 deletions

View File

@ -27,54 +27,16 @@
import android.graphics.Rect;
import android.graphics.Xfermode;
public class EmacsCopyArea implements EmacsPaintReq
public class EmacsCopyArea
{
private int src_x, src_y, dest_x, dest_y, width, height;
private EmacsDrawable destination, source;
private EmacsGC immutableGC;
private static Xfermode xorAlu, srcInAlu, overAlu;
private static Xfermode overAlu;
static
{
overAlu = new PorterDuffXfermode (Mode.SRC_OVER);
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
};
public
EmacsCopyArea (EmacsDrawable source, EmacsDrawable destination,
int src_x, int src_y, int width, int height,
int dest_x, int dest_y, EmacsGC immutableGC)
{
Bitmap bitmap;
this.destination = destination;
this.source = source;
this.src_x = src_x;
this.src_y = src_y;
this.width = width;
this.height = height;
this.dest_x = dest_x;
this.dest_y = dest_y;
this.immutableGC = immutableGC;
}
@Override
public Rect
getRect ()
{
return new Rect (dest_x, dest_y, dest_x + width,
dest_y + height);
}
@Override
public EmacsDrawable
getDrawable ()
{
return destination;
}
private void
private static void
insetRectBy (Rect rect, int left, int top, int right,
int bottom)
{
@ -84,30 +46,38 @@ public class EmacsCopyArea implements EmacsPaintReq
rect.bottom -= bottom;
}
@Override
public EmacsGC
getGC ()
public static void
perform (EmacsDrawable source, EmacsGC gc,
EmacsDrawable destination,
int src_x, int src_y, int width, int height,
int dest_x, int dest_y)
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int alu;
int i;
Bitmap bitmap;
Paint maskPaint;
Canvas maskCanvas;
Paint maskPaint, paint;
Canvas maskCanvas, canvas;
Bitmap srcBitmap, maskBitmap, clipBitmap;
Rect rect, maskRect, srcRect, dstRect, maskDestRect;
boolean needFill;
/* TODO implement stippling. */
if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
alu = immutableGC.function;
paint = gc.gcPaint;
canvas = destination.lockCanvas ();
if (canvas == null)
return;
canvas.save ();
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
/* A copy must be created or drawBitmap could end up overwriting
itself. */
@ -137,14 +107,10 @@ public class EmacsCopyArea implements EmacsPaintReq
if (src_y + height > srcBitmap.getHeight ())
height = srcBitmap.getHeight () - src_y;
rect = getRect ();
rect = new Rect (dest_x, dest_y, dest_x + width,
dest_y + height);
if (alu == EmacsGC.GC_COPY)
paint.setXfermode (null);
else
paint.setXfermode (xorAlu);
if (immutableGC.clip_mask == null)
if (gc.clip_mask == null)
{
bitmap = Bitmap.createBitmap (srcBitmap,
src_x, src_y, width,
@ -156,17 +122,17 @@ public class EmacsCopyArea implements EmacsPaintReq
/* Drawing with a clip mask involves calculating the
intersection of the clip mask with the dst rect, and
extrapolating the corresponding part of the src rect. */
clipBitmap = immutableGC.clip_mask.bitmap;
clipBitmap = gc.clip_mask.bitmap;
dstRect = new Rect (dest_x, dest_y,
dest_x + width,
dest_y + height);
maskRect = new Rect (immutableGC.clip_x_origin,
immutableGC.clip_y_origin,
(immutableGC.clip_x_origin
maskRect = new Rect (gc.clip_x_origin,
gc.clip_y_origin,
(gc.clip_x_origin
+ clipBitmap.getWidth ()),
(immutableGC.clip_y_origin
(gc.clip_y_origin
+ clipBitmap.getHeight ()));
clipBitmap = immutableGC.clip_mask.bitmap;
clipBitmap = gc.clip_mask.bitmap;
if (!maskRect.setIntersect (dstRect, maskRect))
/* There is no intersection between the clip mask and the
@ -191,20 +157,21 @@ public class EmacsCopyArea implements EmacsPaintReq
/* Draw the mask onto the maskBitmap. */
maskCanvas = new Canvas (maskBitmap);
maskRect.offset (-immutableGC.clip_x_origin,
-immutableGC.clip_y_origin);
maskCanvas.drawBitmap (immutableGC.clip_mask.bitmap,
maskRect, new Rect (0, 0,
maskRect.width (),
maskRect.height ()),
paint);
maskRect.offset (immutableGC.clip_x_origin,
immutableGC.clip_y_origin);
maskPaint = new Paint ();
maskRect.offset (-gc.clip_x_origin,
-gc.clip_y_origin);
maskCanvas.drawBitmap (gc.clip_mask.bitmap,
maskRect,
new Rect (0, 0,
maskRect.width (),
maskRect.height ()),
maskPaint);
maskRect.offset (gc.clip_x_origin,
gc.clip_y_origin);
/* Set the transfer mode to SRC_IN to preserve only the parts
of the source that overlap with the mask. */
maskPaint = new Paint ();
maskPaint.setXfermode (srcInAlu);
maskPaint.setXfermode (EmacsGC.srcInAlu);
/* Draw the source. */
maskDestRect = new Rect (0, 0, srcRect.width (),
@ -215,6 +182,10 @@ maskRect, new Rect (0, 0,
/* Finally, draw the mask bitmap to the destination. */
paint.setXfermode (overAlu);
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
gc.resetXfermode ();
}
canvas.restore ();
destination.damageRect (rect);
}
}

View File

@ -29,109 +29,49 @@
import android.graphics.Rect;
import android.graphics.Xfermode;
public class EmacsDrawLine implements EmacsPaintReq
public class EmacsDrawLine
{
private int x, y, x2, y2;
private EmacsDrawable drawable;
private EmacsGC immutableGC;
private static Xfermode xorAlu, srcInAlu;
static
public static void
perform (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int x2, int y2)
{
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
};
Rect rect;
Canvas canvas;
Paint paint;
int i;
public
EmacsDrawLine (EmacsDrawable drawable, int x, int y,
int x2, int y2, EmacsGC immutableGC)
{
this.drawable = drawable;
this.x = x;
this.y = y;
this.x2 = x2;
this.y2 = y2;
this.immutableGC = immutableGC;
}
/* TODO implement stippling. */
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
@Override
public Rect
getRect ()
{
return new Rect (Math.min (x, x2 + 1),
paint = gc.gcPaint;
rect = new Rect (Math.min (x, x2 + 1),
Math.min (y, y2 + 1),
Math.max (x2 + 1, x),
Math.max (y2 + 1, y));
}
canvas = drawable.lockCanvas ();
@Override
public EmacsDrawable
getDrawable ()
{
return drawable;
}
@Override
public EmacsGC
getGC ()
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int alu;
Paint maskPaint;
Canvas maskCanvas;
Bitmap maskBitmap;
Rect rect, srcRect;
int width, height;
/* TODO implement stippling. */
if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
if (canvas == null)
return;
alu = immutableGC.function;
rect = getRect ();
width = rect.width ();
height = rect.height ();
canvas.save ();
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
paint.setStyle (Paint.Style.STROKE);
if (alu == EmacsGC.GC_COPY)
paint.setXfermode (null);
else
paint.setXfermode (xorAlu);
if (gc.clip_mask == null)
canvas.drawLine ((float) x, (float) y,
(float) x2, (float) y2,
paint);
if (immutableGC.clip_mask == null)
{
paint.setColor (immutableGC.foreground | 0xff000000);
canvas.drawLine ((float) x, (float) y,
(float) x2, (float) y2,
paint);
}
else
{
maskPaint = new Paint ();
maskBitmap
= immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
true);
if (maskBitmap == null)
return;
maskPaint.setXfermode (srcInAlu);
maskPaint.setColor (immutableGC.foreground | 0xff000000);
maskCanvas = new Canvas (maskBitmap);
srcRect = new Rect (0, 0, maskBitmap.getWidth (),
maskBitmap.getHeight ());
maskCanvas.drawLine (0.0f, 0.0f, (float) Math.abs (x - x2),
(float) Math.abs (y - y2), maskPaint);
canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
}
paint.setXfermode (null);
/* DrawLine with clip mask not implemented; it is not used by
Emacs. */
canvas.restore ();
drawable.damageRect (rect);
}
}

View File

@ -19,12 +19,13 @@
package org.gnu.emacs;
public class EmacsDrawPoint extends EmacsDrawRectangle
public class EmacsDrawPoint
{
public
EmacsDrawPoint (EmacsDrawable drawable, int x, int y,
EmacsGC immutableGC)
public static void
perform (EmacsDrawable drawable,
EmacsGC immutableGC, int x, int y)
{
super (drawable, x, y, 1, 1, immutableGC);
EmacsDrawRectangle.perform (drawable, immutableGC,
x, y, 1, 1);
}
}

View File

@ -22,110 +22,104 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Xfermode;
public class EmacsDrawRectangle implements EmacsPaintReq
import android.util.Log;
public class EmacsDrawRectangle
{
private int x, y, width, height;
private EmacsDrawable drawable;
private EmacsGC immutableGC;
private static Xfermode xorAlu, srcInAlu;
static
public static void
perform (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
};
public
EmacsDrawRectangle (EmacsDrawable drawable, int x, int y,
int width, int height,
EmacsGC immutableGC)
{
this.drawable = drawable;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.immutableGC = immutableGC;
}
@Override
public Rect
getRect ()
{
/* Canvas.drawRect actually behaves exactly like PolyRectangle wrt
to where the lines are placed, so extend the width and height
by 1 in the damage rectangle. */
return new Rect (x, y, x + width + 1, y + height + 1);
}
@Override
public EmacsDrawable
getDrawable ()
{
return drawable;
}
@Override
public EmacsGC
getGC ()
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int alu;
Paint maskPaint;
int i;
Paint maskPaint, paint;
Canvas maskCanvas;
Bitmap maskBitmap;
Rect rect, srcRect;
Rect rect;
Rect maskRect, dstRect;
Canvas canvas;
Bitmap clipBitmap;
/* TODO implement stippling. */
if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
alu = immutableGC.function;
canvas = drawable.lockCanvas ();
if (canvas == null)
return;
canvas.save ();
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
paint = gc.gcPaint;
rect = new Rect (x, y, x + width, y + height);
paint.setStyle (Paint.Style.STROKE);
paint.setStrokeWidth (1);
if (alu == EmacsGC.GC_COPY)
paint.setXfermode (null);
else
paint.setXfermode (xorAlu);
if (immutableGC.clip_mask == null)
{
paint.setColor (immutableGC.foreground | 0xff000000);
canvas.drawRect (rect, paint);
}
if (gc.clip_mask == null)
canvas.drawRect (rect, paint);
else
{
maskPaint = new Paint ();
maskBitmap
= immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
true);
/* Drawing with a clip mask involves calculating the
intersection of the clip mask with the dst rect, and
extrapolating the corresponding part of the src rect. */
clipBitmap = gc.clip_mask.bitmap;
dstRect = new Rect (x, y, x + width, y + height);
maskRect = new Rect (gc.clip_x_origin,
gc.clip_y_origin,
(gc.clip_x_origin
+ clipBitmap.getWidth ()),
(gc.clip_y_origin
+ clipBitmap.getHeight ()));
clipBitmap = gc.clip_mask.bitmap;
if (maskBitmap == null)
if (!maskRect.setIntersect (dstRect, maskRect))
/* There is no intersection between the clip mask and the
dest rect. */
return;
maskPaint.setXfermode (srcInAlu);
maskPaint.setColor (immutableGC.foreground | 0xff000000);
/* Finally, create a temporary bitmap that is the size of
maskRect. */
maskBitmap
= Bitmap.createBitmap (maskRect.width (), maskRect.height (),
Bitmap.Config.ARGB_8888);
/* Draw the mask onto the maskBitmap. */
maskCanvas = new Canvas (maskBitmap);
srcRect = new Rect (0, 0, maskBitmap.getWidth (),
maskBitmap.getHeight ());
maskCanvas.drawRect (srcRect, maskPaint);
canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
maskRect.offset (-gc.clip_x_origin,
-gc.clip_y_origin);
maskCanvas.drawBitmap (gc.clip_mask.bitmap,
maskRect, new Rect (0, 0,
maskRect.width (),
maskRect.height ()),
paint);
maskRect.offset (gc.clip_x_origin,
gc.clip_y_origin);
/* Set the transfer mode to SRC_IN to preserve only the parts
of the source that overlap with the mask. */
maskPaint = new Paint ();
maskPaint.setXfermode (EmacsGC.srcInAlu);
maskPaint.setStyle (Paint.Style.STROKE);
/* Draw the source. */
maskCanvas.drawRect (maskRect, maskPaint);
/* Finally, draw the mask bitmap to the destination. */
paint.setXfermode (null);
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
}
paint.setXfermode (null);
canvas.restore ();
drawable.damageRect (new Rect (x, y, x + width + 1,
y + height + 1));
}
}

View File

@ -26,7 +26,6 @@
public interface EmacsDrawable
{
public Canvas lockCanvas ();
public void unlockCanvas ();
public void damageRect (Rect damageRect);
public Bitmap getBitmap ();
public boolean isDestroyed ();

View File

@ -26,34 +26,35 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Xfermode;
public class EmacsFillPolygon implements EmacsPaintReq
public class EmacsFillPolygon
{
private EmacsDrawable drawable;
private EmacsGC immutableGC;
private Path path;
private static Xfermode xorAlu, srcInAlu;
static
{
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
};
public
EmacsFillPolygon (EmacsDrawable drawable, Point points[],
EmacsGC immutableGC)
public static void
perform (EmacsDrawable drawable, EmacsGC gc, Point points[])
{
Canvas canvas;
Path path;
Paint paint;
Rect rect;
RectF rectF;
int i;
this.drawable = drawable;
this.immutableGC = immutableGC;
canvas = drawable.lockCanvas ();
if (canvas == null)
return;
paint = gc.gcPaint;
canvas.save ();
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
/* Build the path from the given array of points. */
path = new Path ();
@ -67,84 +68,25 @@ public class EmacsFillPolygon implements EmacsPaintReq
path.close ();
}
}
@Override
public Rect
getRect ()
{
RectF rect;
/* Compute the damage rectangle. */
rectF = new RectF (0, 0, 0, 0);
path.computeBounds (rectF, true);
rect = new RectF (0, 0, 0, 0);
path.computeBounds (rect, true);
return new Rect ((int) Math.floor (rect.left),
(int) Math.floor (rect.top),
(int) Math.ceil (rect.right),
(int) Math.ceil (rect.bottom));
}
@Override
public EmacsDrawable
getDrawable ()
{
return drawable;
}
@Override
public EmacsGC
getGC ()
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int alu;
Paint maskPaint;
Canvas maskCanvas;
Bitmap maskBitmap;
Rect rect;
/* TODO implement stippling. */
if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
alu = immutableGC.function;
rect = getRect ();
if (alu == EmacsGC.GC_COPY)
paint.setXfermode (null);
else
paint.setXfermode (xorAlu);
rect = new Rect ((int) Math.floor (rectF.left),
(int) Math.floor (rectF.top),
(int) Math.ceil (rectF.right),
(int) Math.ceil (rectF.bottom));
paint.setStyle (Paint.Style.FILL);
if (immutableGC.clip_mask == null)
{
paint.setColor (immutableGC.foreground | 0xff000000);
canvas.drawPath (path, paint);
}
else
{
maskPaint = new Paint ();
maskBitmap = immutableGC.clip_mask.bitmap;
maskBitmap = maskBitmap.copy (Bitmap.Config.ARGB_8888,
true);
if (gc.clip_mask == null)
canvas.drawPath (path, paint);
if (maskBitmap == null)
return;
canvas.restore ();
drawable.damageRect (rect);
maskPaint.setXfermode (srcInAlu);
maskPaint.setColor (immutableGC.foreground | 0xff000000);
maskCanvas = new Canvas (maskBitmap);
path.offset (-rect.left, -rect.top, null);
maskCanvas.drawPath (path, maskPaint);
canvas.drawBitmap (maskBitmap, new Rect (0, 0, rect.width (),
rect.height ()),
rect, paint);
}
/* FillPolygon with clip mask not implemented; it is not used by
Emacs. */
}
}

View File

@ -22,108 +22,102 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Xfermode;
import android.util.Log;
public class EmacsFillRectangle implements EmacsPaintReq
public class EmacsFillRectangle
{
private int x, y, width, height;
private EmacsDrawable drawable;
private EmacsGC immutableGC;
private static Xfermode xorAlu, srcInAlu;
static
public static void
perform (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
};
public
EmacsFillRectangle (EmacsDrawable drawable, int x, int y,
int width, int height,
EmacsGC immutableGC)
{
this.drawable = drawable;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.immutableGC = immutableGC;
}
@Override
public Rect
getRect ()
{
return new Rect (x, y, x + width, y + height);
}
@Override
public EmacsDrawable
getDrawable ()
{
return drawable;
}
@Override
public EmacsGC
getGC ()
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int alu;
Paint maskPaint;
int i;
Paint maskPaint, paint;
Canvas maskCanvas;
Bitmap maskBitmap;
Rect rect, srcRect;
Rect rect;
Rect maskRect, dstRect;
Canvas canvas;
Bitmap clipBitmap;
/* TODO implement stippling. */
if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
return;
alu = immutableGC.function;
rect = getRect ();
canvas = drawable.lockCanvas ();
if (canvas == null)
return;
canvas.save ();
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
paint = gc.gcPaint;
rect = new Rect (x, y, x + width, y + height);
paint.setStyle (Paint.Style.FILL);
if (alu == EmacsGC.GC_COPY)
paint.setXfermode (null);
else
paint.setXfermode (xorAlu);
if (immutableGC.clip_mask == null)
{
paint.setColor (immutableGC.foreground | 0xff000000);
canvas.drawRect (rect, paint);
}
if (gc.clip_mask == null)
canvas.drawRect (rect, paint);
else
{
maskPaint = new Paint ();
maskBitmap
= immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
true);
/* Drawing with a clip mask involves calculating the
intersection of the clip mask with the dst rect, and
extrapolating the corresponding part of the src rect. */
clipBitmap = gc.clip_mask.bitmap;
dstRect = new Rect (x, y, x + width, y + height);
maskRect = new Rect (gc.clip_x_origin,
gc.clip_y_origin,
(gc.clip_x_origin
+ clipBitmap.getWidth ()),
(gc.clip_y_origin
+ clipBitmap.getHeight ()));
clipBitmap = gc.clip_mask.bitmap;
if (maskBitmap == null)
if (!maskRect.setIntersect (dstRect, maskRect))
/* There is no intersection between the clip mask and the
dest rect. */
return;
maskPaint.setXfermode (srcInAlu);
maskPaint.setColor (immutableGC.foreground | 0xff000000);
/* Finally, create a temporary bitmap that is the size of
maskRect. */
maskBitmap
= Bitmap.createBitmap (maskRect.width (), maskRect.height (),
Bitmap.Config.ARGB_8888);
/* Draw the mask onto the maskBitmap. */
maskCanvas = new Canvas (maskBitmap);
srcRect = new Rect (0, 0, maskBitmap.getWidth (),
maskBitmap.getHeight ());
maskCanvas.drawRect (srcRect, maskPaint);
canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
maskRect.offset (-gc.clip_x_origin,
-gc.clip_y_origin);
maskCanvas.drawBitmap (gc.clip_mask.bitmap,
maskRect, new Rect (0, 0,
maskRect.width (),
maskRect.height ()),
paint);
maskRect.offset (gc.clip_x_origin,
gc.clip_y_origin);
/* Set the transfer mode to SRC_IN to preserve only the parts
of the source that overlap with the mask. */
maskPaint = new Paint ();
maskPaint.setXfermode (EmacsGC.srcInAlu);
/* Draw the source. */
maskCanvas.drawRect (maskRect, maskPaint);
/* Finally, draw the mask bitmap to the destination. */
paint.setXfermode (null);
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
}
paint.setXfermode (null);
canvas.restore ();
drawable.damageRect (rect);
}
}

View File

@ -164,7 +164,7 @@ public abstract int draw (FontObject fontObject, EmacsGC gc,
public static EmacsFontDriver
createFontDriver ()
{
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
return new EmacsSdk23FontDriver ();
return new EmacsSdk7FontDriver ();

View File

@ -20,6 +20,11 @@
package org.gnu.emacs;
import android.graphics.Rect;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Xfermode;
/* X like graphics context structures. Keep the enums in synch with
androidgui.h! */
@ -32,14 +37,21 @@ public class EmacsGC extends EmacsHandleObject
public static final int GC_FILL_SOLID = 0;
public static final int GC_FILL_OPAQUE_STIPPLED = 1;
public static final Xfermode xorAlu, srcInAlu;
public int function, fill_style;
public int foreground, background;
public int clip_x_origin, clip_y_origin;
public int ts_origin_x, ts_origin_y;
public Rect clip_rects[];
public Rect clip_rects[], real_clip_rects[];
public EmacsPixmap clip_mask, stipple;
private boolean dirty;
private EmacsGC immutableGC;
public Paint gcPaint;
static
{
xorAlu = new PorterDuffXfermode (Mode.XOR);
srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
}
/* The following fields are only set on immutable GCs. */
@ -55,62 +67,41 @@ public class EmacsGC extends EmacsHandleObject
fill_style = GC_FILL_SOLID;
function = GC_COPY;
foreground = 0;
background = 0xffffffff;
background = 0xffffff;
gcPaint = new Paint ();
}
public
EmacsGC (EmacsGC source)
{
super ((short) 0);
int i;
function = source.function;
fill_style = source.fill_style;
foreground = source.foreground;
background = source.background;
clip_x_origin = source.clip_x_origin;
clip_y_origin = source.clip_y_origin;
clip_rects = source.clip_rects;
clip_mask = source.clip_mask;
stipple = source.stipple;
ts_origin_x = source.ts_origin_x;
ts_origin_y = source.ts_origin_y;
/* Offset all the clip rects by ts_origin_x and ts_origin_y. */
if ((ts_origin_x != 0 || ts_origin_y != 0)
&& clip_rects != null)
{
clip_rects = new Rect[clip_rects.length];
for (i = 0; i < clip_rects.length; ++i)
{
clip_rects[i] = new Rect (source.clip_rects[i]);
clip_rects[i].offset (ts_origin_x,
ts_origin_y);
}
}
}
/* Mark this GC as dirty. This means immutableGC will return a new
copy of this GC the next time it is called. */
/* Mark this GC as dirty. Apply parameters to the paint and
recompute real_clip_rects. */
public void
markDirty ()
{
dirty = true;
int i;
if ((ts_origin_x != 0 || ts_origin_y != 0)
&& clip_rects != null)
{
real_clip_rects = new Rect[clip_rects.length];
for (i = 0; i < clip_rects.length; ++i)
{
real_clip_rects[i] = new Rect (clip_rects[i]);
real_clip_rects[i].offset (ts_origin_x, ts_origin_y);
}
}
else
real_clip_rects = clip_rects;
gcPaint.setColor (foreground | 0xff000000);
gcPaint.setXfermode (function == GC_XOR
? xorAlu : srcInAlu);
}
public EmacsGC
immutableGC ()
public void
resetXfermode ()
{
if (immutableGC == null || dirty)
{
immutableGC = new EmacsGC (this);
dirty = false;
}
return immutableGC;
};
gcPaint.setXfermode (function == GC_XOR
? xorAlu : srcInAlu);
}
};

View File

@ -79,6 +79,28 @@ public static native void sendKeyRelease (short window, long time, int state,
/* Send an ANDROID_WINDOW_ACTION event. */
public static native void sendWindowAction (short window, int action);
/* Send an ANDROID_ENTER_NOTIFY event. */
public static native void sendEnterNotify (short window, int x, int y,
long time);
/* Send an ANDROID_LEAVE_NOTIFY event. */
public static native void sendLeaveNotify (short window, int x, int y,
long time);
/* Send an ANDROID_MOTION_NOTIFY event. */
public static native void sendMotionNotify (short window, int x, int y,
long time);
/* Send an ANDROID_BUTTON_PRESS event. */
public static native void sendButtonPress (short window, int x, int y,
long time, int state,
int button);
/* Send an ANDROID_BUTTON_RELEASE event. */
public static native void sendButtonRelease (short window, int x, int y,
long time, int state,
int button);
static
{
System.loadLibrary ("emacs");

View File

@ -93,6 +93,8 @@ public class EmacsPixmap extends EmacsHandleObject
break;
}
bitmap.eraseColor (0xff000000);
this.width = width;
this.height = height;
this.depth = depth;
@ -108,13 +110,6 @@ public class EmacsPixmap extends EmacsHandleObject
return canvas;
}
@Override
public void
unlockCanvas ()
{
}
@Override
public void
damageRect (Rect damageRect)

View File

@ -20,9 +20,80 @@
package org.gnu.emacs;
import android.graphics.Paint;
import android.graphics.Rect;
public class EmacsSdk23FontDriver extends EmacsSdk7FontDriver
{
private void
textExtents1 (Sdk7FontObject font, int code, FontMetrics metrics,
Paint paint, Rect bounds)
{
char[] text;
text = new char[2];
text[0] = (char) code;
text[1] = 'c';
paint.getTextBounds (text, 0, 1, bounds);
metrics.lbearing = (short) bounds.left;
metrics.rbearing = (short) bounds.right;
metrics.ascent = (short) -bounds.top;
metrics.descent = (short) bounds.bottom;
metrics.width
= (short) paint.getRunAdvance (text, 0, 1, 0, 1, false, 1);
}
@Override
public void
textExtents (FontObject font, int code[], FontMetrics fontMetrics)
{
int i;
Paint paintCache;
Rect boundsCache;
Sdk7FontObject fontObject;
char[] text;
float width;
fontObject = (Sdk7FontObject) font;
paintCache = fontObject.typeface.typefacePaint;
paintCache.setTextSize (fontObject.pixelSize);
boundsCache = new Rect ();
if (code.length == 0)
{
fontMetrics.lbearing = 0;
fontMetrics.rbearing = 0;
fontMetrics.ascent = 0;
fontMetrics.descent = 0;
fontMetrics.width = 0;
}
else if (code.length == 1)
textExtents1 ((Sdk7FontObject) font, code[0], fontMetrics,
paintCache, boundsCache);
else
{
text = new char[code.length + 1];
for (i = 0; i < code.length; ++i)
text[i] = (char) code[i];
text[code.length] = 'c';
paintCache.getTextBounds (text, 0, code.length,
boundsCache);
width = paintCache.getRunAdvance (text, 0, code.length, 0,
code.length,
false, code.length);
fontMetrics.lbearing = (short) boundsCache.left;
fontMetrics.rbearing = (short) boundsCache.right;
fontMetrics.ascent = (short) -boundsCache.top;
fontMetrics.descent = (short) boundsCache.bottom;
fontMetrics.width = (short) width;
}
}
@Override
public int
hasChar (FontSpec font, char charCode)

View File

@ -243,93 +243,6 @@ protected class Sdk7FontObject extends FontObject
}
};
private class Sdk7DrawString implements EmacsPaintReq
{
private boolean drawBackground;
private Sdk7FontObject fontObject;
private char[] chars;
private EmacsGC immutableGC;
private EmacsDrawable drawable;
private Rect rect;
private int originX, originY;
public
Sdk7DrawString (Sdk7FontObject fontObject, char[] chars,
EmacsGC immutableGC, EmacsDrawable drawable,
boolean drawBackground, Rect rect,
int originX, int originY)
{
this.fontObject = fontObject;
this.chars = chars;
this.immutableGC = immutableGC;
this.drawable = drawable;
this.drawBackground = drawBackground;
this.rect = rect;
this.originX = originX;
this.originY = originY;
}
@Override
public EmacsDrawable
getDrawable ()
{
return drawable;
}
@Override
public EmacsGC
getGC ()
{
return immutableGC;
}
@Override
public void
paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
{
int scratch;
paint.setStyle (Paint.Style.FILL);
if (drawBackground)
{
paint.setColor (immutableGC.background | 0xff000000);
canvas.drawRect (rect, paint);
}
paint.setTextSize (fontObject.pixelSize);
paint.setColor (immutableGC.foreground | 0xff000000);
paint.setTypeface (fontObject.typeface.typeface);
paint.setAntiAlias (true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
/* Disable hinting as that leads to displayed text not
matching the computed metrics. */
paint.setHinting (Paint.HINTING_OFF);
canvas.drawText (chars, 0, chars.length, originX, originY, paint);
paint.setAntiAlias (false);
}
@Override
public Rect
getRect ()
{
Rect rect;
rect = new Rect ();
fontObject.typeface.typefacePaint.setTextSize (fontObject.pixelSize);
fontObject.typeface.typefacePaint.getTextBounds (chars, 0, chars.length,
rect);
/* Add the background rect to the damage as well. */
rect.union (this.rect);
return rect;
}
};
private String[] fontFamilyList;
private Sdk7Typeface[] typefaceList;
private Sdk7Typeface fallbackTypeface;
@ -498,14 +411,11 @@ private class Sdk7DrawString implements EmacsPaintReq
Paint paint, Rect bounds)
{
char[] text;
float[] width;
text = new char[1];
text[0] = (char) code;
paint.getTextBounds (text, 0, 1, bounds);
width = new float[1];
paint.getTextWidths (text, 0, 1, width);
/* bounds is the bounding box of the glyph corresponding to CODE.
Translate these into XCharStruct values.
@ -526,7 +436,7 @@ raster. descent is the distance (once again counting
metrics.rbearing = (short) bounds.right;
metrics.ascent = (short) -bounds.top;
metrics.descent = (short) bounds.bottom;
metrics.width = (short) Math.round (width[0]);
metrics.width = (short) paint.measureText ("" + text[0]);
}
@Override
@ -563,7 +473,8 @@ else if (code.length == 1)
for (i = 0; i < code.length; ++i)
text[i] = (char) code[i];
paintCache.getTextBounds (text, 0, 1, boundsCache);
paintCache.getTextBounds (text, 0, code.length,
boundsCache);
width = paintCache.measureText (text, 0, code.length);
fontMetrics.lbearing = (short) boundsCache.left;
@ -587,11 +498,12 @@ else if (code.length == 1)
int[] chars, int x, int y, int backgroundWidth,
boolean withBackground)
{
Rect backgroundRect;
Rect backgroundRect, bounds;
Sdk7FontObject sdk7FontObject;
Sdk7DrawString op;
char[] charsArray;
int i;
Canvas canvas;
Paint paint;
sdk7FontObject = (Sdk7FontObject) fontObject;
charsArray = new char[chars.length];
@ -605,12 +517,41 @@ else if (code.length == 1)
backgroundRect.right = x + backgroundWidth;
backgroundRect.bottom = y + sdk7FontObject.descent;
op = new Sdk7DrawString (sdk7FontObject, charsArray,
gc.immutableGC (), drawable,
withBackground,
backgroundRect, x, y);
canvas = drawable.lockCanvas ();
EmacsService.SERVICE.appendPaintOperation (op);
if (canvas == null)
return 0;
canvas.save ();
paint = gc.gcPaint;
if (gc.real_clip_rects != null)
{
for (i = 0; i < gc.real_clip_rects.length; ++i)
canvas.clipRect (gc.real_clip_rects[i]);
}
paint.setStyle (Paint.Style.FILL);
if (withBackground)
{
paint.setColor (gc.background | 0xff000000);
canvas.drawRect (backgroundRect, paint);
paint.setColor (gc.foreground | 0xff000000);
}
paint.setTextSize (sdk7FontObject.pixelSize);
paint.setTypeface (sdk7FontObject.typeface.typeface);
paint.setAntiAlias (true);
canvas.drawText (charsArray, 0, chars.length, x, y, paint);
canvas.restore ();
bounds = new Rect ();
paint.getTextBounds (charsArray, 0, chars.length, bounds);
bounds.offset (x, y);
bounds.union (backgroundRect);
drawable.damageRect (bounds);
paint.setAntiAlias (false);
return 1;
}
};

View File

@ -19,7 +19,6 @@
package org.gnu.emacs;
import java.lang.Runnable;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
@ -59,7 +58,6 @@ public class EmacsService extends Service
private EmacsThread thread;
private Handler handler;
private EmacsPaintQueue paintQueue;
/* Display metrics used by font backends. */
public DisplayMetrics metrics;
@ -191,126 +189,42 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
return view.thing;
}
/* X drawing operations. These are quite primitive operations. The
drawing queue is kept on the Emacs thread, but is periodically
flushed to the application thread, upon buffers swaps and once it
gets too big. */
private void
ensurePaintQueue ()
{
if (paintQueue == null)
paintQueue = new EmacsPaintQueue ();
}
public void
flushPaintQueue ()
{
final EmacsPaintQueue queue;
if (paintQueue == null)
return;
if (paintQueue.numRequests < 1)
/* No requests to flush. */
return;
queue = paintQueue;
handler.post (new Runnable () {
@Override
public void
run ()
{
queue.run ();
}
});
/* Clear the paint queue. */
paintQueue = null;
}
private void
checkFlush ()
{
if (paintQueue != null
&& paintQueue.numRequests > MAX_PENDING_REQUESTS)
flushPaintQueue ();
}
public void
fillRectangle (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsFillRectangle (drawable, x, y,
width, height,
gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsFillRectangle.perform (drawable, gc, x, y,
width, height);
}
public void
fillPolygon (EmacsDrawable drawable, EmacsGC gc,
Point points[])
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsFillPolygon (drawable, points,
gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsFillPolygon.perform (drawable, gc, points);
}
public void
drawRectangle (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsDrawRectangle (drawable, x, y,
width, height,
gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsDrawRectangle.perform (drawable, gc, x, y,
width, height);
}
public void
drawLine (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int x2, int y2)
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsDrawLine (drawable, x, y,
x2, y2,
gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsDrawLine.perform (drawable, gc, x, y,
x2, y2);
}
public void
drawPoint (EmacsDrawable drawable, EmacsGC gc,
int x, int y)
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsDrawPoint (drawable, x, y,
gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsDrawPoint.perform (drawable, gc, x, y);
}
public void
@ -319,15 +233,9 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
int srcX, int srcY, int width, int height, int destX,
int destY)
{
EmacsPaintReq req;
ensurePaintQueue ();
req = new EmacsCopyArea (srcDrawable, dstDrawable,
srcX, srcY, width, height, destX,
destY, gc.immutableGC ());
paintQueue.appendPaintOperation (req);
checkFlush ();
EmacsCopyArea.perform (srcDrawable, gc, dstDrawable,
srcX, srcY, width, height, destX,
destY);
}
public void
@ -342,12 +250,4 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
{
window.clearArea (x, y, width, height);
}
public void
appendPaintOperation (EmacsPaintReq op)
{
ensurePaintQueue ();
paintQueue.appendPaintOperation (op);
checkFlush ();
}
};

View File

@ -29,6 +29,7 @@
public class EmacsSurfaceView extends SurfaceView
{
public Object surfaceChangeLock;
private boolean created;
public
@ -36,33 +37,36 @@ public class EmacsSurfaceView extends SurfaceView
{
super (view.getContext ());
surfaceChangeLock = new Object ();
getHolder ().addCallback (new SurfaceHolder.Callback () {
@Override
public void
surfaceChanged (SurfaceHolder holder, int format,
int width, int height)
{
/* Force a buffer swap now to get the contents of the Emacs
view on screen. */
view.swapBuffers (true);
view.swapBuffers ();
}
@Override
public void
surfaceCreated (SurfaceHolder holder)
{
created = true;
/* Force a buffer swap now to get the contents of the Emacs
view on screen. */
view.swapBuffers (true);
synchronized (surfaceChangeLock)
{
created = true;
view.swapBuffers ();
}
}
@Override
public void
surfaceDestroyed (SurfaceHolder holder)
{
created = false;
synchronized (surfaceChangeLock)
{
created = false;
}
}
});
}

View File

@ -23,6 +23,7 @@
import android.view.View;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.graphics.Bitmap;
@ -64,6 +65,14 @@ public class EmacsView extends ViewGroup
/* The associated surface view. */
private EmacsSurfaceView surfaceView;
/* Whether or not a configure event must be sent for the next layout
event regardless of what changed. */
public boolean mustReportLayout;
/* If non-null, whether or not bitmaps must be recreated upon the
next call to getBitmap. */
private Rect bitmapDirty;
public
EmacsView (EmacsWindow window)
{
@ -81,6 +90,43 @@ public class EmacsView extends ViewGroup
addView (this.surfaceView);
}
private void
handleDirtyBitmap ()
{
/* Recreate the front and back buffer bitmaps. */
bitmap
= Bitmap.createBitmap (bitmapDirty.width (),
bitmapDirty.height (),
Bitmap.Config.ARGB_8888);
bitmap.eraseColor (0xffffffff);
/* 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! */
bitmapDirty = null;
}
public synchronized Bitmap
getBitmap ()
{
if (bitmapDirty != null)
handleDirtyBitmap ();
return bitmap;
}
public synchronized Canvas
getCanvas ()
{
if (bitmapDirty != null)
handleDirtyBitmap ();
return canvas;
}
@Override
protected void
onMeasure (int widthMeasureSpec, int heightMeasureSpec)
@ -114,7 +160,7 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
}
@Override
protected void
protected synchronized void
onLayout (boolean changed, int left, int top, int right,
int bottom)
{
@ -122,19 +168,15 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
View child;
Rect windowRect;
if (changed)
if (changed || mustReportLayout)
{
mustReportLayout = false;
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);
}
if (changed)
bitmapDirty = new Rect (left, top, right, bottom);
count = getChildCount ();
for (i = 0; i < count; ++i)
@ -159,47 +201,60 @@ else if (child.getVisibility () != GONE)
}
}
public void
public synchronized void
damageRect (Rect damageRect)
{
damageRegion.union (damageRect);
}
public void
/* This method is called from both the UI thread and the Emacs
thread. */
public synchronized void
swapBuffers (boolean force)
{
Bitmap back;
Canvas canvas;
Rect damageRect;
Bitmap bitmap;
if (damageRegion.isEmpty ())
return;
if (!surfaceView.isCreated ())
return;
bitmap = getBitmap ();
if (bitmap == null)
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. */
/* Lock the canvas with the specified damage. */
damageRect = damageRegion.getBounds ();
canvas = surfaceView.lockCanvas (damageRect);
synchronized (surfaceView.surfaceChangeLock)
{
damageRect = damageRegion.getBounds ();
/* Return if locking the canvas failed. */
if (canvas == null)
return;
if (!surfaceView.isCreated ())
return;
/* Copy from the back buffer to the canvas. If damageRect was
made empty, then draw the entire back buffer. */
if (bitmap == null)
return;
if (damageRect.isEmpty ())
canvas.drawBitmap (bitmap, 0f, 0f, paint);
else
canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
/* Lock the canvas with the specified damage. */
canvas = surfaceView.lockCanvas (damageRect);
/* Unlock the canvas and clear the damage. */
surfaceView.unlockCanvasAndPost (canvas);
damageRegion.setEmpty ();
/* 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 ();
}
}
public void
@ -241,4 +296,18 @@ else if (child.getVisibility () != GONE)
super.onFocusChanged (gainFocus, direction,
previouslyFocusedRect);
}
@Override
public boolean
onGenericMotionEvent (MotionEvent motion)
{
return window.onSomeKindOfMotionEvent (motion);
}
@Override
public boolean
onTouchEvent (MotionEvent motion)
{
return window.onSomeKindOfMotionEvent (motion);
}
};

View File

@ -31,8 +31,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.InputDevice;
import android.content.Intent;
import android.util.Log;
import android.os.Build;
/* This defines a window, which is a handle. Windows represent a
rectangular subset of the screen with their own contents.
@ -68,6 +73,10 @@ public class EmacsWindow extends EmacsHandleObject
window background. */
private EmacsGC scratchGC;
/* The button state and keyboard modifier mask at the time of the
last button press or release event. */
private int lastButtonState, lastModifiers;
public
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
int width, int height)
@ -212,6 +221,7 @@ public class EmacsWindow extends EmacsHandleObject
public void
run ()
{
view.mustReportLayout = true;
view.requestLayout ();
}
});
@ -224,6 +234,8 @@ public class EmacsWindow extends EmacsHandleObject
{
rect.right = rect.left + width;
rect.bottom = rect.top + height;
requestViewLayout ();
}
}
@ -279,17 +291,7 @@ public class EmacsWindow extends EmacsHandleObject
public Canvas
lockCanvas ()
{
if (view.canvas != null)
return view.canvas;
return null;
}
@Override
public void
unlockCanvas ()
{
return view.getCanvas ();
}
@Override
@ -302,17 +304,7 @@ public class EmacsWindow extends EmacsHandleObject
public void
swapBuffers ()
{
/* Before calling swapBuffers, make sure to flush the paint
queue. */
EmacsService.SERVICE.flushPaintQueue ();
view.post (new Runnable () {
@Override
public void
run ()
{
view.swapBuffers ();
}
});
view.swapBuffers ();
}
public void
@ -337,7 +329,7 @@ public class EmacsWindow extends EmacsHandleObject
public Bitmap
getBitmap ()
{
return view.bitmap;
return view.getBitmap ();
}
public void
@ -357,6 +349,7 @@ public class EmacsWindow extends EmacsHandleObject
recognized as an ASCII key press
event. */
event.getUnicodeChar (state));
lastModifiers = event.getModifiers ();
}
public void
@ -372,6 +365,7 @@ public class EmacsWindow extends EmacsHandleObject
event.getModifiers (),
keyCode,
event.getUnicodeChar (state));
lastModifiers = event.getModifiers ();
}
public void
@ -386,4 +380,105 @@ public class EmacsWindow extends EmacsHandleObject
/* Destroy the associated frame when the activity is detached. */
EmacsNative.sendWindowAction (this.handle, 0);
}
/* Look through the button state to determine what button EVENT was
generated from. DOWN is true if EVENT is a button press event,
false otherwise. Value is the X number of the button. */
private int
whatButtonWasIt (MotionEvent event, boolean down)
{
int eventState, notIn;
if (Build.VERSION.SDK_INT
< Build.VERSION_CODES.ICE_CREAM_SANDWICH)
/* Earlier versions of Android only support one mouse
button. */
return 1;
eventState = event.getButtonState ();
notIn = (down ? eventState & ~lastButtonState
: lastButtonState & ~eventState);
if ((notIn & MotionEvent.BUTTON_PRIMARY) != 0)
return 1;
if ((notIn & MotionEvent.BUTTON_SECONDARY) != 0)
return 3;
if ((notIn & MotionEvent.BUTTON_TERTIARY) != 0)
return 2;
/* Not a real value. */
return 4;
}
public boolean
onSomeKindOfMotionEvent (MotionEvent event)
{
if (!event.isFromSource (InputDevice.SOURCE_CLASS_POINTER))
return false;
switch (event.getAction ())
{
case MotionEvent.ACTION_HOVER_ENTER:
EmacsNative.sendEnterNotify (this.handle, (int) event.getX (),
(int) event.getY (),
event.getEventTime ());
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_HOVER_MOVE:
EmacsNative.sendMotionNotify (this.handle, (int) event.getX (),
(int) event.getY (),
event.getEventTime ());
return true;
case MotionEvent.ACTION_HOVER_EXIT:
EmacsNative.sendLeaveNotify (this.handle, (int) event.getX (),
(int) event.getY (),
event.getEventTime ());
return true;
case MotionEvent.ACTION_BUTTON_PRESS:
/* Find the button which was pressed. */
EmacsNative.sendButtonPress (this.handle, (int) event.getX (),
(int) event.getY (),
event.getEventTime (),
lastModifiers,
whatButtonWasIt (event, true));
if (Build.VERSION.SDK_INT
< Build.VERSION_CODES.ICE_CREAM_SANDWICH)
return true;
lastButtonState = event.getButtonState ();
return true;
case MotionEvent.ACTION_BUTTON_RELEASE:
/* Find the button which was released. */
EmacsNative.sendButtonRelease (this.handle, (int) event.getX (),
(int) event.getY (),
event.getEventTime (),
lastModifiers,
whatButtonWasIt (event, false));
if (Build.VERSION.SDK_INT
< Build.VERSION_CODES.ICE_CREAM_SANDWICH)
return true;
lastButtonState = event.getButtonState ();
return true;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
/* Emacs must return true even though touch events are not yet
handled, because the value of this function is used by the
system to decide whether or not Emacs gets ACTION_MOVE
events. */
return true;
}
return false;
}
};