import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
It is also a ViewGroup, as it also lays out children. */
public final class EmacsView extends ViewGroup
+ implements ViewTreeObserver.OnGlobalLayoutListener
{
public static final String TAG = "EmacsView";
context = getContext ();
tem = context.getSystemService (Context.INPUT_METHOD_SERVICE);
imManager = (InputMethodManager) tem;
+
+ /* Add this view as its own global layout listener. */
+ getViewTreeObserver ().addOnGlobalLayoutListener (this);
}
private void
return canvas;
}
+ public void
+ prepareForLayout (int wantedWidth, int wantedHeight)
+ {
+ measuredWidth = wantedWidth;
+ measuredHeight = wantedWidth;
+ }
+
@Override
protected void
onMeasure (int widthMeasureSpec, int heightMeasureSpec)
bitmapDirty = true;
/* Now expose the view contents again. */
- EmacsNative.sendExpose (this.window.handle, 0, 0,
- measuredWidth, measuredHeight);
+ EmacsNative.sendExpose (this.window.handle, 0, 0, 0, 0);
super.onAttachedToWindow ();
}
{
return icMode;
}
+
+ @Override
+ public void
+ onGlobalLayout ()
+ {
+ int[] locations;
+
+ /* Get the absolute offset of this view and specify its left and
+ top position in subsequent ConfigureNotify events. */
+
+ locations = new int[2];
+ getLocationInWindow (locations);
+ window.notifyContentRectPosition (locations[0],
+ locations[1]);
+ }
};
creating new bitmaps. */
public volatile int background;
+ /* The position of this window relative to the root window. */
+ public int xPosition, yPosition;
+
public
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
int width, int height, boolean overrideRedirect)
background = pixel;
}
- public Rect
+ public synchronized Rect
getGeometry ()
{
- synchronized (this)
- {
- /* Huh, this is it. */
- return rect;
- }
+ return new Rect (rect);
}
@Override
- public void
+ public synchronized void
destroyHandle () throws IllegalStateException
{
if (parent != null)
return attached;
}
- public long
+ public synchronized long
viewLayout (int left, int top, int right, int bottom)
{
int rectWidth, rectHeight;
- synchronized (this)
- {
- rect.left = left;
- rect.top = top;
- rect.right = right;
- rect.bottom = bottom;
- }
+ rect.left = left;
+ rect.top = top;
+ rect.right = right;
+ rect.bottom = bottom;
rectWidth = right - left;
rectHeight = bottom - top;
+ /* If parent is null, use xPosition and yPosition instead of the
+ geometry rectangle positions. */
+
+ if (parent == null)
+ {
+ left = xPosition;
+ top = yPosition;
+ }
+
return EmacsNative.sendConfigureNotify (this.handle,
System.currentTimeMillis (),
left, top, rectWidth,
public void
requestViewLayout ()
{
- /* This is necessary because otherwise subsequent drawing on the
- Emacs thread may be lost. */
view.explicitlyDirtyBitmap ();
EmacsService.SERVICE.runOnUiThread (new Runnable () {
});
}
- public void
+ public synchronized void
resizeWindow (int width, int height)
{
- synchronized (this)
- {
- rect.right = rect.left + width;
- rect.bottom = rect.top + height;
+ rect.right = rect.left + width;
+ rect.bottom = rect.top + height;
- requestViewLayout ();
- }
+ requestViewLayout ();
}
- public void
+ public synchronized void
moveWindow (int x, int y)
{
int width, height;
- synchronized (this)
- {
- width = rect.width ();
- height = rect.height ();
+ width = rect.width ();
+ height = rect.height ();
- rect.left = x;
- rect.top = y;
- rect.right = x + width;
- rect.bottom = y + height;
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
- requestViewLayout ();
- }
+ requestViewLayout ();
}
private WindowManager.LayoutParams
return EmacsService.SERVICE;
}
- public void
+ public synchronized void
mapWindow ()
{
+ final int width, height;
+
if (isMapped)
return;
isMapped = true;
+ width = rect.width ();
+ height = rect.height ();
if (parent == null)
{
/* Attach the view. */
try
{
+ view.prepareForLayout (width, height);
windowManager.addView (view, params);
/* Record the window manager being used in the
public void
run ()
{
+ /* Prior to mapping the view, set its measuredWidth and
+ measuredHeight to some reasonable value, in order to
+ avoid excessive bitmap dirtying. */
+
+ view.prepareForLayout (width, height);
view.setVisibility (View.VISIBLE);
if (!getDontFocusOnMap ())
- /* Eventually this should check no-focus-on-map. */
view.requestFocus ();
}
});
public void
clearWindow ()
{
- synchronized (this)
- {
- EmacsService.SERVICE.fillRectangle (this, scratchGC,
- 0, 0, rect.width (),
- rect.height ());
- }
+ EmacsService.SERVICE.fillRectangle (this, scratchGC,
+ 0, 0, rect.width (),
+ rect.height ());
}
public void
return false;
}
- public void
+ public synchronized void
reparentTo (final EmacsWindow otherWindow, int x, int y)
{
int width, height;
parent = otherWindow;
/* Move this window to the new location. */
- synchronized (this)
- {
- width = rect.width ();
- height = rect.height ();
- rect.left = x;
- rect.top = y;
- rect.right = x + width;
- rect.bottom = y + height;
- }
+ width = rect.width ();
+ height = rect.height ();
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
/* Now do the work necessary on the UI thread to reparent the
window. */
});
}
- public void
+ public synchronized void
raise ()
{
/* This does nothing here. */
});
}
- public void
+ public synchronized void
lower ()
{
/* This does nothing here. */
});
}
- public int[]
+ public synchronized int[]
getWindowGeometry ()
{
int[] array;
- Rect rect;
array = new int[4];
- rect = getGeometry ();
- array[0] = rect.left;
- array[1] = rect.top;
+ array[0] = parent != null ? rect.left : xPosition;
+ array[1] = parent != null ? rect.top : yPosition;
array[2] = rect.width ();
array[3] = rect.height ();
}
});
}
+
+ public synchronized void
+ notifyContentRectPosition (int xPosition, int yPosition)
+ {
+ Rect geometry;
+
+ /* Ignore these notifications if not a child of the root
+ window. */
+ if (parent != null)
+ return;
+
+ /* xPosition and yPosition are the position of this window
+ relative to the screen. Set them and request a ConfigureNotify
+ event. */
+
+ if (this.xPosition != xPosition
+ || this.yPosition != yPosition)
+ {
+ this.xPosition = xPosition;
+ this.yPosition = yPosition;
+
+ EmacsNative.sendConfigureNotify (this.handle,
+ System.currentTimeMillis (),
+ xPosition, yPosition,
+ rect.width (), rect.height ());
+ }
+ }
};
import java.util.ArrayList;
import java.util.List;
+import android.app.ActivityOptions;
import android.content.Intent;
+import android.os.Build;
import android.util.Log;
/* Code to paper over the differences in lifecycles between
registerWindow (EmacsWindow window)
{
Intent intent;
+ ActivityOptions options;
Log.d (TAG, "registerWindow (maybe): " + window);
intent.addFlags (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
| Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- EmacsService.SERVICE.startActivity (intent);
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
+ EmacsService.SERVICE.startActivity (intent);
+ else
+ {
+ /* Specify the desired window size. */
+ options = ActivityOptions.makeBasic ();
+ options.setLaunchBounds (window.getGeometry ());
+ EmacsService.SERVICE.startActivity (intent,
+ options.toBundle ());
+ }
+
Log.d (TAG, "registerWindow: startActivity");
}
cancel_mouse_face (f);
}
+ /* Now change the left and top position of this window. */
+
+ {
+ int old_left = f->left_pos;
+ int old_top = f->top_pos;
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+
+ {
+ android_window root;
+ unsigned int dummy_uint;
+
+ android_get_geometry (FRAME_ANDROID_WINDOW (f),
+ &root, &f->left_pos, &f->top_pos,
+ &dummy_uint, &dummy_uint,
+ &dummy_uint);
+ }
+
+ if (!FRAME_TOOLTIP_P (f)
+ && (old_left != f->left_pos || old_top != f->top_pos))
+ {
+ inev.ie.kind = MOVE_FRAME_EVENT;
+ XSETFRAME (inev.ie.frame_or_window, f);
+ }
+ }
+
goto OTHER;
case ANDROID_KEY_PRESS:
if (!FRAME_GARBAGED_P (f))
{
+ __android_log_print (ANDROID_LOG_VERBOSE, __func__,
+ "expose: %d %d %d %d\n",
+ event->xexpose.x, event->xexpose.y,
+ event->xexpose.width,
+ event->xexpose.height);
expose_frame (f, event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
show_back_buffer (f);