aboutsummaryrefslogtreecommitdiffstats
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.java161
9 files changed, 523 insertions, 58 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:
168 rm -rf install-temp 168 rm -rf install-temp
169 find . -name '*.class' -delete 169 find . -name '*.class' -delete
170 170
171maintainer-clean: clean 171maintainer-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
31jdb_port=64013 31jdb_port=64013
32jdb=no 32jdb=no
33attach_existing=no 33attach_existing=no
34gdbserver=
34 35
35while [ $# -gt 0 ]; do 36while [ $# -gt 0 ]; do
36 case "$1" in 37 case "$1" in
@@ -41,6 +42,7 @@ while [ $# -gt 0 ]; do
41 echo "You must specify an argument to --device" 42 echo "You must specify an argument to --device"
42 exit 1 43 exit 1
43 fi 44 fi
45 shift
44 ;; 46 ;;
45 "--help" ) 47 "--help" )
46 echo "Usage: $progname [options] -- [gdb options]" 48 echo "Usage: $progname [options] -- [gdb options]"
@@ -50,6 +52,7 @@ while [ $# -gt 0 ]; do
50 echo " --jdb-port PORT run the JDB server on a specific port" 52 echo " --jdb-port PORT run the JDB server on a specific port"
51 echo " --jdb run JDB instead of GDB" 53 echo " --jdb run JDB instead of GDB"
52 echo " --attach-existing attach to an existing process" 54 echo " --attach-existing attach to an existing process"
55 echo " --gdbserver BINARY upload and use the specified gdbserver binary"
53 echo " --help print this message" 56 echo " --help print this message"
54 echo "" 57 echo ""
55 echo "Available devices:" 58 echo "Available devices:"
@@ -62,9 +65,18 @@ while [ $# -gt 0 ]; do
62 "--jdb" ) 65 "--jdb" )
63 jdb=yes 66 jdb=yes
64 ;; 67 ;;
68 "--gdbserver" )
69 shift
70 gdbserver=$1
71 ;;
65 "--port" ) 72 "--port" )
73 shift
66 gdb_port=$1 74 gdb_port=$1
67 ;; 75 ;;
76 "--jdb-port" )
77 shift
78 jdb_port=$1
79 ;;
68 "--attach-existing" ) 80 "--attach-existing" )
69 attach_existing=yes 81 attach_existing=yes
70 ;; 82 ;;
@@ -170,46 +182,71 @@ elif [ -z $package_pids ]; then
170 exit 1 182 exit 1
171fi 183fi
172 184
173# Start JDB to make the wait dialog disappear. 185# This isn't necessary when attaching gdb to an existing process.
174echo "Attaching JDB to unblock the application." 186if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
175adb -s $device forward --remove-all 187 # Start JDB to make the wait dialog disappear.
176adb -s $device forward "tcp:$jdb_port" "jdwp:$pid" 188 echo "Attaching JDB to unblock the application."
189 adb -s $device forward --remove-all
190 adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
177 191
178if [ ! $? ]; then 192 if [ ! $? ]; then
179 echo "Failed to forward jdwp:$pid to $jdb_port!" 193 echo "Failed to forward jdwp:$pid to $jdb_port!"
180 echo "Perhaps you need to specify a different port with --port?" 194 echo "Perhaps you need to specify a different port with --port?"
181 exit 1; 195 exit 1;
182fi 196 fi
183 197
184jdb_command="jdb -connect \ 198 jdb_command="jdb -connect \
185 com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port" 199 com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
186 200
187if [ $jdb = "yes" ]; then 201 if [ $jdb = "yes" ]; then
188 # Just start JDB and then exit 202 # Just start JDB and then exit
189 $jdb_command 203 $jdb_command
190 exit 1 204 exit 1
191fi 205 fi
192 206
193exec 4<> /tmp/file-descriptor-stamp 207 exec 4<> /tmp/file-descriptor-stamp
194 208
195# Now run JDB with IO redirected to file descriptor 4 in a subprocess. 209 # Now run JDB with IO redirected to file descriptor 4 in a subprocess.
196$jdb_command <&4 >&4 & 210 $jdb_command <&4 >&4 &
197 211
198character= 212 character=
199# Next, wait until the prompt is found. 213 # Next, wait until the prompt is found.
200while read -n1 -u 4 character; do 214 while read -n1 -u 4 character; do
201 if [ "$character" = ">" ]; then 215 if [ "$character" = ">" ]; then
202 echo "JDB attached successfully" 216 echo "JDB attached successfully"
203 break; 217 break;
204 fi 218 fi
205done 219 done
220fi
221
222# See if gdbserver has to be uploaded
223if [ -z "$gdbserver" ]; then
224 gdbserver_bin=/system/bin/gdbserver
225else
226 gdbserver_bin=/data/local/tmp/gdbserver
227
228 # Upload the specified gdbserver binary to the device.
229 adb -s $device push "$gdbserver" "$gdbserver_bin"
230 adb -s $device shell chmod +x "$gdbserver_bin"
231fi
206 232
207# Now start gdbserver on the device asynchronously. 233# Now start gdbserver on the device asynchronously.
208 234
209echo "Attaching gdbserver to $pid on $device..." 235echo "Attaching gdbserver to $pid on $device..."
210exec 5<> /tmp/file-descriptor-stamp 236exec 5<> /tmp/file-descriptor-stamp
211adb -s $device shell run-as $package /system/bin/gdbserver --once \ 237
212 "+debug.$package_uid.socket" --attach $pid >&5 & 238if [ -z "$gdbserver" ]; then
239 adb -s $device shell run-as $package $gdbserver_bin --once \
240 "+debug.$package_uid.socket" --attach $pid >&5 &
241 gdb_socket="localfilesystem:$app_data_dir/debug.$package_uid.socket"
242else
243 # Normally the program cannot access $gdbserver_bin when it is
244 # placed in /data/local/tmp.
245 adb -s $device shell $gdbserver_bin --once \
246 "+/data/local/tmp/debug.$package_uid.socket" \
247 --attach $pid >&5 &
248 gdb_socket="localfilesystem:/data/local/tmp/debug.$package_uid.socket"
249fi
213 250
214# Wait until gdbserver successfully runs. 251# Wait until gdbserver successfully runs.
215line= 252line=
@@ -227,16 +264,17 @@ while read -u 5 line; do
227 esac 264 esac
228done 265done
229 266
230# Send EOF to JDB to make it go away. This will also cause Android to 267if [ "$attach_existing" != "yes" ]; then
231# allow Emacs to continue executing. 268 # Send EOF to JDB to make it go away. This will also cause
232echo "Making JDB go away..." 269 # Android to allow Emacs to continue executing.
233echo "exit" >&4 270 echo "Making JDB go away..."
234read -u 4 line 271 echo "exit" >&4
235echo "JDB has gone away with $line" 272 read -u 4 line
273 echo "JDB has gone away with $line"
274fi
236 275
237# Forward the gdb server port here. 276# Forward the gdb server port here.
238adb -s $device forward "tcp:$gdb_port" \ 277adb -s $device forward "tcp:$gdb_port" $gdb_socket
239 "localfilesystem:$app_data_dir/debug.$package_uid.socket"
240if [ ! $? ]; then 278if [ ! $? ]; then
241 echo "Failed to forward $app_data_dir/debug.$package_uid.socket" 279 echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
242 echo "to $gdb_port! Perhaps you need to specify a different port" 280 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
43 private FrameLayout layout; 43 private FrameLayout layout;
44 44
45 /* List of activities with focus. */ 45 /* List of activities with focus. */
46 private static List<EmacsActivity> focusedActivities; 46 public static List<EmacsActivity> focusedActivities;
47 47
48 /* The currently focused window. */ 48 /* The currently focused window. */
49 public static EmacsWindow focusedWindow; 49 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 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.List;
23import java.util.ArrayList;
24
25import android.content.Context;
26import android.content.Intent;
27
28import android.os.Bundle;
29
30import android.view.Menu;
31import android.view.MenuItem;
32import android.view.View;
33
34import android.widget.PopupMenu;
35
36/* Context menu implementation. This object is built from JNI and
37 describes a menu hiearchy. Then, `inflate' can turn it into an
38 Android menu, which can be turned into a popup (or other kind of)
39 menu. */
40
41public class EmacsContextMenu
42{
43 private class Item
44 {
45 public int itemID;
46 public String itemName;
47 public EmacsContextMenu subMenu;
48 public boolean isEnabled;
49 };
50
51 public List<Item> menuItems;
52 public String title;
53 private EmacsContextMenu parent;
54
55 /* Create a context menu with no items inside and the title TITLE,
56 which may be NULL. */
57
58 public static EmacsContextMenu
59 createContextMenu (String title)
60 {
61 EmacsContextMenu menu;
62
63 menu = new EmacsContextMenu ();
64 menu.menuItems = new ArrayList<Item> ();
65 menu.title = title;
66
67 return menu;
68 }
69
70 /* Add a normal menu item to the context menu with the id ITEMID and
71 the name ITEMNAME. Enable it if ISENABLED, else keep it
72 disabled. */
73
74 public void
75 addItem (int itemID, String itemName, boolean isEnabled)
76 {
77 Item item;
78
79 item = new Item ();
80 item.itemID = itemID;
81 item.itemName = itemName;
82 item.isEnabled = isEnabled;
83
84 menuItems.add (item);
85 }
86
87 /* Create a disabled menu item with the name ITEMNAME. */
88
89 public void
90 addPane (String itemName)
91 {
92 Item item;
93
94 item = new Item ();
95 item.itemName = itemName;
96
97 menuItems.add (item);
98 }
99
100 /* Add a submenu to the context menu with the specified title and
101 item name. */
102
103 public EmacsContextMenu
104 addSubmenu (String itemName, String title)
105 {
106 EmacsContextMenu submenu;
107 Item item;
108
109 item = new Item ();
110 item.itemID = 0;
111 item.itemName = itemName;
112 item.subMenu = createContextMenu (title);
113 item.subMenu.parent = this;
114
115 menuItems.add (item);
116 return item.subMenu;
117 }
118
119 /* Add the contents of this menu to MENU. */
120
121 private void
122 inflateMenuItems (Menu menu)
123 {
124 Intent intent;
125 MenuItem menuItem;
126 Menu submenu;
127
128 for (Item item : menuItems)
129 {
130 if (item.subMenu != null)
131 {
132 /* This is a submenu. Create the submenu and add the
133 contents of the menu to it. */
134 submenu = menu.addSubMenu (item.itemName);
135 inflateMenuItems (submenu);
136 }
137 else
138 {
139 menuItem = menu.add (item.itemName);
140
141 /* If the item ID is zero, then disable the item. */
142 if (item.itemID == 0 || !item.isEnabled)
143 menuItem.setEnabled (false);
144 }
145 }
146 }
147
148 /* Enter the items in this context menu to MENU. Create each menu
149 item with an Intent containing a Bundle, where the key
150 "emacs:menu_item_hi" maps to the high 16 bits of the
151 corresponding item ID, and the key "emacs:menu_item_low" maps to
152 the low 16 bits of the item ID. */
153
154 public void
155 expandTo (Menu menu)
156 {
157 inflateMenuItems (menu);
158 }
159
160 /* Return the parent or NULL. */
161
162 public EmacsContextMenu
163 parent ()
164 {
165 return parent;
166 }
167
168 /* Like display, but does the actual work and runs in the main
169 thread. */
170
171 private boolean
172 display1 (EmacsWindow window, int xPosition, int yPosition)
173 {
174 return window.view.popupMenu (this, xPosition, yPosition);
175 }
176
177 /* Display this context menu on WINDOW, at xPosition and
178 yPosition. */
179
180 public boolean
181 display (final EmacsWindow window, final int xPosition,
182 final int yPosition)
183 {
184 Runnable runnable;
185 final Holder<Boolean> rc;
186
187 rc = new Holder<Boolean> ();
188
189 runnable = new Runnable () {
190 @Override
191 public void
192 run ()
193 {
194 synchronized (this)
195 {
196 rc.thing = display1 (window, xPosition, yPosition);
197 notify ();
198 }
199 }
200 };
201
202 try
203 {
204 runnable.wait ();
205 }
206 catch (InterruptedException e)
207 {
208 EmacsNative.emacsAbort ();
209 }
210
211 return rc.thing;
212 }
213};
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
59 } 59 }
60 60
61 paint = gc.gcPaint; 61 paint = gc.gcPaint;
62 rect = new Rect (x, y, x + width, y + height); 62 rect = new Rect (x + 1, y + 1, x + width, y + height);
63 63
64 paint.setStyle (Paint.Style.STROKE); 64 paint.setStyle (Paint.Style.STROKE);
65 65
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
93 else 93 else
94 real_clip_rects = clip_rects; 94 real_clip_rects = clip_rects;
95 95
96 gcPaint.setStrokeWidth (1f);
96 gcPaint.setColor (foreground | 0xff000000); 97 gcPaint.setColor (foreground | 0xff000000);
97 gcPaint.setXfermode (function == GC_XOR 98 gcPaint.setXfermode (function == GC_XOR
98 ? xorAlu : srcInAlu); 99 ? 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;
29 29
30import android.view.View; 30import android.view.View;
31import android.view.InputDevice; 31import android.view.InputDevice;
32import android.view.KeyEvent;
32 33
33import android.annotation.TargetApi; 34import android.annotation.TargetApi;
34import android.app.Service; 35import android.app.Service;
@@ -150,13 +151,13 @@ public class EmacsService extends Service
150 /* Functions from here on must only be called from the Emacs 151 /* Functions from here on must only be called from the Emacs
151 thread. */ 152 thread. */
152 153
153 void 154 public void
154 runOnUiThread (Runnable runnable) 155 runOnUiThread (Runnable runnable)
155 { 156 {
156 handler.post (runnable); 157 handler.post (runnable);
157 } 158 }
158 159
159 EmacsView 160 public EmacsView
160 getEmacsView (final EmacsWindow window, final int visibility, 161 getEmacsView (final EmacsWindow window, final int visibility,
161 final boolean isFocusedByDefault) 162 final boolean isFocusedByDefault)
162 { 163 {
@@ -197,6 +198,38 @@ public class EmacsService extends Service
197 } 198 }
198 199
199 public void 200 public void
201 getLocationOnScreen (final EmacsView view, final int[] coordinates)
202 {
203 Runnable runnable;
204
205 runnable = new Runnable () {
206 public void
207 run ()
208 {
209 synchronized (this)
210 {
211 view.getLocationOnScreen (coordinates);
212 notify ();
213 }
214 }
215 };
216
217 synchronized (runnable)
218 {
219 runOnUiThread (runnable);
220
221 try
222 {
223 runnable.wait ();
224 }
225 catch (InterruptedException e)
226 {
227 EmacsNative.emacsAbort ();
228 }
229 }
230 }
231
232 public void
200 fillRectangle (EmacsDrawable drawable, EmacsGC gc, 233 fillRectangle (EmacsDrawable drawable, EmacsGC gc,
201 int x, int y, int width, int height) 234 int x, int y, int width, int height)
202 { 235 {
@@ -368,4 +401,10 @@ public class EmacsService extends Service
368 401
369 return false; 402 return false;
370 } 403 }
404
405 public String
406 nameKeysym (int keysym)
407 {
408 return KeyEvent.keyCodeToString (keysym);
409 }
371}; 410};
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;
21 21
22import android.content.res.ColorStateList; 22import android.content.res.ColorStateList;
23 23
24import android.view.ContextMenu;
24import android.view.View; 25import android.view.View;
25import android.view.KeyEvent; 26import android.view.KeyEvent;
26import android.view.MotionEvent; 27import android.view.MotionEvent;
@@ -73,6 +74,12 @@ public class EmacsView extends ViewGroup
73 next call to getBitmap. */ 74 next call to getBitmap. */
74 private Rect bitmapDirty; 75 private Rect bitmapDirty;
75 76
77 /* Whether or not a popup is active. */
78 private boolean popupActive;
79
80 /* The current context menu. */
81 private EmacsContextMenu contextMenu;
82
76 public 83 public
77 EmacsView (EmacsWindow window) 84 EmacsView (EmacsWindow window)
78 { 85 {
@@ -98,6 +105,10 @@ public class EmacsView extends ViewGroup
98 /* Get rid of the foreground and background tint. */ 105 /* Get rid of the foreground and background tint. */
99 setBackgroundTintList (null); 106 setBackgroundTintList (null);
100 setForegroundTintList (null); 107 setForegroundTintList (null);
108
109 /* Get rid of the default focus highlight. */
110 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
111 setDefaultFocusHighlightEnabled (false);
101 } 112 }
102 113
103 private void 114 private void
@@ -423,4 +434,40 @@ public class EmacsView extends ViewGroup
423 removeView (surfaceView); 434 removeView (surfaceView);
424 addView (surfaceView, 0); 435 addView (surfaceView, 0);
425 } 436 }
437
438 @Override
439 protected void
440 onCreateContextMenu (ContextMenu menu)
441 {
442 if (contextMenu == null)
443 return;
444
445 contextMenu.expandTo (menu);
446 }
447
448 public boolean
449 popupMenu (EmacsContextMenu menu, int xPosition,
450 int yPosition)
451 {
452 if (popupActive)
453 return false;
454
455 contextMenu = menu;
456
457 /* On API 21 or later, use showContextMenu (float, float). */
458 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
459 return showContextMenu ((float) xPosition, (float) yPosition);
460 else
461 return showContextMenu ();
462 }
463
464 public void
465 cancelPopupMenu ()
466 {
467 if (!popupActive)
468 throw new IllegalStateException ("cancelPopupMenu called without"
469 + " popupActive set");
470
471 contextMenu = null;
472 }
426}; 473};
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;
24import java.util.List; 24import java.util.List;
25import java.util.HashMap; 25import java.util.HashMap;
26 26
27import android.content.Context;
28
27import android.graphics.Rect; 29import android.graphics.Rect;
28import android.graphics.Canvas; 30import android.graphics.Canvas;
29import android.graphics.Bitmap; 31import android.graphics.Bitmap;
30import android.graphics.Point; 32import android.graphics.Point;
33import android.graphics.PixelFormat;
31 34
32import android.view.View; 35import android.view.View;
36import android.view.ViewManager;
33import android.view.ViewGroup; 37import android.view.ViewGroup;
38import android.view.Gravity;
34import android.view.KeyEvent; 39import android.view.KeyEvent;
35import android.view.MotionEvent; 40import android.view.MotionEvent;
36import android.view.InputDevice; 41import android.view.InputDevice;
42import android.view.WindowManager;
37 43
38import android.content.Intent; 44import android.content.Intent;
39import android.util.Log; 45import android.util.Log;
@@ -110,9 +116,17 @@ public class EmacsWindow extends EmacsHandleObject
110 not the window should be focusable. */ 116 not the window should be focusable. */
111 private boolean dontFocusOnMap, dontAcceptFocus; 117 private boolean dontFocusOnMap, dontAcceptFocus;
112 118
119 /* Whether or not the window is override-redirect. An
120 override-redirect window always has its own system window. */
121 private boolean overrideRedirect;
122
123 /* The window manager that is the parent of this window. NULL if
124 there is no such window manager. */
125 private WindowManager windowManager;
126
113 public 127 public
114 EmacsWindow (short handle, final EmacsWindow parent, int x, int y, 128 EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
115 int width, int height) 129 int width, int height, boolean overrideRedirect)
116 { 130 {
117 super (handle); 131 super (handle);
118 132
@@ -124,6 +138,7 @@ public class EmacsWindow extends EmacsHandleObject
124 view = EmacsService.SERVICE.getEmacsView (this, View.GONE, 138 view = EmacsService.SERVICE.getEmacsView (this, View.GONE,
125 parent == null); 139 parent == null);
126 this.parent = parent; 140 this.parent = parent;
141 this.overrideRedirect = overrideRedirect;
127 142
128 /* Create the list of children. */ 143 /* Create the list of children. */
129 children = new ArrayList<EmacsWindow> (); 144 children = new ArrayList<EmacsWindow> ();
@@ -180,7 +195,7 @@ public class EmacsWindow extends EmacsHandleObject
180 public void 195 public void
181 run () 196 run ()
182 { 197 {
183 View parent; 198 ViewManager parent;
184 EmacsWindowAttachmentManager manager; 199 EmacsWindowAttachmentManager manager;
185 200
186 if (EmacsActivity.focusedWindow == EmacsWindow.this) 201 if (EmacsActivity.focusedWindow == EmacsWindow.this)
@@ -189,10 +204,15 @@ public class EmacsWindow extends EmacsHandleObject
189 manager = EmacsWindowAttachmentManager.MANAGER; 204 manager = EmacsWindowAttachmentManager.MANAGER;
190 view.setVisibility (View.GONE); 205 view.setVisibility (View.GONE);
191 206
192 parent = (View) view.getParent (); 207 /* If the window manager is set, use that instead. */
208 if (windowManager != null)
209 parent = windowManager;
210 else
211 parent = (ViewManager) view.getParent ();
212 windowManager = null;
193 213
194 if (parent != null) 214 if (parent != null)
195 ((ViewGroup) parent).removeView (view); 215 parent.removeView (view);
196 216
197 manager.detachWindow (EmacsWindow.this); 217 manager.detachWindow (EmacsWindow.this);
198 } 218 }
@@ -247,6 +267,10 @@ public class EmacsWindow extends EmacsHandleObject
247 public void 267 public void
248 run () 268 run ()
249 { 269 {
270 if (overrideRedirect)
271 /* Set the layout parameters again. */
272 view.setLayoutParams (getWindowLayoutParams ());
273
250 view.mustReportLayout = true; 274 view.mustReportLayout = true;
251 view.requestLayout (); 275 view.requestLayout ();
252 } 276 }
@@ -284,6 +308,39 @@ public class EmacsWindow extends EmacsHandleObject
284 } 308 }
285 } 309 }
286 310
311 private WindowManager.LayoutParams
312 getWindowLayoutParams ()
313 {
314 WindowManager.LayoutParams params;
315 int flags, type;
316 Rect rect;
317
318 flags = 0;
319 rect = getGeometry ();
320 flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
321 flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
322 type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
323
324 params
325 = new WindowManager.LayoutParams (rect.width (), rect.height (),
326 rect.left, rect.top,
327 type, flags,
328 PixelFormat.RGBA_8888);
329 params.gravity = Gravity.TOP | Gravity.LEFT;
330 return params;
331 }
332
333 private Context
334 findSuitableActivityContext ()
335 {
336 /* Find a recently focused activity. */
337 if (!EmacsActivity.focusedActivities.isEmpty ())
338 return EmacsActivity.focusedActivities.get (0);
339
340 /* Return the service context, which probably won't work. */
341 return EmacsService.SERVICE;
342 }
343
287 public void 344 public void
288 mapWindow () 345 mapWindow ()
289 { 346 {
@@ -300,20 +357,60 @@ public class EmacsWindow extends EmacsHandleObject
300 run () 357 run ()
301 { 358 {
302 EmacsWindowAttachmentManager manager; 359 EmacsWindowAttachmentManager manager;
360 WindowManager windowManager;
361 Context ctx;
362 Object tem;
363 WindowManager.LayoutParams params;
303 364
304 /* Make the view visible, first of all. */ 365 /* Make the view visible, first of all. */
305 view.setVisibility (View.VISIBLE); 366 view.setVisibility (View.VISIBLE);
306 367
307 manager = EmacsWindowAttachmentManager.MANAGER; 368 if (!overrideRedirect)
308 369 {
309 /* If parent is the root window, notice that there are new 370 manager = EmacsWindowAttachmentManager.MANAGER;
310 children available for interested activites to pick 371
311 up. */ 372 /* If parent is the root window, notice that there are new
312 manager.registerWindow (EmacsWindow.this); 373 children available for interested activites to pick
313 374 up. */
314 if (!getDontFocusOnMap ()) 375 manager.registerWindow (EmacsWindow.this);
315 /* Eventually this should check no-focus-on-map. */ 376
316 view.requestFocus (); 377 if (!getDontFocusOnMap ())
378 /* Eventually this should check no-focus-on-map. */
379 view.requestFocus ();
380 }
381 else
382 {
383 /* But if the window is an override-redirect window,
384 then:
385
386 - Find an activity that is currently active.
387
388 - Map the window as a panel on top of that
389 activity using the system window manager. */
390
391 ctx = findSuitableActivityContext ();
392 tem = ctx.getSystemService (Context.WINDOW_SERVICE);
393 windowManager = (WindowManager) tem;
394
395 /* Calculate layout parameters. */
396 params = getWindowLayoutParams ();
397 view.setLayoutParams (params);
398
399 /* Attach the view. */
400 try
401 {
402 windowManager.addView (view, params);
403
404 /* Record the window manager being used in the
405 EmacsWindow object. */
406 EmacsWindow.this.windowManager = windowManager;
407 }
408 catch (Exception e)
409 {
410 Log.w (TAG,
411 "failed to attach override-redirect window, " + e);
412 }
413 }
317 } 414 }
318 }); 415 });
319 } 416 }
@@ -355,6 +452,11 @@ public class EmacsWindow extends EmacsHandleObject
355 452
356 view.setVisibility (View.GONE); 453 view.setVisibility (View.GONE);
357 454
455 /* Detach the view from the window manager if possible. */
456 if (windowManager != null)
457 windowManager.removeView (view);
458 windowManager = null;
459
358 /* Now that the window is unmapped, unregister it as 460 /* Now that the window is unmapped, unregister it as
359 well. */ 461 well. */
360 manager.detachWindow (EmacsWindow.this); 462 manager.detachWindow (EmacsWindow.this);
@@ -756,17 +858,23 @@ public class EmacsWindow extends EmacsHandleObject
756 run () 858 run ()
757 { 859 {
758 EmacsWindowAttachmentManager manager; 860 EmacsWindowAttachmentManager manager;
759 View parent; 861 ViewManager parent;
760 862
761 /* First, detach this window if necessary. */ 863 /* First, detach this window if necessary. */
762 manager = EmacsWindowAttachmentManager.MANAGER; 864 manager = EmacsWindowAttachmentManager.MANAGER;
763 manager.detachWindow (EmacsWindow.this); 865 manager.detachWindow (EmacsWindow.this);
764 866
765 /* Also unparent this view. */ 867 /* Also unparent this view. */
766 parent = (View) view.getParent (); 868
869 /* If the window manager is set, use that instead. */
870 if (windowManager != null)
871 parent = windowManager;
872 else
873 parent = (ViewManager) view.getParent ();
874 windowManager = null;
767 875
768 if (parent != null) 876 if (parent != null)
769 ((ViewGroup) parent).removeView (view); 877 parent.removeView (view);
770 878
771 /* Next, either add this window as a child of the new 879 /* Next, either add this window as a child of the new
772 parent's view, or make it available again. */ 880 parent's view, or make it available again. */
@@ -899,4 +1007,23 @@ public class EmacsWindow extends EmacsHandleObject
899 { 1007 {
900 return dontFocusOnMap; 1008 return dontFocusOnMap;
901 } 1009 }
1010
1011 public int[]
1012 translateCoordinates (int x, int y)
1013 {
1014 int[] array;
1015
1016 /* This is supposed to translate coordinates to the root
1017 window. */
1018 array = new int[2];
1019 EmacsService.SERVICE.getLocationOnScreen (view, array);
1020
1021 /* Now, the coordinates of the view should be in array. Offset X
1022 and Y by them. */
1023 array[0] += x;
1024 array[1] += y;
1025
1026 /* Return the resulting coordinates. */
1027 return array;
1028 }
902}; 1029};