summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/Makefile.in2
-rwxr-xr-xjava/debug.sh110
-rw-r--r--java/org/gnu/emacs/EmacsActivity.java2
-rw-r--r--java/org/gnu/emacs/EmacsContextMenu.java213
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java2
-rw-r--r--java/org/gnu/emacs/EmacsGC.java1
-rw-r--r--java/org/gnu/emacs/EmacsService.java43
-rw-r--r--java/org/gnu/emacs/EmacsView.java47
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java157
9 files changed, 521 insertions, 56 deletions
diff --git a/java/Makefile.in b/java/Makefile.in
index 05e61dede89..c539fb0f1fb 100644
--- a/java/Makefile.in
+++ b/java/Makefile.in
@@ -168,4 +168,4 @@ clean:
rm -rf install-temp
find . -name '*.class' -delete
-maintainer-clean: clean
+maintainer-clean distclean bootstrap-clean: clean
diff --git a/java/debug.sh b/java/debug.sh
index 3e3e3d9c281..aa80aeeebcd 100755
--- a/java/debug.sh
+++ b/java/debug.sh
@@ -31,6 +31,7 @@ gdb_port=5039
jdb_port=64013
jdb=no
attach_existing=no
+gdbserver=
while [ $# -gt 0 ]; do
case "$1" in
@@ -41,6 +42,7 @@ while [ $# -gt 0 ]; do
echo "You must specify an argument to --device"
exit 1
fi
+ shift
;;
"--help" )
echo "Usage: $progname [options] -- [gdb options]"
@@ -50,6 +52,7 @@ while [ $# -gt 0 ]; do
echo " --jdb-port PORT run the JDB server on a specific port"
echo " --jdb run JDB instead of GDB"
echo " --attach-existing attach to an existing process"
+ echo " --gdbserver BINARY upload and use the specified gdbserver binary"
echo " --help print this message"
echo ""
echo "Available devices:"
@@ -62,9 +65,18 @@ while [ $# -gt 0 ]; do
"--jdb" )
jdb=yes
;;
+ "--gdbserver" )
+ shift
+ gdbserver=$1
+ ;;
"--port" )
+ shift
gdb_port=$1
;;
+ "--jdb-port" )
+ shift
+ jdb_port=$1
+ ;;
"--attach-existing" )
attach_existing=yes
;;
@@ -170,46 +182,71 @@ elif [ -z $package_pids ]; then
exit 1
fi
-# Start JDB to make the wait dialog disappear.
-echo "Attaching JDB to unblock the application."
-adb -s $device forward --remove-all
-adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
+# This isn't necessary when attaching gdb to an existing process.
+if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
+ # Start JDB to make the wait dialog disappear.
+ echo "Attaching JDB to unblock the application."
+ adb -s $device forward --remove-all
+ adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
-if [ ! $? ]; then
- echo "Failed to forward jdwp:$pid to $jdb_port!"
- echo "Perhaps you need to specify a different port with --port?"
- exit 1;
-fi
+ if [ ! $? ]; then
+ echo "Failed to forward jdwp:$pid to $jdb_port!"
+ echo "Perhaps you need to specify a different port with --port?"
+ exit 1;
+ fi
-jdb_command="jdb -connect \
+ jdb_command="jdb -connect \
com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
-if [ $jdb = "yes" ]; then
- # Just start JDB and then exit
- $jdb_command
- exit 1
-fi
+ if [ $jdb = "yes" ]; then
+ # Just start JDB and then exit
+ $jdb_command
+ exit 1
+ fi
-exec 4<> /tmp/file-descriptor-stamp
+ exec 4<> /tmp/file-descriptor-stamp
-# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
-$jdb_command <&4 >&4 &
+ # Now run JDB with IO redirected to file descriptor 4 in a subprocess.
+ $jdb_command <&4 >&4 &
-character=
-# Next, wait until the prompt is found.
-while read -n1 -u 4 character; do
- if [ "$character" = ">" ]; then
- echo "JDB attached successfully"
- break;
- fi
-done
+ character=
+ # Next, wait until the prompt is found.
+ while read -n1 -u 4 character; do
+ if [ "$character" = ">" ]; then
+ echo "JDB attached successfully"
+ break;
+ fi
+ done
+fi
+
+# See if gdbserver has to be uploaded
+if [ -z "$gdbserver" ]; then
+ gdbserver_bin=/system/bin/gdbserver
+else
+ gdbserver_bin=/data/local/tmp/gdbserver
+
+ # Upload the specified gdbserver binary to the device.
+ adb -s $device push "$gdbserver" "$gdbserver_bin"
+ adb -s $device shell chmod +x "$gdbserver_bin"
+fi
# Now start gdbserver on the device asynchronously.
echo "Attaching gdbserver to $pid on $device..."
exec 5<> /tmp/file-descriptor-stamp
-adb -s $device shell run-as $package /system/bin/gdbserver --once \
- "+debug.$package_uid.socket" --attach $pid >&5 &
+
+if [ -z "$gdbserver" ]; then
+ adb -s $device shell run-as $package $gdbserver_bin --once \
+ "+debug.$package_uid.socket" --attach $pid >&5 &
+ gdb_socket="localfilesystem:$app_data_dir/debug.$package_uid.socket"
+else
+ # Normally the program cannot access $gdbserver_bin when it is
+ # placed in /data/local/tmp.
+ adb -s $device shell $gdbserver_bin --once \
+ "+/data/local/tmp/debug.$package_uid.socket" \
+ --attach $pid >&5 &
+ gdb_socket="localfilesystem:/data/local/tmp/debug.$package_uid.socket"
+fi
# Wait until gdbserver successfully runs.
line=
@@ -227,16 +264,17 @@ while read -u 5 line; do
esac
done
-# Send EOF to JDB to make it go away. This will also cause Android to
-# allow Emacs to continue executing.
-echo "Making JDB go away..."
-echo "exit" >&4
-read -u 4 line
-echo "JDB has gone away with $line"
+if [ "$attach_existing" != "yes" ]; then
+ # Send EOF to JDB to make it go away. This will also cause
+ # Android to allow Emacs to continue executing.
+ echo "Making JDB go away..."
+ echo "exit" >&4
+ read -u 4 line
+ echo "JDB has gone away with $line"
+fi
# Forward the gdb server port here.
-adb -s $device forward "tcp:$gdb_port" \
- "localfilesystem:$app_data_dir/debug.$package_uid.socket"
+adb -s $device forward "tcp:$gdb_port" $gdb_socket
if [ ! $? ]; then
echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
echo "to $gdb_port! Perhaps you need to specify a different port"
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java
index 2b661024842..4cd286d1e89 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -43,7 +43,7 @@ public class EmacsActivity extends Activity
private FrameLayout layout;
/* List of activities with focus. */
- private static List<EmacsActivity> focusedActivities;
+ public static List<EmacsActivity> focusedActivities;
/* The currently focused window. */
public static EmacsWindow focusedWindow;
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
new file mode 100644
index 00000000000..8d7ae08b257
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -0,0 +1,213 @@
+/* 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 java.util.List;
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.content.Intent;
+
+import android.os.Bundle;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+import android.widget.PopupMenu;
+
+/* Context menu implementation. This object is built from JNI and
+ describes a menu hiearchy. Then, `inflate' can turn it into an
+ Android menu, which can be turned into a popup (or other kind of)
+ menu. */
+
+public class EmacsContextMenu
+{
+ private class Item
+ {
+ public int itemID;
+ public String itemName;
+ public EmacsContextMenu subMenu;
+ public boolean isEnabled;
+ };
+
+ public List<Item> menuItems;
+ public String title;
+ private EmacsContextMenu parent;
+
+ /* Create a context menu with no items inside and the title TITLE,
+ which may be NULL. */
+
+ public static EmacsContextMenu
+ createContextMenu (String title)
+ {
+ EmacsContextMenu menu;
+
+ menu = new EmacsContextMenu ();
+ menu.menuItems = new ArrayList<Item> ();
+ menu.title = title;
+
+ return menu;
+ }
+
+ /* Add a normal menu item to the context menu with the id ITEMID and
+ the name ITEMNAME. Enable it if ISENABLED, else keep it
+ disabled. */
+
+ public void
+ addItem (int itemID, String itemName, boolean isEnabled)
+ {
+ Item item;
+
+ item = new Item ();
+ item.itemID = itemID;
+ item.itemName = itemName;
+ item.isEnabled = isEnabled;
+
+ menuItems.add (item);
+ }
+
+ /* Create a disabled menu item with the name ITEMNAME. */
+
+ public void
+ addPane (String itemName)
+ {
+ Item item;
+
+ item = new Item ();
+ item.itemName = itemName;
+
+ menuItems.add (item);
+ }
+
+ /* Add a submenu to the context menu with the specified title and
+ item name. */
+
+ public EmacsContextMenu
+ addSubmenu (String itemName, String title)
+ {
+ EmacsContextMenu submenu;
+ Item item;
+
+ item = new Item ();
+ item.itemID = 0;
+ item.itemName = itemName;
+ item.subMenu = createContextMenu (title);
+ item.subMenu.parent = this;
+
+ menuItems.add (item);
+ return item.subMenu;
+ }
+
+ /* Add the contents of this menu to MENU. */
+
+ private void
+ inflateMenuItems (Menu menu)
+ {
+ Intent intent;
+ MenuItem menuItem;
+ Menu submenu;
+
+ for (Item item : menuItems)
+ {
+ if (item.subMenu != null)
+ {
+ /* This is a submenu. Create the submenu and add the
+ contents of the menu to it. */
+ submenu = menu.addSubMenu (item.itemName);
+ inflateMenuItems (submenu);
+ }
+ else
+ {
+ menuItem = menu.add (item.itemName);
+
+ /* If the item ID is zero, then disable the item. */
+ if (item.itemID == 0 || !item.isEnabled)
+ menuItem.setEnabled (false);
+ }
+ }
+ }
+
+ /* Enter the items in this context menu to MENU. Create each menu
+ item with an Intent containing a Bundle, where the key
+ "emacs:menu_item_hi" maps to the high 16 bits of the
+ corresponding item ID, and the key "emacs:menu_item_low" maps to
+ the low 16 bits of the item ID. */
+
+ public void
+ expandTo (Menu menu)
+ {
+ inflateMenuItems (menu);
+ }
+
+ /* Return the parent or NULL. */
+
+ public EmacsContextMenu
+ parent ()
+ {
+ return parent;
+ }
+
+ /* Like display, but does the actual work and runs in the main
+ thread. */
+
+ private boolean
+ display1 (EmacsWindow window, int xPosition, int yPosition)
+ {
+ return window.view.popupMenu (this, xPosition, yPosition);
+ }
+
+ /* Display this context menu on WINDOW, at xPosition and
+ yPosition. */
+
+ public boolean
+ display (final EmacsWindow window, final int xPosition,
+ final int yPosition)
+ {
+ Runnable runnable;
+ final Holder<Boolean> rc;
+
+ rc = new Holder<Boolean> ();
+
+ runnable = new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ synchronized (this)
+ {
+ rc.thing = display1 (window, xPosition, yPosition);
+ notify ();
+ }
+ }
+ };
+
+ try
+ {
+ runnable.wait ();
+ }
+ catch (InterruptedException e)
+ {
+ EmacsNative.emacsAbort ();
+ }
+
+ return rc.thing;
+ }
+};
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
index b42e9556e8c..84ff498847b 100644
--- a/java/org/gnu/emacs/EmacsDrawRectangle.java
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -59,7 +59,7 @@ public class EmacsDrawRectangle
}
paint = gc.gcPaint;
- rect = new Rect (x, y, x + width, y + height);
+ rect = new Rect (x + 1, y + 1, x + width, y + height);
paint.setStyle (Paint.Style.STROKE);
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
index caa5c91edd4..c579625f3f7 100644
--- a/java/org/gnu/emacs/EmacsGC.java
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -93,6 +93,7 @@ public class EmacsGC extends EmacsHandleObject
else
real_clip_rects = clip_rects;
+ gcPaint.setStrokeWidth (1f);
gcPaint.setColor (foreground | 0xff000000);
gcPaint.setXfermode (function == GC_XOR
? xorAlu : srcInAlu);
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index c008300dd3a..f935b63fa0d 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -29,6 +29,7 @@ import android.graphics.Point;
import android.view.View;
import android.view.InputDevice;
+import android.view.KeyEvent;
import android.annotation.TargetApi;
import android.app.Service;
@@ -150,13 +151,13 @@ public class EmacsService extends Service
/* Functions from here on must only be called from the Emacs
thread. */
- void
+ public void
runOnUiThread (Runnable runnable)
{
handler.post (runnable);
}
- EmacsView
+ public EmacsView
getEmacsView (final EmacsWindow window, final int visibility,
final boolean isFocusedByDefault)
{
@@ -197,6 +198,38 @@ public class EmacsService extends Service
}
public void
+ getLocationOnScreen (final EmacsView view, final int[] coordinates)
+ {
+ Runnable runnable;
+
+ runnable = new Runnable () {
+ public void
+ run ()
+ {
+ synchronized (this)
+ {
+ view.getLocationOnScreen (coordinates);
+ notify ();
+ }
+ }
+ };
+
+ synchronized (runnable)
+ {
+ runOnUiThread (runnable);
+
+ try
+ {
+ runnable.wait ();
+ }
+ catch (InterruptedException e)
+ {
+ EmacsNative.emacsAbort ();
+ }
+ }
+ }
+
+ public void
fillRectangle (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
@@ -368,4 +401,10 @@ public class EmacsService extends Service
return false;
}
+
+ public String
+ nameKeysym (int keysym)
+ {
+ return KeyEvent.keyCodeToString (keysym);
+ }
};
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 41acabab97b..1391f630be0 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -21,6 +21,7 @@ package org.gnu.emacs;
import android.content.res.ColorStateList;
+import android.view.ContextMenu;
import android.view.View;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -73,6 +74,12 @@ public class EmacsView extends ViewGroup
next call to getBitmap. */
private Rect bitmapDirty;
+ /* Whether or not a popup is active. */
+ private boolean popupActive;
+
+ /* The current context menu. */
+ private EmacsContextMenu contextMenu;
+
public
EmacsView (EmacsWindow window)
{
@@ -98,6 +105,10 @@ public class EmacsView extends ViewGroup
/* Get rid of the foreground and background tint. */
setBackgroundTintList (null);
setForegroundTintList (null);
+
+ /* Get rid of the default focus highlight. */
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
+ setDefaultFocusHighlightEnabled (false);
}
private void
@@ -423,4 +434,40 @@ public class EmacsView extends ViewGroup
removeView (surfaceView);
addView (surfaceView, 0);
}
+
+ @Override
+ protected void
+ onCreateContextMenu (ContextMenu menu)
+ {
+ if (contextMenu == null)
+ return;
+
+ contextMenu.expandTo (menu);
+ }
+
+ public boolean
+ popupMenu (EmacsContextMenu menu, int xPosition,
+ int yPosition)
+ {
+ if (popupActive)
+ return false;
+
+ contextMenu = menu;
+
+ /* On API 21 or later, use showContextMenu (float, float). */
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
+ return showContextMenu ((float) xPosition, (float) yPosition);
+ else
+ return showContextMenu ();
+ }
+
+ public void
+ cancelPopupMenu ()
+ {
+ if (!popupActive)
+ throw new IllegalStateException ("cancelPopupMenu called without"
+ + " popupActive set");
+
+ contextMenu = null;
+ }
};
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index 1f8596dba50..6effa79d1a4 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -24,16 +24,22 @@ import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
+import android.content.Context;
+
import android.graphics.Rect;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.PixelFormat;
import android.view.View;
+import android.view.ViewManager;
import android.view.ViewGroup;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.InputDevice;
+import android.view.WindowManager;
import android.content.Intent;
import android.util.Log;
@@ -110,9 +116,17 @@ public class EmacsWindow extends EmacsHandleObject
not the window should be focusable. */
private boolean dontFocusOnMap, dontAcceptFocus;
+ /* Whether or not the window is override-redirect. An
+ override-redirect window always has its own system window. */
+ private boolean overrideRedirect;
+
+ /* The window manager that is the parent of this window. NULL if
+ there is no such window manager. */
+ private WindowManager windowManager;
+
public
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
- int width, int height)
+ int width, int height, boolean overrideRedirect)
{
super (handle);
@@ -124,6 +138,7 @@ public class EmacsWindow extends EmacsHandleObject
view = EmacsService.SERVICE.getEmacsView (this, View.GONE,
parent == null);
this.parent = parent;
+ this.overrideRedirect = overrideRedirect;
/* Create the list of children. */
children = new ArrayList<EmacsWindow> ();
@@ -180,7 +195,7 @@ public class EmacsWindow extends EmacsHandleObject
public void
run ()
{
- View parent;
+ ViewManager parent;
EmacsWindowAttachmentManager manager;
if (EmacsActivity.focusedWindow == EmacsWindow.this)
@@ -189,10 +204,15 @@ public class EmacsWindow extends EmacsHandleObject
manager = EmacsWindowAttachmentManager.MANAGER;
view.setVisibility (View.GONE);
- parent = (View) view.getParent ();
+ /* If the window manager is set, use that instead. */
+ if (windowManager != null)
+ parent = windowManager;
+ else
+ parent = (ViewManager) view.getParent ();
+ windowManager = null;
if (parent != null)
- ((ViewGroup) parent).removeView (view);
+ parent.removeView (view);
manager.detachWindow (EmacsWindow.this);
}
@@ -247,6 +267,10 @@ public class EmacsWindow extends EmacsHandleObject
public void
run ()
{
+ if (overrideRedirect)
+ /* Set the layout parameters again. */
+ view.setLayoutParams (getWindowLayoutParams ());
+
view.mustReportLayout = true;
view.requestLayout ();
}
@@ -284,6 +308,39 @@ public class EmacsWindow extends EmacsHandleObject
}
}
+ private WindowManager.LayoutParams
+ getWindowLayoutParams ()
+ {
+ WindowManager.LayoutParams params;
+ int flags, type;
+ Rect rect;
+
+ flags = 0;
+ rect = getGeometry ();
+ flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+
+ params
+ = new WindowManager.LayoutParams (rect.width (), rect.height (),
+ rect.left, rect.top,
+ type, flags,
+ PixelFormat.RGBA_8888);
+ params.gravity = Gravity.TOP | Gravity.LEFT;
+ return params;
+ }
+
+ private Context
+ findSuitableActivityContext ()
+ {
+ /* Find a recently focused activity. */
+ if (!EmacsActivity.focusedActivities.isEmpty ())
+ return EmacsActivity.focusedActivities.get (0);
+
+ /* Return the service context, which probably won't work. */
+ return EmacsService.SERVICE;
+ }
+
public void
mapWindow ()
{
@@ -300,20 +357,60 @@ public class EmacsWindow extends EmacsHandleObject
run ()
{
EmacsWindowAttachmentManager manager;
+ WindowManager windowManager;
+ Context ctx;
+ Object tem;
+ WindowManager.LayoutParams params;
/* Make the view visible, first of all. */
view.setVisibility (View.VISIBLE);
- manager = EmacsWindowAttachmentManager.MANAGER;
+ if (!overrideRedirect)
+ {
+ manager = EmacsWindowAttachmentManager.MANAGER;
- /* If parent is the root window, notice that there are new
- children available for interested activites to pick
- up. */
- manager.registerWindow (EmacsWindow.this);
+ /* If parent is the root window, notice that there are new
+ children available for interested activites to pick
+ up. */
+ manager.registerWindow (EmacsWindow.this);
- if (!getDontFocusOnMap ())
- /* Eventually this should check no-focus-on-map. */
- view.requestFocus ();
+ if (!getDontFocusOnMap ())
+ /* Eventually this should check no-focus-on-map. */
+ view.requestFocus ();
+ }
+ else
+ {
+ /* But if the window is an override-redirect window,
+ then:
+
+ - Find an activity that is currently active.
+
+ - Map the window as a panel on top of that
+ activity using the system window manager. */
+
+ ctx = findSuitableActivityContext ();
+ tem = ctx.getSystemService (Context.WINDOW_SERVICE);
+ windowManager = (WindowManager) tem;
+
+ /* Calculate layout parameters. */
+ params = getWindowLayoutParams ();
+ view.setLayoutParams (params);
+
+ /* Attach the view. */
+ try
+ {
+ windowManager.addView (view, params);
+
+ /* Record the window manager being used in the
+ EmacsWindow object. */
+ EmacsWindow.this.windowManager = windowManager;
+ }
+ catch (Exception e)
+ {
+ Log.w (TAG,
+ "failed to attach override-redirect window, " + e);
+ }
+ }
}
});
}
@@ -355,6 +452,11 @@ public class EmacsWindow extends EmacsHandleObject
view.setVisibility (View.GONE);
+ /* Detach the view from the window manager if possible. */
+ if (windowManager != null)
+ windowManager.removeView (view);
+ windowManager = null;
+
/* Now that the window is unmapped, unregister it as
well. */
manager.detachWindow (EmacsWindow.this);
@@ -756,17 +858,23 @@ public class EmacsWindow extends EmacsHandleObject
run ()
{
EmacsWindowAttachmentManager manager;
- View parent;
+ ViewManager parent;
/* First, detach this window if necessary. */
manager = EmacsWindowAttachmentManager.MANAGER;
manager.detachWindow (EmacsWindow.this);
/* Also unparent this view. */
- parent = (View) view.getParent ();
+
+ /* If the window manager is set, use that instead. */
+ if (windowManager != null)
+ parent = windowManager;
+ else
+ parent = (ViewManager) view.getParent ();
+ windowManager = null;
if (parent != null)
- ((ViewGroup) parent).removeView (view);
+ parent.removeView (view);
/* Next, either add this window as a child of the new
parent's view, or make it available again. */
@@ -899,4 +1007,23 @@ public class EmacsWindow extends EmacsHandleObject
{
return dontFocusOnMap;
}
+
+ public int[]
+ translateCoordinates (int x, int y)
+ {
+ int[] array;
+
+ /* This is supposed to translate coordinates to the root
+ window. */
+ array = new int[2];
+ EmacsService.SERVICE.getLocationOnScreen (view, array);
+
+ /* Now, the coordinates of the view should be in array. Offset X
+ and Y by them. */
+ array[0] += x;
+ array[1] += y;
+
+ /* Return the resulting coordinates. */
+ return array;
+ }
};