diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/AndroidManifest.xml | 9 | ||||
| -rw-r--r-- | java/Makefile.in | 3 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsActivity.java | 153 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsCopyArea.java | 135 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsDrawRectangle.java | 8 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsFontDriver.java | 26 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsMultitaskActivity.java | 25 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsNative.java | 18 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsPaintQueue.java | 24 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsPixmap.java | 29 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsSdk23FontDriver.java | 43 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsSdk7FontDriver.java | 188 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 83 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsSurfaceView.java | 37 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 45 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindow.java | 143 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindowAttachmentManager.java | 166 |
17 files changed, 904 insertions, 231 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 75aa5bdf409..06417017ae3 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml | |||
| @@ -31,13 +31,15 @@ | |||
| 31 | android:targetSdkVersion="28"/> | 31 | android:targetSdkVersion="28"/> |
| 32 | 32 | ||
| 33 | <application android:name="org.gnu.emacs.EmacsApplication" | 33 | <application android:name="org.gnu.emacs.EmacsApplication" |
| 34 | android:label="GNU Emacs" | 34 | android:label="Emacs" |
| 35 | android:hardwareAccelerated="true" | 35 | android:hardwareAccelerated="true" |
| 36 | android:supportsRtl="true" | 36 | android:supportsRtl="true" |
| 37 | android:theme="@android:style/Theme" | 37 | android:theme="@android:style/Theme" |
| 38 | android:debuggable="true" | 38 | android:debuggable="true" |
| 39 | android:extractNativeLibs="true"> | 39 | android:extractNativeLibs="true"> |
| 40 | <activity android:name="org.gnu.emacs.EmacsActivity"> | 40 | <activity android:name="org.gnu.emacs.EmacsActivity" |
| 41 | android:launchMode="singleTop" | ||
| 42 | android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"> | ||
| 41 | <intent-filter> | 43 | <intent-filter> |
| 42 | <action android:name="android.intent.action.MAIN" /> | 44 | <action android:name="android.intent.action.MAIN" /> |
| 43 | <category android:name="android.intent.category.DEFAULT" /> | 45 | <category android:name="android.intent.category.DEFAULT" /> |
| @@ -45,6 +47,9 @@ | |||
| 45 | </intent-filter> | 47 | </intent-filter> |
| 46 | </activity> | 48 | </activity> |
| 47 | 49 | ||
| 50 | <activity android:name="org.gnu.emacs.EmacsMultitaskActivity" | ||
| 51 | android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/> | ||
| 52 | |||
| 48 | <service android:name="org.gnu.emacs.EmacsService" | 53 | <service android:name="org.gnu.emacs.EmacsService" |
| 49 | android:directBootAware="false" | 54 | android:directBootAware="false" |
| 50 | android:enabled="true" | 55 | android:enabled="true" |
diff --git a/java/Makefile.in b/java/Makefile.in index e9fcc625cb2..31bd22b5a2e 100644 --- a/java/Makefile.in +++ b/java/Makefile.in | |||
| @@ -60,7 +60,7 @@ all: emacs.apk | |||
| 60 | # Binaries to cross-compile. | 60 | # Binaries to cross-compile. |
| 61 | CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \ | 61 | CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \ |
| 62 | ../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \ | 62 | ../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \ |
| 63 | ../xcompile/lib-src/ebrowse | 63 | ../xcompile/lib-src/ebrowse ../xcompile/lib-src/emacsclient |
| 64 | 64 | ||
| 65 | # Libraries to cross-compile. | 65 | # Libraries to cross-compile. |
| 66 | CROSS_LIBS = ../xcompile/src/libemacs.so | 66 | CROSS_LIBS = ../xcompile/src/libemacs.so |
| @@ -84,6 +84,7 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml | |||
| 84 | # Install architecture independents to assets/etc and assets/lisp | 84 | # Install architecture independents to assets/etc and assets/lisp |
| 85 | cp -r $(top_builddir)/lisp install_temp/assets | 85 | cp -r $(top_builddir)/lisp install_temp/assets |
| 86 | cp -r $(top_builddir)/etc install_temp/assets | 86 | cp -r $(top_builddir)/etc install_temp/assets |
| 87 | cp -r $(top_builddir)/info install_temp/assets | ||
| 87 | # Remove undesirable files from those directories. | 88 | # Remove undesirable files from those directories. |
| 88 | for subdir in `find install_temp -type d -print`; do \ | 89 | for subdir in `find install_temp -type d -print`; do \ |
| 89 | chmod a+rx $${subdir} ; \ | 90 | chmod a+rx $${subdir} ; \ |
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index cacd5f13e60..67f411a38c3 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java | |||
| @@ -32,65 +32,114 @@ import android.widget.FrameLayout; | |||
| 32 | import android.widget.FrameLayout.LayoutParams; | 32 | import android.widget.FrameLayout.LayoutParams; |
| 33 | 33 | ||
| 34 | public class EmacsActivity extends Activity | 34 | public class EmacsActivity extends Activity |
| 35 | implements EmacsWindowAttachmentManager.WindowConsumer | ||
| 35 | { | 36 | { |
| 36 | public static final String TAG = "EmacsActivity"; | 37 | public static final String TAG = "EmacsActivity"; |
| 37 | 38 | ||
| 38 | /* List of all activities that do not have an associated | ||
| 39 | EmacsWindow. */ | ||
| 40 | public static List<EmacsActivity> availableActivities; | ||
| 41 | |||
| 42 | /* The currently attached EmacsWindow, or null if none. */ | 39 | /* The currently attached EmacsWindow, or null if none. */ |
| 43 | private EmacsWindow window; | 40 | private EmacsWindow window; |
| 44 | 41 | ||
| 45 | /* The frame layout associated with the activity. */ | 42 | /* The frame layout associated with the activity. */ |
| 46 | private FrameLayout layout; | 43 | private FrameLayout layout; |
| 47 | 44 | ||
| 45 | /* List of activities with focus. */ | ||
| 46 | private static List<EmacsActivity> focusedActivities; | ||
| 47 | |||
| 48 | /* The currently focused window. */ | ||
| 49 | public static EmacsWindow focusedWindow; | ||
| 50 | |||
| 48 | static | 51 | static |
| 49 | { | 52 | { |
| 50 | /* Set up the list of available activities. */ | 53 | focusedActivities = new ArrayList<EmacsActivity> (); |
| 51 | availableActivities = new ArrayList<EmacsActivity> (); | ||
| 52 | }; | 54 | }; |
| 53 | 55 | ||
| 56 | public static void | ||
| 57 | invalidateFocus1 (EmacsWindow window) | ||
| 58 | { | ||
| 59 | if (window.view.isFocused ()) | ||
| 60 | focusedWindow = window; | ||
| 61 | |||
| 62 | for (EmacsWindow child : window.children) | ||
| 63 | invalidateFocus1 (window); | ||
| 64 | } | ||
| 65 | |||
| 66 | public static void | ||
| 67 | invalidateFocus () | ||
| 68 | { | ||
| 69 | EmacsWindow oldFocus; | ||
| 70 | |||
| 71 | /* Walk through each focused activity and assign the window focus | ||
| 72 | to the bottom-most focused window within. Record the old focus | ||
| 73 | as well. */ | ||
| 74 | oldFocus = focusedWindow; | ||
| 75 | focusedWindow = null; | ||
| 76 | |||
| 77 | for (EmacsActivity activity : focusedActivities) | ||
| 78 | { | ||
| 79 | if (activity.window != null) | ||
| 80 | invalidateFocus1 (activity.window); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Send focus in- and out- events to the previous and current | ||
| 84 | focus. */ | ||
| 85 | |||
| 86 | if (oldFocus != null) | ||
| 87 | EmacsNative.sendFocusOut (oldFocus.handle, | ||
| 88 | System.currentTimeMillis ()); | ||
| 89 | |||
| 90 | if (focusedWindow != null) | ||
| 91 | EmacsNative.sendFocusIn (focusedWindow.handle, | ||
| 92 | System.currentTimeMillis ()); | ||
| 93 | } | ||
| 94 | |||
| 95 | @Override | ||
| 54 | public void | 96 | public void |
| 55 | attachChild (EmacsWindow child) | 97 | detachWindow () |
| 98 | { | ||
| 99 | if (window == null) | ||
| 100 | Log.w (TAG, "detachWindow called, but there is no window"); | ||
| 101 | else | ||
| 102 | { | ||
| 103 | /* Clear the window's pointer to this activity and remove the | ||
| 104 | window's view. */ | ||
| 105 | window.setConsumer (null); | ||
| 106 | layout.removeView (window.view); | ||
| 107 | window = null; | ||
| 108 | |||
| 109 | invalidateFocus (); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | @Override | ||
| 114 | public void | ||
| 115 | attachWindow (EmacsWindow child) | ||
| 56 | { | 116 | { |
| 57 | if (window != null) | 117 | if (window != null) |
| 58 | throw new IllegalStateException ("trying to attach window when one" | 118 | throw new IllegalStateException ("trying to attach window when one" |
| 59 | + " already exists"); | 119 | + " already exists"); |
| 60 | 120 | ||
| 61 | /* Record and attach the view. */ | 121 | /* Record and attach the view. */ |
| 122 | |||
| 62 | window = child; | 123 | window = child; |
| 63 | layout.addView (window.view); | 124 | layout.addView (window.view); |
| 125 | child.setConsumer (this); | ||
| 64 | 126 | ||
| 65 | /* Remove the objects from the lists of what is available. */ | 127 | /* Invalidate the focus. */ |
| 66 | EmacsService.availableChildren.remove (child); | 128 | invalidateFocus (); |
| 67 | availableActivities.remove (this); | ||
| 68 | |||
| 69 | /* Now set child->activity. */ | ||
| 70 | child.setActivity (this); | ||
| 71 | } | 129 | } |
| 72 | 130 | ||
| 73 | /* Make this activity available for future windows to attach | 131 | @Override |
| 74 | again. */ | ||
| 75 | |||
| 76 | public void | 132 | public void |
| 77 | makeAvailable () | 133 | destroy () |
| 78 | { | 134 | { |
| 79 | window = null; | 135 | finish (); |
| 80 | 136 | } | |
| 81 | for (EmacsWindow iterWindow | ||
| 82 | : EmacsService.availableChildren) | ||
| 83 | { | ||
| 84 | synchronized (iterWindow) | ||
| 85 | { | ||
| 86 | if (!iterWindow.isDestroyed ()) | ||
| 87 | attachChild (iterWindow); | ||
| 88 | |||
| 89 | return; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | 137 | ||
| 93 | availableActivities.add (this); | 138 | @Override |
| 139 | public EmacsWindow | ||
| 140 | getAttachedWindow () | ||
| 141 | { | ||
| 142 | return window; | ||
| 94 | } | 143 | } |
| 95 | 144 | ||
| 96 | @Override | 145 | @Override |
| @@ -109,38 +158,38 @@ public class EmacsActivity extends Activity | |||
| 109 | /* Set it as the content view. */ | 158 | /* Set it as the content view. */ |
| 110 | setContentView (layout); | 159 | setContentView (layout); |
| 111 | 160 | ||
| 112 | /* Make the activity available before starting the | ||
| 113 | service. */ | ||
| 114 | makeAvailable (); | ||
| 115 | |||
| 116 | if (EmacsService.SERVICE == null) | 161 | if (EmacsService.SERVICE == null) |
| 117 | /* Start the Emacs service now. */ | 162 | /* Start the Emacs service now. */ |
| 118 | startService (new Intent (this, EmacsService.class)); | 163 | startService (new Intent (this, EmacsService.class)); |
| 119 | 164 | ||
| 165 | /* Add this activity to the list of available activities. */ | ||
| 166 | EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this); | ||
| 167 | |||
| 120 | super.onCreate (savedInstanceState); | 168 | super.onCreate (savedInstanceState); |
| 121 | } | 169 | } |
| 122 | 170 | ||
| 123 | @Override | 171 | @Override |
| 124 | public void | 172 | public void |
| 125 | onStop () | 173 | onDestroy () |
| 126 | { | 174 | { |
| 127 | /* The activity is no longer visible. If there is a window | 175 | /* The activity will die shortly hereafter. If there is a window |
| 128 | attached, detach it. */ | 176 | attached, close it now. */ |
| 129 | 177 | Log.d (TAG, "onDestroy " + this); | |
| 130 | if (window != null) | 178 | EmacsWindowAttachmentManager.MANAGER.removeWindowConsumer (this); |
| 131 | { | 179 | focusedActivities.remove (this); |
| 132 | layout.removeView (window.view); | 180 | invalidateFocus (); |
| 181 | super.onDestroy (); | ||
| 182 | } | ||
| 133 | 183 | ||
| 134 | /* Notice that the window is already available too. But do | 184 | @Override |
| 135 | not call noticeAvailableChild; that might assign it to some | 185 | public void |
| 136 | other activity, which behaves badly. */ | 186 | onWindowFocusChanged (boolean isFocused) |
| 137 | EmacsService.availableChildren.add (window); | 187 | { |
| 138 | window = null; | 188 | if (isFocused && !focusedActivities.contains (this)) |
| 139 | } | 189 | focusedActivities.add (this); |
| 190 | else | ||
| 191 | focusedActivities.remove (this); | ||
| 140 | 192 | ||
| 141 | /* Finally, remove this activity from the list of available | 193 | invalidateFocus (); |
| 142 | activities. */ | ||
| 143 | availableActivities.remove (this); | ||
| 144 | super.onStop (); | ||
| 145 | } | 194 | } |
| 146 | }; | 195 | }; |
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java index f34d1ecde01..0dd5b2c1fb6 100644 --- a/java/org/gnu/emacs/EmacsCopyArea.java +++ b/java/org/gnu/emacs/EmacsCopyArea.java | |||
| @@ -32,19 +32,22 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 32 | private int src_x, src_y, dest_x, dest_y, width, height; | 32 | private int src_x, src_y, dest_x, dest_y, width, height; |
| 33 | private EmacsDrawable destination, source; | 33 | private EmacsDrawable destination, source; |
| 34 | private EmacsGC immutableGC; | 34 | private EmacsGC immutableGC; |
| 35 | private static Xfermode xorAlu, srcInAlu; | 35 | private static Xfermode xorAlu, srcInAlu, overAlu; |
| 36 | 36 | ||
| 37 | static | 37 | static |
| 38 | { | 38 | { |
| 39 | overAlu = new PorterDuffXfermode (Mode.SRC_OVER); | ||
| 39 | xorAlu = new PorterDuffXfermode (Mode.XOR); | 40 | xorAlu = new PorterDuffXfermode (Mode.XOR); |
| 40 | srcInAlu = new PorterDuffXfermode (Mode.SRC_IN); | 41 | srcInAlu = new PorterDuffXfermode (Mode.SRC_IN); |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | public | 44 | public |
| 44 | EmacsCopyArea (EmacsDrawable destination, EmacsDrawable source, | 45 | EmacsCopyArea (EmacsDrawable source, EmacsDrawable destination, |
| 45 | int src_x, int src_y, int width, int height, | 46 | int src_x, int src_y, int width, int height, |
| 46 | int dest_x, int dest_y, EmacsGC immutableGC) | 47 | int dest_x, int dest_y, EmacsGC immutableGC) |
| 47 | { | 48 | { |
| 49 | Bitmap bitmap; | ||
| 50 | |||
| 48 | this.destination = destination; | 51 | this.destination = destination; |
| 49 | this.source = source; | 52 | this.source = source; |
| 50 | this.src_x = src_x; | 53 | this.src_x = src_x; |
| @@ -71,6 +74,16 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 71 | return destination; | 74 | return destination; |
| 72 | } | 75 | } |
| 73 | 76 | ||
| 77 | private void | ||
| 78 | insetRectBy (Rect rect, int left, int top, int right, | ||
| 79 | int bottom) | ||
| 80 | { | ||
| 81 | rect.left += left; | ||
| 82 | rect.top += top; | ||
| 83 | rect.right -= right; | ||
| 84 | rect.bottom -= bottom; | ||
| 85 | } | ||
| 86 | |||
| 74 | @Override | 87 | @Override |
| 75 | public EmacsGC | 88 | public EmacsGC |
| 76 | getGC () | 89 | getGC () |
| @@ -86,16 +99,45 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 86 | Bitmap bitmap; | 99 | Bitmap bitmap; |
| 87 | Paint maskPaint; | 100 | Paint maskPaint; |
| 88 | Canvas maskCanvas; | 101 | Canvas maskCanvas; |
| 89 | Bitmap maskBitmap; | 102 | Bitmap srcBitmap, maskBitmap, clipBitmap; |
| 90 | Rect rect, srcRect; | 103 | Rect rect, maskRect, srcRect, dstRect, maskDestRect; |
| 104 | boolean needFill; | ||
| 91 | 105 | ||
| 92 | /* TODO implement stippling. */ | 106 | /* TODO implement stippling. */ |
| 93 | if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) | 107 | if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) |
| 94 | return; | 108 | return; |
| 95 | 109 | ||
| 96 | alu = immutableGC.function; | 110 | alu = immutableGC.function; |
| 111 | |||
| 112 | /* A copy must be created or drawBitmap could end up overwriting | ||
| 113 | itself. */ | ||
| 114 | srcBitmap = source.getBitmap (); | ||
| 115 | |||
| 116 | /* If srcBitmap is out of bounds, then adjust the source rectangle | ||
| 117 | to be within bounds. Note that tiling on windows with | ||
| 118 | backgrounds is unimplemented. */ | ||
| 119 | |||
| 120 | if (src_x < 0) | ||
| 121 | { | ||
| 122 | width += src_x; | ||
| 123 | dest_x -= src_x; | ||
| 124 | src_x = 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (src_y < 0) | ||
| 128 | { | ||
| 129 | height += src_y; | ||
| 130 | dest_y -= src_y; | ||
| 131 | src_y = 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (src_x + width > srcBitmap.getWidth ()) | ||
| 135 | width = srcBitmap.getWidth () - src_x; | ||
| 136 | |||
| 137 | if (src_y + height > srcBitmap.getHeight ()) | ||
| 138 | height = srcBitmap.getHeight () - src_y; | ||
| 139 | |||
| 97 | rect = getRect (); | 140 | rect = getRect (); |
| 98 | bitmap = source.getBitmap (); | ||
| 99 | 141 | ||
| 100 | if (alu == EmacsGC.GC_COPY) | 142 | if (alu == EmacsGC.GC_COPY) |
| 101 | paint.setXfermode (null); | 143 | paint.setXfermode (null); |
| @@ -103,29 +145,76 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 103 | paint.setXfermode (xorAlu); | 145 | paint.setXfermode (xorAlu); |
| 104 | 146 | ||
| 105 | if (immutableGC.clip_mask == null) | 147 | if (immutableGC.clip_mask == null) |
| 106 | canvas.drawBitmap (bitmap, new Rect (src_x, src_y, | 148 | { |
| 107 | src_x + width, | 149 | bitmap = Bitmap.createBitmap (srcBitmap, |
| 108 | src_y + height), | 150 | src_x, src_y, width, |
| 109 | rect, paint); | 151 | height); |
| 152 | canvas.drawBitmap (bitmap, null, rect, paint); | ||
| 153 | } | ||
| 110 | else | 154 | else |
| 111 | { | 155 | { |
| 112 | maskPaint = new Paint (); | 156 | /* Drawing with a clip mask involves calculating the |
| 113 | srcRect = new Rect (0, 0, rect.width (), | 157 | intersection of the clip mask with the dst rect, and |
| 114 | rect.height ()); | 158 | extrapolating the corresponding part of the src rect. */ |
| 115 | maskBitmap | 159 | clipBitmap = immutableGC.clip_mask.bitmap; |
| 116 | = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888, | 160 | dstRect = new Rect (dest_x, dest_y, |
| 117 | true); | 161 | dest_x + width, |
| 118 | 162 | dest_y + height); | |
| 119 | if (maskBitmap == null) | 163 | maskRect = new Rect (immutableGC.clip_x_origin, |
| 164 | immutableGC.clip_y_origin, | ||
| 165 | (immutableGC.clip_x_origin | ||
| 166 | + clipBitmap.getWidth ()), | ||
| 167 | (immutableGC.clip_y_origin | ||
| 168 | + clipBitmap.getHeight ())); | ||
| 169 | clipBitmap = immutableGC.clip_mask.bitmap; | ||
| 170 | |||
| 171 | if (!maskRect.setIntersect (dstRect, maskRect)) | ||
| 172 | /* There is no intersection between the clip mask and the | ||
| 173 | dest rect. */ | ||
| 120 | return; | 174 | return; |
| 121 | 175 | ||
| 122 | maskPaint.setXfermode (srcInAlu); | 176 | /* Now figure out which part of the source corresponds to |
| 177 | maskRect and return it relative to srcBitmap. */ | ||
| 178 | srcRect = new Rect (src_x, src_y, src_x + width, | ||
| 179 | src_y + height); | ||
| 180 | insetRectBy (srcRect, maskRect.left - dstRect.left, | ||
| 181 | maskRect.top - dstRect.top, | ||
| 182 | maskRect.right - dstRect.right, | ||
| 183 | maskRect.bottom - dstRect.bottom); | ||
| 184 | |||
| 185 | /* Finally, create a temporary bitmap that is the size of | ||
| 186 | maskRect. */ | ||
| 187 | |||
| 188 | maskBitmap | ||
| 189 | = Bitmap.createBitmap (maskRect.width (), maskRect.height (), | ||
| 190 | Bitmap.Config.ARGB_8888); | ||
| 191 | |||
| 192 | /* Draw the mask onto the maskBitmap. */ | ||
| 123 | maskCanvas = new Canvas (maskBitmap); | 193 | maskCanvas = new Canvas (maskBitmap); |
| 124 | maskCanvas.drawBitmap (bitmap, new Rect (src_x, src_y, | 194 | maskRect.offset (-immutableGC.clip_x_origin, |
| 125 | src_x + width, | 195 | -immutableGC.clip_y_origin); |
| 126 | src_y + height), | 196 | maskCanvas.drawBitmap (immutableGC.clip_mask.bitmap, |
| 127 | srcRect, maskPaint); | 197 | maskRect, new Rect (0, 0, |
| 128 | canvas.drawBitmap (maskBitmap, srcRect, rect, paint); | 198 | maskRect.width (), |
| 199 | maskRect.height ()), | ||
| 200 | paint); | ||
| 201 | maskRect.offset (immutableGC.clip_x_origin, | ||
| 202 | immutableGC.clip_y_origin); | ||
| 203 | |||
| 204 | /* Set the transfer mode to SRC_IN to preserve only the parts | ||
| 205 | of the source that overlap with the mask. */ | ||
| 206 | maskPaint = new Paint (); | ||
| 207 | maskPaint.setXfermode (srcInAlu); | ||
| 208 | |||
| 209 | /* Draw the source. */ | ||
| 210 | maskDestRect = new Rect (0, 0, srcRect.width (), | ||
| 211 | srcRect.height ()); | ||
| 212 | maskCanvas.drawBitmap (srcBitmap, srcRect, maskDestRect, | ||
| 213 | maskPaint); | ||
| 214 | |||
| 215 | /* Finally, draw the mask bitmap to the destination. */ | ||
| 216 | paint.setXfermode (overAlu); | ||
| 217 | canvas.drawBitmap (maskBitmap, null, maskRect, paint); | ||
| 129 | } | 218 | } |
| 130 | } | 219 | } |
| 131 | } | 220 | } |
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java index 462bf7c85b5..e3f28227146 100644 --- a/java/org/gnu/emacs/EmacsDrawRectangle.java +++ b/java/org/gnu/emacs/EmacsDrawRectangle.java | |||
| @@ -57,7 +57,10 @@ public class EmacsDrawRectangle implements EmacsPaintReq | |||
| 57 | public Rect | 57 | public Rect |
| 58 | getRect () | 58 | getRect () |
| 59 | { | 59 | { |
| 60 | return new Rect (x, y, x + width, y + height); | 60 | /* Canvas.drawRect actually behaves exactly like PolyRectangle wrt |
| 61 | to where the lines are placed, so extend the width and height | ||
| 62 | by 1 in the damage rectangle. */ | ||
| 63 | return new Rect (x, y, x + width + 1, y + height + 1); | ||
| 61 | } | 64 | } |
| 62 | 65 | ||
| 63 | @Override | 66 | @Override |
| @@ -89,9 +92,10 @@ public class EmacsDrawRectangle implements EmacsPaintReq | |||
| 89 | return; | 92 | return; |
| 90 | 93 | ||
| 91 | alu = immutableGC.function; | 94 | alu = immutableGC.function; |
| 92 | rect = getRect (); | 95 | rect = new Rect (x, y, x + width, y + height); |
| 93 | 96 | ||
| 94 | paint.setStyle (Paint.Style.STROKE); | 97 | paint.setStyle (Paint.Style.STROKE); |
| 98 | paint.setStrokeWidth (1); | ||
| 95 | 99 | ||
| 96 | if (alu == EmacsGC.GC_COPY) | 100 | if (alu == EmacsGC.GC_COPY) |
| 97 | paint.setXfermode (null); | 101 | paint.setXfermode (null); |
diff --git a/java/org/gnu/emacs/EmacsFontDriver.java b/java/org/gnu/emacs/EmacsFontDriver.java index f419e71059d..9f40aa04c44 100644 --- a/java/org/gnu/emacs/EmacsFontDriver.java +++ b/java/org/gnu/emacs/EmacsFontDriver.java | |||
| @@ -21,6 +21,8 @@ package org.gnu.emacs; | |||
| 21 | 21 | ||
| 22 | import java.util.List; | 22 | import java.util.List; |
| 23 | 23 | ||
| 24 | import android.os.Build; | ||
| 25 | |||
| 24 | public abstract class EmacsFontDriver | 26 | public abstract class EmacsFontDriver |
| 25 | { | 27 | { |
| 26 | /* Font weights. */ | 28 | /* Font weights. */ |
| @@ -75,6 +77,7 @@ public abstract class EmacsFontDriver | |||
| 75 | public Integer size; | 77 | public Integer size; |
| 76 | public Integer spacing; | 78 | public Integer spacing; |
| 77 | public Integer avgwidth; | 79 | public Integer avgwidth; |
| 80 | public Integer dpi; | ||
| 78 | 81 | ||
| 79 | @Override | 82 | @Override |
| 80 | public String | 83 | public String |
| @@ -88,7 +91,8 @@ public abstract class EmacsFontDriver | |||
| 88 | + " weight: " + weight | 91 | + " weight: " + weight |
| 89 | + " slant: " + slant | 92 | + " slant: " + slant |
| 90 | + " spacing: " + spacing | 93 | + " spacing: " + spacing |
| 91 | + " avgwidth: " + avgwidth); | 94 | + " avgwidth: " + avgwidth |
| 95 | + " dpi: " + dpi); | ||
| 92 | } | 96 | } |
| 93 | }; | 97 | }; |
| 94 | 98 | ||
| @@ -99,6 +103,17 @@ public abstract class EmacsFontDriver | |||
| 99 | public short width; | 103 | public short width; |
| 100 | public short ascent; | 104 | public short ascent; |
| 101 | public short descent; | 105 | public short descent; |
| 106 | |||
| 107 | @Override | ||
| 108 | public String | ||
| 109 | toString () | ||
| 110 | { | ||
| 111 | return ("lbearing " + lbearing | ||
| 112 | + " rbearing " + rbearing | ||
| 113 | + " width " + width | ||
| 114 | + " ascent " + ascent | ||
| 115 | + " descent " + descent); | ||
| 116 | } | ||
| 102 | } | 117 | } |
| 103 | 118 | ||
| 104 | public class FontEntity extends FontSpec | 119 | public class FontEntity extends FontSpec |
| @@ -139,12 +154,19 @@ public abstract class EmacsFontDriver | |||
| 139 | public abstract FontObject openFont (FontEntity fontEntity, int pixelSize); | 154 | public abstract FontObject openFont (FontEntity fontEntity, int pixelSize); |
| 140 | public abstract int hasChar (FontSpec font, char charCode); | 155 | public abstract int hasChar (FontSpec font, char charCode); |
| 141 | public abstract void textExtents (FontObject font, int code[], | 156 | public abstract void textExtents (FontObject font, int code[], |
| 142 | FontMetrics fontMetrics[]); | 157 | FontMetrics fontMetrics); |
| 143 | public abstract int encodeChar (FontObject fontObject, char charCode); | 158 | public abstract int encodeChar (FontObject fontObject, char charCode); |
| 159 | public abstract int draw (FontObject fontObject, EmacsGC gc, | ||
| 160 | EmacsDrawable drawable, int[] chars, | ||
| 161 | int x, int y, int backgroundWidth, | ||
| 162 | boolean withBackground); | ||
| 144 | 163 | ||
| 145 | public static EmacsFontDriver | 164 | public static EmacsFontDriver |
| 146 | createFontDriver () | 165 | createFontDriver () |
| 147 | { | 166 | { |
| 167 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) | ||
| 168 | return new EmacsSdk23FontDriver (); | ||
| 169 | |||
| 148 | return new EmacsSdk7FontDriver (); | 170 | return new EmacsSdk7FontDriver (); |
| 149 | } | 171 | } |
| 150 | }; | 172 | }; |
diff --git a/java/org/gnu/emacs/EmacsMultitaskActivity.java b/java/org/gnu/emacs/EmacsMultitaskActivity.java new file mode 100644 index 00000000000..dbdc99a3559 --- /dev/null +++ b/java/org/gnu/emacs/EmacsMultitaskActivity.java | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* Communication module for Android terminals. -*- c-file-style: "GNU" -*- | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | public class EmacsMultitaskActivity extends EmacsActivity | ||
| 23 | { | ||
| 24 | |||
| 25 | } | ||
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 6550e6fa2a1..c80339031a8 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java | |||
| @@ -38,10 +38,15 @@ public class EmacsNative | |||
| 38 | libDir must be the package's data storage location for native | 38 | libDir must be the package's data storage location for native |
| 39 | libraries. It is used as PATH. | 39 | libraries. It is used as PATH. |
| 40 | 40 | ||
| 41 | pixelDensityX and pixelDensityY are the DPI values that will be | ||
| 42 | used by Emacs. | ||
| 43 | |||
| 41 | emacsService must be the emacsService singleton. */ | 44 | emacsService must be the emacsService singleton. */ |
| 42 | public static native void setEmacsParams (AssetManager assetManager, | 45 | public static native void setEmacsParams (AssetManager assetManager, |
| 43 | String filesDir, | 46 | String filesDir, |
| 44 | String libDir, | 47 | String libDir, |
| 48 | float pixelDensityX, | ||
| 49 | float pixelDensityY, | ||
| 45 | EmacsService emacsService); | 50 | EmacsService emacsService); |
| 46 | 51 | ||
| 47 | /* Initialize Emacs with the argument array ARGV. Each argument | 52 | /* Initialize Emacs with the argument array ARGV. Each argument |
| @@ -59,11 +64,20 @@ public class EmacsNative | |||
| 59 | 64 | ||
| 60 | /* Send an ANDROID_KEY_PRESS event. */ | 65 | /* Send an ANDROID_KEY_PRESS event. */ |
| 61 | public static native void sendKeyPress (short window, long time, int state, | 66 | public static native void sendKeyPress (short window, long time, int state, |
| 62 | int keyCode); | 67 | int keyCode, int unicodeChar); |
| 63 | 68 | ||
| 64 | /* Send an ANDROID_KEY_RELEASE event. */ | 69 | /* Send an ANDROID_KEY_RELEASE event. */ |
| 65 | public static native void sendKeyRelease (short window, long time, int state, | 70 | public static native void sendKeyRelease (short window, long time, int state, |
| 66 | int keyRelease); | 71 | int keyCode, int unicodeChar); |
| 72 | |||
| 73 | /* Send an ANDROID_FOCUS_IN event. */ | ||
| 74 | public static native void sendFocusIn (short window, long time); | ||
| 75 | |||
| 76 | /* Send an ANDROID_FOCUS_OUT event. */ | ||
| 77 | public static native void sendFocusOut (short window, long time); | ||
| 78 | |||
| 79 | /* Send an ANDROID_WINDOW_ACTION event. */ | ||
| 80 | public static native void sendWindowAction (short window, int action); | ||
| 67 | 81 | ||
| 68 | static | 82 | static |
| 69 | { | 83 | { |
diff --git a/java/org/gnu/emacs/EmacsPaintQueue.java b/java/org/gnu/emacs/EmacsPaintQueue.java index 5af5868d3b9..f4840dbf5ae 100644 --- a/java/org/gnu/emacs/EmacsPaintQueue.java +++ b/java/org/gnu/emacs/EmacsPaintQueue.java | |||
| @@ -47,7 +47,7 @@ public class EmacsPaintQueue | |||
| 47 | { | 47 | { |
| 48 | EmacsDrawable drawable, last; | 48 | EmacsDrawable drawable, last; |
| 49 | Canvas canvas; | 49 | Canvas canvas; |
| 50 | EmacsGC gc, lastGC; | 50 | EmacsGC gc; |
| 51 | int i; | 51 | int i; |
| 52 | Paint paint; | 52 | Paint paint; |
| 53 | Rect rect, offsetRect, copyRect; | 53 | Rect rect, offsetRect, copyRect; |
| @@ -60,45 +60,34 @@ public class EmacsPaintQueue | |||
| 60 | for (EmacsPaintReq req : paintOperations) | 60 | for (EmacsPaintReq req : paintOperations) |
| 61 | { | 61 | { |
| 62 | drawable = req.getDrawable (); | 62 | drawable = req.getDrawable (); |
| 63 | |||
| 64 | synchronized (req) | ||
| 65 | { | ||
| 66 | /* Ignore graphics requests for drawables that have been | ||
| 67 | destroyed. */ | ||
| 68 | if (drawable.isDestroyed ()) | ||
| 69 | continue; | ||
| 70 | } | ||
| 71 | |||
| 72 | canvas = drawable.lockCanvas (); | 63 | canvas = drawable.lockCanvas (); |
| 73 | 64 | ||
| 74 | if (canvas == null) | 65 | if (canvas == null) |
| 75 | /* No canvas is currently available. */ | 66 | /* No canvas is currently available. */ |
| 76 | continue; | 67 | continue; |
| 77 | 68 | ||
| 78 | lastGC = gc; | ||
| 79 | gc = req.getGC (); | 69 | gc = req.getGC (); |
| 80 | rect = req.getRect (); | 70 | rect = req.getRect (); |
| 81 | 71 | ||
| 72 | drawable.damageRect (rect); | ||
| 73 | |||
| 82 | if (gc.clip_rects == null) | 74 | if (gc.clip_rects == null) |
| 83 | { | 75 | { |
| 84 | /* No clipping is applied. Just draw and continue. */ | 76 | /* No clipping is applied. Just draw and continue. */ |
| 85 | canvas.save (); | ||
| 86 | req.paintTo (canvas, paint, gc); | 77 | req.paintTo (canvas, paint, gc); |
| 87 | canvas.restore (); | ||
| 88 | drawable.damageRect (rect); | ||
| 89 | continue; | 78 | continue; |
| 90 | } | 79 | } |
| 91 | 80 | ||
| 92 | if (gc.clip_rects != null && gc.clip_rects.length > 0) | 81 | if (gc.clip_rects != null && gc.clip_rects.length > 0) |
| 93 | { | 82 | { |
| 94 | canvas.save (); | ||
| 95 | |||
| 96 | if (gc.clip_rects.length == 1) | 83 | if (gc.clip_rects.length == 1) |
| 97 | { | 84 | { |
| 98 | /* There is only a single clip rect, which is simple | 85 | /* There is only a single clip rect, which is simple |
| 99 | enough. */ | 86 | enough. */ |
| 87 | canvas.save (); | ||
| 100 | canvas.clipRect (gc.clip_rects[0]); | 88 | canvas.clipRect (gc.clip_rects[0]); |
| 101 | req.paintTo (canvas, paint, gc); | 89 | req.paintTo (canvas, paint, gc); |
| 90 | canvas.restore (); | ||
| 102 | } | 91 | } |
| 103 | else | 92 | else |
| 104 | { | 93 | { |
| @@ -122,9 +111,6 @@ public class EmacsPaintQueue | |||
| 122 | } | 111 | } |
| 123 | } | 112 | } |
| 124 | } | 113 | } |
| 125 | |||
| 126 | drawable.damageRect (rect); | ||
| 127 | canvas.restore (); | ||
| 128 | } | 114 | } |
| 129 | } | 115 | } |
| 130 | } | 116 | } |
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java index ccd5f1e0043..897902c5b57 100644 --- a/java/org/gnu/emacs/EmacsPixmap.java +++ b/java/org/gnu/emacs/EmacsPixmap.java | |||
| @@ -69,6 +69,35 @@ public class EmacsPixmap extends EmacsHandleObject | |||
| 69 | this.depth = depth; | 69 | this.depth = depth; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | public | ||
| 73 | EmacsPixmap (short handle, int width, int height, int depth) | ||
| 74 | { | ||
| 75 | super (handle); | ||
| 76 | |||
| 77 | if (depth != 1 && depth != 24) | ||
| 78 | throw new IllegalArgumentException ("Invalid depth specified" | ||
| 79 | + " for pixmap: " + depth); | ||
| 80 | |||
| 81 | switch (depth) | ||
| 82 | { | ||
| 83 | case 1: | ||
| 84 | bitmap = Bitmap.createBitmap (width, height, | ||
| 85 | Bitmap.Config.ALPHA_8, | ||
| 86 | false); | ||
| 87 | break; | ||
| 88 | |||
| 89 | case 24: | ||
| 90 | bitmap = Bitmap.createBitmap (width, height, | ||
| 91 | Bitmap.Config.ARGB_8888, | ||
| 92 | false); | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | |||
| 96 | this.width = width; | ||
| 97 | this.height = height; | ||
| 98 | this.depth = depth; | ||
| 99 | } | ||
| 100 | |||
| 72 | @Override | 101 | @Override |
| 73 | public Canvas | 102 | public Canvas |
| 74 | lockCanvas () | 103 | lockCanvas () |
diff --git a/java/org/gnu/emacs/EmacsSdk23FontDriver.java b/java/org/gnu/emacs/EmacsSdk23FontDriver.java new file mode 100644 index 00000000000..34e2b1803a2 --- /dev/null +++ b/java/org/gnu/emacs/EmacsSdk23FontDriver.java | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* Font backend for Android terminals. -*- c-file-style: "GNU" -*- | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import android.graphics.Paint; | ||
| 23 | |||
| 24 | public class EmacsSdk23FontDriver extends EmacsSdk7FontDriver | ||
| 25 | { | ||
| 26 | @Override | ||
| 27 | public int | ||
| 28 | hasChar (FontSpec font, char charCode) | ||
| 29 | { | ||
| 30 | Sdk7FontObject fontObject; | ||
| 31 | Paint paint; | ||
| 32 | |||
| 33 | if (font instanceof Sdk7FontObject) | ||
| 34 | { | ||
| 35 | fontObject = (Sdk7FontObject) font; | ||
| 36 | paint = fontObject.typeface.typefacePaint; | ||
| 37 | } | ||
| 38 | else | ||
| 39 | paint = ((Sdk7FontEntity) font).typeface.typefacePaint; | ||
| 40 | |||
| 41 | return paint.hasGlyph (String.valueOf (charCode)) ? 1 : 0; | ||
| 42 | } | ||
| 43 | }; | ||
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java index 5a8cdbfc75b..437f38e62db 100644 --- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java +++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java | |||
| @@ -28,16 +28,19 @@ import java.util.List; | |||
| 28 | import android.graphics.Paint; | 28 | import android.graphics.Paint; |
| 29 | import android.graphics.Rect; | 29 | import android.graphics.Rect; |
| 30 | import android.graphics.Typeface; | 30 | import android.graphics.Typeface; |
| 31 | import android.graphics.Canvas; | ||
| 31 | 32 | ||
| 32 | import android.util.Log; | 33 | import android.util.Log; |
| 33 | 34 | ||
| 35 | import android.os.Build; | ||
| 36 | |||
| 34 | public class EmacsSdk7FontDriver extends EmacsFontDriver | 37 | public class EmacsSdk7FontDriver extends EmacsFontDriver |
| 35 | { | 38 | { |
| 36 | private static final String TOFU_STRING = "\uDB3F\uDFFD"; | 39 | private static final String TOFU_STRING = "\uDB3F\uDFFD"; |
| 37 | private static final String EM_STRING = "m"; | 40 | private static final String EM_STRING = "m"; |
| 38 | private static final String TAG = "EmacsSdk7FontDriver"; | 41 | private static final String TAG = "EmacsSdk7FontDriver"; |
| 39 | 42 | ||
| 40 | private class Sdk7Typeface | 43 | protected class Sdk7Typeface |
| 41 | { | 44 | { |
| 42 | /* The typeface and paint. */ | 45 | /* The typeface and paint. */ |
| 43 | public Typeface typeface; | 46 | public Typeface typeface; |
| @@ -57,7 +60,10 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 57 | width = UNSPECIFIED; | 60 | width = UNSPECIFIED; |
| 58 | spacing = PROPORTIONAL; | 61 | spacing = PROPORTIONAL; |
| 59 | 62 | ||
| 63 | this.typeface = typeface; | ||
| 64 | |||
| 60 | typefacePaint = new Paint (); | 65 | typefacePaint = new Paint (); |
| 66 | typefacePaint.setAntiAlias (true); | ||
| 61 | typefacePaint.setTypeface (typeface); | 67 | typefacePaint.setTypeface (typeface); |
| 62 | 68 | ||
| 63 | /* For the calls to measureText below. */ | 69 | /* For the calls to measureText below. */ |
| @@ -160,7 +166,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 160 | } | 166 | } |
| 161 | }; | 167 | }; |
| 162 | 168 | ||
| 163 | private class Sdk7FontEntity extends FontEntity | 169 | protected class Sdk7FontEntity extends FontEntity |
| 164 | { | 170 | { |
| 165 | /* The typeface. */ | 171 | /* The typeface. */ |
| 166 | public Sdk7Typeface typeface; | 172 | public Sdk7Typeface typeface; |
| @@ -177,19 +183,17 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 177 | slant = typeface.slant; | 183 | slant = typeface.slant; |
| 178 | spacing = typeface.spacing; | 184 | spacing = typeface.spacing; |
| 179 | width = typeface.width; | 185 | width = typeface.width; |
| 186 | dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f); | ||
| 180 | 187 | ||
| 181 | this.typeface = typeface; | 188 | this.typeface = typeface; |
| 182 | } | 189 | } |
| 183 | }; | 190 | }; |
| 184 | 191 | ||
| 185 | private class Sdk7FontObject extends FontObject | 192 | protected class Sdk7FontObject extends FontObject |
| 186 | { | 193 | { |
| 187 | /* The typeface. */ | 194 | /* The typeface. */ |
| 188 | public Sdk7Typeface typeface; | 195 | public Sdk7Typeface typeface; |
| 189 | 196 | ||
| 190 | /* The text size. */ | ||
| 191 | public int pixelSize; | ||
| 192 | |||
| 193 | public | 197 | public |
| 194 | Sdk7FontObject (Sdk7Typeface typeface, int pixelSize) | 198 | Sdk7FontObject (Sdk7Typeface typeface, int pixelSize) |
| 195 | { | 199 | { |
| @@ -205,6 +209,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 205 | slant = typeface.slant; | 209 | slant = typeface.slant; |
| 206 | spacing = typeface.spacing; | 210 | spacing = typeface.spacing; |
| 207 | width = typeface.width; | 211 | width = typeface.width; |
| 212 | dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f); | ||
| 208 | 213 | ||
| 209 | /* Compute the ascent and descent. */ | 214 | /* Compute the ascent and descent. */ |
| 210 | typeface.typefacePaint.setTextSize (pixelSize); | 215 | typeface.typefacePaint.setTextSize (pixelSize); |
| @@ -238,6 +243,93 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 238 | } | 243 | } |
| 239 | }; | 244 | }; |
| 240 | 245 | ||
| 246 | private class Sdk7DrawString implements EmacsPaintReq | ||
| 247 | { | ||
| 248 | private boolean drawBackground; | ||
| 249 | private Sdk7FontObject fontObject; | ||
| 250 | private char[] chars; | ||
| 251 | private EmacsGC immutableGC; | ||
| 252 | private EmacsDrawable drawable; | ||
| 253 | private Rect rect; | ||
| 254 | private int originX, originY; | ||
| 255 | |||
| 256 | public | ||
| 257 | Sdk7DrawString (Sdk7FontObject fontObject, char[] chars, | ||
| 258 | EmacsGC immutableGC, EmacsDrawable drawable, | ||
| 259 | boolean drawBackground, Rect rect, | ||
| 260 | int originX, int originY) | ||
| 261 | { | ||
| 262 | this.fontObject = fontObject; | ||
| 263 | this.chars = chars; | ||
| 264 | this.immutableGC = immutableGC; | ||
| 265 | this.drawable = drawable; | ||
| 266 | this.drawBackground = drawBackground; | ||
| 267 | this.rect = rect; | ||
| 268 | this.originX = originX; | ||
| 269 | this.originY = originY; | ||
| 270 | } | ||
| 271 | |||
| 272 | @Override | ||
| 273 | public EmacsDrawable | ||
| 274 | getDrawable () | ||
| 275 | { | ||
| 276 | return drawable; | ||
| 277 | } | ||
| 278 | |||
| 279 | @Override | ||
| 280 | public EmacsGC | ||
| 281 | getGC () | ||
| 282 | { | ||
| 283 | return immutableGC; | ||
| 284 | } | ||
| 285 | |||
| 286 | @Override | ||
| 287 | public void | ||
| 288 | paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC) | ||
| 289 | { | ||
| 290 | int scratch; | ||
| 291 | |||
| 292 | paint.setStyle (Paint.Style.FILL); | ||
| 293 | |||
| 294 | if (drawBackground) | ||
| 295 | { | ||
| 296 | paint.setColor (immutableGC.background | 0xff000000); | ||
| 297 | canvas.drawRect (rect, paint); | ||
| 298 | } | ||
| 299 | |||
| 300 | paint.setTextSize (fontObject.pixelSize); | ||
| 301 | paint.setColor (immutableGC.foreground | 0xff000000); | ||
| 302 | paint.setTypeface (fontObject.typeface.typeface); | ||
| 303 | paint.setAntiAlias (true); | ||
| 304 | |||
| 305 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) | ||
| 306 | /* Disable hinting as that leads to displayed text not | ||
| 307 | matching the computed metrics. */ | ||
| 308 | paint.setHinting (Paint.HINTING_OFF); | ||
| 309 | |||
| 310 | canvas.drawText (chars, 0, chars.length, originX, originY, paint); | ||
| 311 | paint.setAntiAlias (false); | ||
| 312 | } | ||
| 313 | |||
| 314 | @Override | ||
| 315 | public Rect | ||
| 316 | getRect () | ||
| 317 | { | ||
| 318 | Rect rect; | ||
| 319 | |||
| 320 | rect = new Rect (); | ||
| 321 | |||
| 322 | fontObject.typeface.typefacePaint.setTextSize (fontObject.pixelSize); | ||
| 323 | fontObject.typeface.typefacePaint.getTextBounds (chars, 0, chars.length, | ||
| 324 | rect); | ||
| 325 | |||
| 326 | /* Add the background rect to the damage as well. */ | ||
| 327 | rect.union (this.rect); | ||
| 328 | |||
| 329 | return rect; | ||
| 330 | } | ||
| 331 | }; | ||
| 332 | |||
| 241 | private String[] fontFamilyList; | 333 | private String[] fontFamilyList; |
| 242 | private Sdk7Typeface[] typefaceList; | 334 | private Sdk7Typeface[] typefaceList; |
| 243 | private Sdk7Typeface fallbackTypeface; | 335 | private Sdk7Typeface fallbackTypeface; |
| @@ -252,7 +344,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 252 | systemFontsDirectory = new File ("/system/fonts"); | 344 | systemFontsDirectory = new File ("/system/fonts"); |
| 253 | 345 | ||
| 254 | fontFamilyList = systemFontsDirectory.list (); | 346 | fontFamilyList = systemFontsDirectory.list (); |
| 255 | typefaceList = new Sdk7Typeface[fontFamilyList.length]; | 347 | typefaceList = new Sdk7Typeface[fontFamilyList.length + 3]; |
| 256 | 348 | ||
| 257 | /* It would be nice to avoid opening each and every font upon | 349 | /* It would be nice to avoid opening each and every font upon |
| 258 | startup. But that doesn't seem to be possible on | 350 | startup. But that doesn't seem to be possible on |
| @@ -267,8 +359,18 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 267 | typeface); | 359 | typeface); |
| 268 | } | 360 | } |
| 269 | 361 | ||
| 362 | /* Initialize the default monospace and serif typefaces. */ | ||
| 270 | fallbackTypeface = new Sdk7Typeface ("monospace", | 363 | fallbackTypeface = new Sdk7Typeface ("monospace", |
| 271 | Typeface.MONOSPACE); | 364 | Typeface.MONOSPACE); |
| 365 | typefaceList[fontFamilyList.length] = fallbackTypeface; | ||
| 366 | |||
| 367 | fallbackTypeface = new Sdk7Typeface ("Monospace", | ||
| 368 | Typeface.MONOSPACE); | ||
| 369 | typefaceList[fontFamilyList.length + 1] = fallbackTypeface; | ||
| 370 | |||
| 371 | fallbackTypeface = new Sdk7Typeface ("Sans Serif", | ||
| 372 | Typeface.DEFAULT); | ||
| 373 | typefaceList[fontFamilyList.length + 2] = fallbackTypeface; | ||
| 272 | } | 374 | } |
| 273 | 375 | ||
| 274 | private boolean | 376 | private boolean |
| @@ -278,11 +380,6 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 278 | && !fontSpec.family.equals (typeface.familyName)) | 380 | && !fontSpec.family.equals (typeface.familyName)) |
| 279 | return false; | 381 | return false; |
| 280 | 382 | ||
| 281 | |||
| 282 | if (fontSpec.adstyle != null | ||
| 283 | && !fontSpec.adstyle.isEmpty ()) | ||
| 284 | /* return false; */; | ||
| 285 | |||
| 286 | if (fontSpec.slant != null | 383 | if (fontSpec.slant != null |
| 287 | && !fontSpec.weight.equals (typeface.weight)) | 384 | && !fontSpec.weight.equals (typeface.weight)) |
| 288 | return false; | 385 | return false; |
| @@ -393,7 +490,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 393 | paint.getTextBounds (TOFU_STRING, 0, TOFU_STRING.length (), | 490 | paint.getTextBounds (TOFU_STRING, 0, TOFU_STRING.length (), |
| 394 | rect1); | 491 | rect1); |
| 395 | paint.getTextBounds ("" + charCode, 0, 1, rect2); | 492 | paint.getTextBounds ("" + charCode, 0, 1, rect2); |
| 396 | return rect1.equals (rect2) ? 1 : 0; | 493 | return rect1.equals (rect2) ? 0 : 1; |
| 397 | } | 494 | } |
| 398 | 495 | ||
| 399 | private void | 496 | private void |
| @@ -434,21 +531,47 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 434 | 531 | ||
| 435 | @Override | 532 | @Override |
| 436 | public void | 533 | public void |
| 437 | textExtents (FontObject font, int code[], FontMetrics fontMetrics[]) | 534 | textExtents (FontObject font, int code[], FontMetrics fontMetrics) |
| 438 | { | 535 | { |
| 439 | int i; | 536 | int i; |
| 440 | Paint paintCache; | 537 | Paint paintCache; |
| 441 | Rect boundsCache; | 538 | Rect boundsCache; |
| 442 | Sdk7FontObject fontObject; | 539 | Sdk7FontObject fontObject; |
| 540 | char[] text; | ||
| 541 | float width; | ||
| 443 | 542 | ||
| 444 | fontObject = (Sdk7FontObject) font; | 543 | fontObject = (Sdk7FontObject) font; |
| 445 | paintCache = fontObject.typeface.typefacePaint; | 544 | paintCache = fontObject.typeface.typefacePaint; |
| 446 | paintCache.setTextSize (fontObject.pixelSize); | 545 | paintCache.setTextSize (fontObject.pixelSize); |
| 447 | boundsCache = new Rect (); | 546 | boundsCache = new Rect (); |
| 448 | 547 | ||
| 449 | for (i = 0; i < code.length; ++i) | 548 | if (code.length == 0) |
| 450 | textExtents1 ((Sdk7FontObject) font, code[i], fontMetrics[i], | 549 | { |
| 550 | fontMetrics.lbearing = 0; | ||
| 551 | fontMetrics.rbearing = 0; | ||
| 552 | fontMetrics.ascent = 0; | ||
| 553 | fontMetrics.descent = 0; | ||
| 554 | fontMetrics.width = 0; | ||
| 555 | } | ||
| 556 | else if (code.length == 1) | ||
| 557 | textExtents1 ((Sdk7FontObject) font, code[0], fontMetrics, | ||
| 451 | paintCache, boundsCache); | 558 | paintCache, boundsCache); |
| 559 | else | ||
| 560 | { | ||
| 561 | text = new char[code.length]; | ||
| 562 | |||
| 563 | for (i = 0; i < code.length; ++i) | ||
| 564 | text[i] = (char) code[i]; | ||
| 565 | |||
| 566 | paintCache.getTextBounds (text, 0, 1, boundsCache); | ||
| 567 | width = paintCache.measureText (text, 0, code.length); | ||
| 568 | |||
| 569 | fontMetrics.lbearing = (short) boundsCache.left; | ||
| 570 | fontMetrics.rbearing = (short) boundsCache.right; | ||
| 571 | fontMetrics.ascent = (short) -boundsCache.top; | ||
| 572 | fontMetrics.descent = (short) boundsCache.bottom; | ||
| 573 | fontMetrics.width = (short) Math.round (width); | ||
| 574 | } | ||
| 452 | } | 575 | } |
| 453 | 576 | ||
| 454 | @Override | 577 | @Override |
| @@ -457,4 +580,37 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver | |||
| 457 | { | 580 | { |
| 458 | return charCode; | 581 | return charCode; |
| 459 | } | 582 | } |
| 583 | |||
| 584 | @Override | ||
| 585 | public int | ||
| 586 | draw (FontObject fontObject, EmacsGC gc, EmacsDrawable drawable, | ||
| 587 | int[] chars, int x, int y, int backgroundWidth, | ||
| 588 | boolean withBackground) | ||
| 589 | { | ||
| 590 | Rect backgroundRect; | ||
| 591 | Sdk7FontObject sdk7FontObject; | ||
| 592 | Sdk7DrawString op; | ||
| 593 | char[] charsArray; | ||
| 594 | int i; | ||
| 595 | |||
| 596 | sdk7FontObject = (Sdk7FontObject) fontObject; | ||
| 597 | charsArray = new char[chars.length]; | ||
| 598 | |||
| 599 | for (i = 0; i < chars.length; ++i) | ||
| 600 | charsArray[i] = (char) chars[i]; | ||
| 601 | |||
| 602 | backgroundRect = new Rect (); | ||
| 603 | backgroundRect.top = y - sdk7FontObject.ascent; | ||
| 604 | backgroundRect.left = x; | ||
| 605 | backgroundRect.right = x + backgroundWidth; | ||
| 606 | backgroundRect.bottom = y + sdk7FontObject.descent; | ||
| 607 | |||
| 608 | op = new Sdk7DrawString (sdk7FontObject, charsArray, | ||
| 609 | gc.immutableGC (), drawable, | ||
| 610 | withBackground, | ||
| 611 | backgroundRect, x, y); | ||
| 612 | |||
| 613 | EmacsService.SERVICE.appendPaintOperation (op); | ||
| 614 | return 1; | ||
| 615 | } | ||
| 460 | }; | 616 | }; |
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 311226e6f7e..41a45b0bd85 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java | |||
| @@ -28,6 +28,8 @@ import android.graphics.Canvas; | |||
| 28 | import android.graphics.Bitmap; | 28 | import android.graphics.Bitmap; |
| 29 | import android.graphics.Point; | 29 | import android.graphics.Point; |
| 30 | 30 | ||
| 31 | import android.view.View; | ||
| 32 | |||
| 31 | import android.annotation.TargetApi; | 33 | import android.annotation.TargetApi; |
| 32 | import android.app.Service; | 34 | import android.app.Service; |
| 33 | import android.content.Context; | 35 | import android.content.Context; |
| @@ -37,7 +39,9 @@ import android.os.Build; | |||
| 37 | import android.os.Looper; | 39 | import android.os.Looper; |
| 38 | import android.os.IBinder; | 40 | import android.os.IBinder; |
| 39 | import android.os.Handler; | 41 | import android.os.Handler; |
| 42 | |||
| 40 | import android.util.Log; | 43 | import android.util.Log; |
| 44 | import android.util.DisplayMetrics; | ||
| 41 | 45 | ||
| 42 | class Holder<T> | 46 | class Holder<T> |
| 43 | { | 47 | { |
| @@ -57,14 +61,8 @@ public class EmacsService extends Service | |||
| 57 | private Handler handler; | 61 | private Handler handler; |
| 58 | private EmacsPaintQueue paintQueue; | 62 | private EmacsPaintQueue paintQueue; |
| 59 | 63 | ||
| 60 | /* List of all EmacsWindows that are available to attach to an | 64 | /* Display metrics used by font backends. */ |
| 61 | activity. */ | 65 | public DisplayMetrics metrics; |
| 62 | public static List<EmacsWindow> availableChildren; | ||
| 63 | |||
| 64 | static | ||
| 65 | { | ||
| 66 | availableChildren = new ArrayList<EmacsWindow> (); | ||
| 67 | }; | ||
| 68 | 66 | ||
| 69 | @Override | 67 | @Override |
| 70 | public int | 68 | public int |
| @@ -88,7 +86,7 @@ public class EmacsService extends Service | |||
| 88 | Context context; | 86 | Context context; |
| 89 | 87 | ||
| 90 | context = getApplicationContext (); | 88 | context = getApplicationContext (); |
| 91 | apiLevel = android.os.Build.VERSION.SDK_INT; | 89 | apiLevel = Build.VERSION.SDK_INT; |
| 92 | 90 | ||
| 93 | if (apiLevel >= Build.VERSION_CODES.GINGERBREAD) | 91 | if (apiLevel >= Build.VERSION_CODES.GINGERBREAD) |
| 94 | return context.getApplicationInfo().nativeLibraryDir; | 92 | return context.getApplicationInfo().nativeLibraryDir; |
| @@ -105,11 +103,16 @@ public class EmacsService extends Service | |||
| 105 | AssetManager manager; | 103 | AssetManager manager; |
| 106 | Context app_context; | 104 | Context app_context; |
| 107 | String filesDir, libDir; | 105 | String filesDir, libDir; |
| 106 | double pixelDensityX; | ||
| 107 | double pixelDensityY; | ||
| 108 | 108 | ||
| 109 | SERVICE = this; | 109 | SERVICE = this; |
| 110 | handler = new Handler (Looper.getMainLooper ()); | 110 | handler = new Handler (Looper.getMainLooper ()); |
| 111 | manager = getAssets (); | 111 | manager = getAssets (); |
| 112 | app_context = getApplicationContext (); | 112 | app_context = getApplicationContext (); |
| 113 | metrics = getResources ().getDisplayMetrics (); | ||
| 114 | pixelDensityX = metrics.xdpi; | ||
| 115 | pixelDensityY = metrics.ydpi; | ||
| 113 | 116 | ||
| 114 | try | 117 | try |
| 115 | { | 118 | { |
| @@ -122,6 +125,8 @@ public class EmacsService extends Service | |||
| 122 | + " and libDir = " + libDir); | 125 | + " and libDir = " + libDir); |
| 123 | 126 | ||
| 124 | EmacsNative.setEmacsParams (manager, filesDir, libDir, | 127 | EmacsNative.setEmacsParams (manager, filesDir, libDir, |
| 128 | (float) pixelDensityX, | ||
| 129 | (float) pixelDensityY, | ||
| 125 | this); | 130 | this); |
| 126 | 131 | ||
| 127 | /* Start the thread that runs Emacs. */ | 132 | /* Start the thread that runs Emacs. */ |
| @@ -147,7 +152,8 @@ public class EmacsService extends Service | |||
| 147 | } | 152 | } |
| 148 | 153 | ||
| 149 | EmacsView | 154 | EmacsView |
| 150 | getEmacsView (final EmacsWindow window) | 155 | getEmacsView (final EmacsWindow window, final int visibility, |
| 156 | final boolean isFocusedByDefault) | ||
| 151 | { | 157 | { |
| 152 | Runnable runnable; | 158 | Runnable runnable; |
| 153 | final Holder<EmacsView> view; | 159 | final Holder<EmacsView> view; |
| @@ -161,6 +167,8 @@ public class EmacsService extends Service | |||
| 161 | synchronized (this) | 167 | synchronized (this) |
| 162 | { | 168 | { |
| 163 | view.thing = new EmacsView (window); | 169 | view.thing = new EmacsView (window); |
| 170 | view.thing.setVisibility (visibility); | ||
| 171 | view.thing.setFocusedByDefault (isFocusedByDefault); | ||
| 164 | notify (); | 172 | notify (); |
| 165 | } | 173 | } |
| 166 | } | 174 | } |
| @@ -183,48 +191,6 @@ public class EmacsService extends Service | |||
| 183 | return view.thing; | 191 | return view.thing; |
| 184 | } | 192 | } |
| 185 | 193 | ||
| 186 | /* Notice that a child of the root window named WINDOW is now | ||
| 187 | available for attachment to a specific activity. */ | ||
| 188 | |||
| 189 | public void | ||
| 190 | noticeAvailableChild (final EmacsWindow window) | ||
| 191 | { | ||
| 192 | Log.d (TAG, "A new child is available: " + window); | ||
| 193 | |||
| 194 | handler.post (new Runnable () { | ||
| 195 | public void | ||
| 196 | run () | ||
| 197 | { | ||
| 198 | for (EmacsActivity activity | ||
| 199 | : EmacsActivity.availableActivities) | ||
| 200 | { | ||
| 201 | /* TODO: check if the activity matches. */ | ||
| 202 | activity.attachChild (window); | ||
| 203 | break; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* Nope, wait for an activity to become available. */ | ||
| 207 | availableChildren.add (window); | ||
| 208 | } | ||
| 209 | }); | ||
| 210 | } | ||
| 211 | |||
| 212 | /* Notice that a child of the root window named WINDOW has been | ||
| 213 | destroyed. */ | ||
| 214 | |||
| 215 | public void | ||
| 216 | noticeChildDestroyed (final EmacsWindow child) | ||
| 217 | { | ||
| 218 | handler.post (new Runnable () { | ||
| 219 | @Override | ||
| 220 | public void | ||
| 221 | run () | ||
| 222 | { | ||
| 223 | availableChildren.remove (child); | ||
| 224 | } | ||
| 225 | }); | ||
| 226 | } | ||
| 227 | |||
| 228 | /* X drawing operations. These are quite primitive operations. The | 194 | /* X drawing operations. These are quite primitive operations. The |
| 229 | drawing queue is kept on the Emacs thread, but is periodically | 195 | drawing queue is kept on the Emacs thread, but is periodically |
| 230 | flushed to the application thread, upon buffers swaps and once it | 196 | flushed to the application thread, upon buffers swaps and once it |
| @@ -311,11 +277,6 @@ public class EmacsService extends Service | |||
| 311 | 277 | ||
| 312 | ensurePaintQueue (); | 278 | ensurePaintQueue (); |
| 313 | 279 | ||
| 314 | if (gc.clip_rects != null && gc.clip_rects.length >= 1) | ||
| 315 | android.util.Log.d ("drawRectangle", | ||
| 316 | gc.clip_rects[0].toString () | ||
| 317 | + " " + gc.toString ()); | ||
| 318 | |||
| 319 | req = new EmacsDrawRectangle (drawable, x, y, | 280 | req = new EmacsDrawRectangle (drawable, x, y, |
| 320 | width, height, | 281 | width, height, |
| 321 | gc.immutableGC ()); | 282 | gc.immutableGC ()); |
| @@ -381,4 +342,12 @@ public class EmacsService extends Service | |||
| 381 | { | 342 | { |
| 382 | window.clearArea (x, y, width, height); | 343 | window.clearArea (x, y, width, height); |
| 383 | } | 344 | } |
| 345 | |||
| 346 | public void | ||
| 347 | appendPaintOperation (EmacsPaintReq op) | ||
| 348 | { | ||
| 349 | ensurePaintQueue (); | ||
| 350 | paintQueue.appendPaintOperation (op); | ||
| 351 | checkFlush (); | ||
| 352 | } | ||
| 384 | }; | 353 | }; |
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java b/java/org/gnu/emacs/EmacsSurfaceView.java index 194f6ad37a3..b8b828e4820 100644 --- a/java/org/gnu/emacs/EmacsSurfaceView.java +++ b/java/org/gnu/emacs/EmacsSurfaceView.java | |||
| @@ -22,6 +22,8 @@ package org.gnu.emacs; | |||
| 22 | import android.view.SurfaceView; | 22 | import android.view.SurfaceView; |
| 23 | import android.view.SurfaceHolder; | 23 | import android.view.SurfaceHolder; |
| 24 | 24 | ||
| 25 | import android.os.Build; | ||
| 26 | |||
| 25 | import android.graphics.Canvas; | 27 | import android.graphics.Canvas; |
| 26 | import android.graphics.Rect; | 28 | import android.graphics.Rect; |
| 27 | 29 | ||
| @@ -40,7 +42,9 @@ public class EmacsSurfaceView extends SurfaceView | |||
| 40 | surfaceChanged (SurfaceHolder holder, int format, | 42 | surfaceChanged (SurfaceHolder holder, int format, |
| 41 | int width, int height) | 43 | int width, int height) |
| 42 | { | 44 | { |
| 43 | 45 | /* Force a buffer swap now to get the contents of the Emacs | |
| 46 | view on screen. */ | ||
| 47 | view.swapBuffers (true); | ||
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | @Override | 50 | @Override |
| @@ -51,7 +55,7 @@ public class EmacsSurfaceView extends SurfaceView | |||
| 51 | 55 | ||
| 52 | /* Force a buffer swap now to get the contents of the Emacs | 56 | /* Force a buffer swap now to get the contents of the Emacs |
| 53 | view on screen. */ | 57 | view on screen. */ |
| 54 | view.swapBuffers (); | 58 | view.swapBuffers (true); |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | @Override | 61 | @Override |
| @@ -72,12 +76,37 @@ public class EmacsSurfaceView extends SurfaceView | |||
| 72 | public Canvas | 76 | public Canvas |
| 73 | lockCanvas (Rect damage) | 77 | lockCanvas (Rect damage) |
| 74 | { | 78 | { |
| 75 | return getHolder ().lockCanvas (damage); | 79 | SurfaceHolder holder; |
| 80 | |||
| 81 | holder = getHolder (); | ||
| 82 | |||
| 83 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) | ||
| 84 | { | ||
| 85 | damage.setEmpty (); | ||
| 86 | return holder.lockHardwareCanvas (); | ||
| 87 | } | ||
| 88 | |||
| 89 | return holder.lockCanvas (damage); | ||
| 90 | } | ||
| 91 | |||
| 92 | /* This method is only used during debugging when it seems damage | ||
| 93 | isn't working correctly. */ | ||
| 94 | |||
| 95 | public Canvas | ||
| 96 | lockCanvas () | ||
| 97 | { | ||
| 98 | SurfaceHolder holder; | ||
| 99 | |||
| 100 | holder = getHolder (); | ||
| 101 | return holder.lockCanvas (); | ||
| 76 | } | 102 | } |
| 77 | 103 | ||
| 78 | public void | 104 | public void |
| 79 | unlockCanvasAndPost (Canvas canvas) | 105 | unlockCanvasAndPost (Canvas canvas) |
| 80 | { | 106 | { |
| 81 | getHolder ().unlockCanvasAndPost (canvas); | 107 | SurfaceHolder holder; |
| 108 | |||
| 109 | holder = getHolder (); | ||
| 110 | holder.unlockCanvasAndPost (canvas); | ||
| 82 | } | 111 | } |
| 83 | }; | 112 | }; |
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 237946d6366..7b48eaf0aa6 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java | |||
| @@ -19,17 +19,20 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | 19 | ||
| 20 | package org.gnu.emacs; | 20 | package org.gnu.emacs; |
| 21 | 21 | ||
| 22 | import android.content.res.ColorStateList; | ||
| 23 | |||
| 22 | import android.view.View; | 24 | import android.view.View; |
| 23 | import android.view.KeyEvent; | 25 | import android.view.KeyEvent; |
| 24 | import android.view.ViewGroup; | 26 | import android.view.ViewGroup; |
| 27 | |||
| 25 | import android.graphics.Bitmap; | 28 | import android.graphics.Bitmap; |
| 26 | import android.graphics.Canvas; | 29 | import android.graphics.Canvas; |
| 27 | import android.graphics.Rect; | 30 | import android.graphics.Rect; |
| 28 | import android.graphics.Region; | 31 | import android.graphics.Region; |
| 29 | import android.graphics.Paint; | 32 | import android.graphics.Paint; |
| 30 | import android.util.Log; | ||
| 31 | 33 | ||
| 32 | import android.os.Build; | 34 | import android.os.Build; |
| 35 | import android.util.Log; | ||
| 33 | 36 | ||
| 34 | /* This is an Android view which has a back and front buffer. When | 37 | /* This is an Android view which has a back and front buffer. When |
| 35 | swapBuffers is called, the back buffer is swapped to the front | 38 | swapBuffers is called, the back buffer is swapped to the front |
| @@ -70,10 +73,11 @@ public class EmacsView extends ViewGroup | |||
| 70 | this.damageRegion = new Region (); | 73 | this.damageRegion = new Region (); |
| 71 | this.paint = new Paint (); | 74 | this.paint = new Paint (); |
| 72 | 75 | ||
| 76 | setFocusable (true); | ||
| 77 | setFocusableInTouchMode (true); | ||
| 78 | |||
| 73 | /* Create the surface view. */ | 79 | /* Create the surface view. */ |
| 74 | this.surfaceView = new EmacsSurfaceView (this); | 80 | this.surfaceView = new EmacsSurfaceView (this); |
| 75 | |||
| 76 | setFocusable (FOCUSABLE); | ||
| 77 | addView (this.surfaceView); | 81 | addView (this.surfaceView); |
| 78 | } | 82 | } |
| 79 | 83 | ||
| @@ -162,7 +166,7 @@ public class EmacsView extends ViewGroup | |||
| 162 | } | 166 | } |
| 163 | 167 | ||
| 164 | public void | 168 | public void |
| 165 | swapBuffers () | 169 | swapBuffers (boolean force) |
| 166 | { | 170 | { |
| 167 | Bitmap back; | 171 | Bitmap back; |
| 168 | Canvas canvas; | 172 | Canvas canvas; |
| @@ -185,14 +189,25 @@ public class EmacsView extends ViewGroup | |||
| 185 | if (canvas == null) | 189 | if (canvas == null) |
| 186 | return; | 190 | return; |
| 187 | 191 | ||
| 188 | /* Copy from the back buffer to the canvas. */ | 192 | /* Copy from the back buffer to the canvas. If damageRect was |
| 189 | canvas.drawBitmap (bitmap, damageRect, damageRect, paint); | 193 | made empty, then draw the entire back buffer. */ |
| 194 | |||
| 195 | if (damageRect.isEmpty ()) | ||
| 196 | canvas.drawBitmap (bitmap, 0f, 0f, paint); | ||
| 197 | else | ||
| 198 | canvas.drawBitmap (bitmap, damageRect, damageRect, paint); | ||
| 190 | 199 | ||
| 191 | /* Unlock the canvas and clear the damage. */ | 200 | /* Unlock the canvas and clear the damage. */ |
| 192 | surfaceView.unlockCanvasAndPost (canvas); | 201 | surfaceView.unlockCanvasAndPost (canvas); |
| 193 | damageRegion.setEmpty (); | 202 | damageRegion.setEmpty (); |
| 194 | } | 203 | } |
| 195 | 204 | ||
| 205 | public void | ||
| 206 | swapBuffers () | ||
| 207 | { | ||
| 208 | swapBuffers (false); | ||
| 209 | } | ||
| 210 | |||
| 196 | @Override | 211 | @Override |
| 197 | public boolean | 212 | public boolean |
| 198 | onKeyDown (int keyCode, KeyEvent event) | 213 | onKeyDown (int keyCode, KeyEvent event) |
| @@ -203,9 +218,27 @@ public class EmacsView extends ViewGroup | |||
| 203 | 218 | ||
| 204 | @Override | 219 | @Override |
| 205 | public boolean | 220 | public boolean |
| 221 | onKeyMultiple (int keyCode, int repeatCount, KeyEvent event) | ||
| 222 | { | ||
| 223 | window.onKeyDown (keyCode, event); | ||
| 224 | return true; | ||
| 225 | } | ||
| 226 | |||
| 227 | @Override | ||
| 228 | public boolean | ||
| 206 | onKeyUp (int keyCode, KeyEvent event) | 229 | onKeyUp (int keyCode, KeyEvent event) |
| 207 | { | 230 | { |
| 208 | window.onKeyUp (keyCode, event); | 231 | window.onKeyUp (keyCode, event); |
| 209 | return true; | 232 | return true; |
| 210 | } | 233 | } |
| 234 | |||
| 235 | @Override | ||
| 236 | public void | ||
| 237 | onFocusChanged (boolean gainFocus, int direction, | ||
| 238 | Rect previouslyFocusedRect) | ||
| 239 | { | ||
| 240 | window.onFocusChanged (gainFocus); | ||
| 241 | super.onFocusChanged (gainFocus, direction, | ||
| 242 | previouslyFocusedRect); | ||
| 243 | } | ||
| 211 | }; | 244 | }; |
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index 28db04a261d..26e788a20a8 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java | |||
| @@ -32,6 +32,8 @@ import android.view.View; | |||
| 32 | import android.view.ViewGroup; | 32 | import android.view.ViewGroup; |
| 33 | import android.view.KeyEvent; | 33 | import android.view.KeyEvent; |
| 34 | 34 | ||
| 35 | import android.content.Intent; | ||
| 36 | |||
| 35 | /* This defines a window, which is a handle. Windows represent a | 37 | /* This defines a window, which is a handle. Windows represent a |
| 36 | rectangular subset of the screen with their own contents. | 38 | rectangular subset of the screen with their own contents. |
| 37 | 39 | ||
| @@ -57,10 +59,10 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 57 | 59 | ||
| 58 | /* List of all children in stacking order. This must be kept | 60 | /* List of all children in stacking order. This must be kept |
| 59 | consistent! */ | 61 | consistent! */ |
| 60 | private ArrayList<EmacsWindow> children; | 62 | public ArrayList<EmacsWindow> children; |
| 61 | 63 | ||
| 62 | /* The EmacsActivity currently attached, if it exists. */ | 64 | /* The window consumer currently attached, if it exists. */ |
| 63 | private EmacsActivity attached; | 65 | private EmacsWindowAttachmentManager.WindowConsumer attached; |
| 64 | 66 | ||
| 65 | /* The window background scratch GC. foreground is always the | 67 | /* The window background scratch GC. foreground is always the |
| 66 | window background. */ | 68 | window background. */ |
| @@ -74,35 +76,44 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 74 | 76 | ||
| 75 | rect = new Rect (x, y, x + width, y + height); | 77 | rect = new Rect (x, y, x + width, y + height); |
| 76 | 78 | ||
| 77 | /* Create the view from the context's UI thread. */ | 79 | /* Create the view from the context's UI thread. The window is |
| 78 | view = EmacsService.SERVICE.getEmacsView (this); | 80 | unmapped, so the view is GONE. */ |
| 81 | view = EmacsService.SERVICE.getEmacsView (this, View.GONE, | ||
| 82 | parent == null); | ||
| 79 | this.parent = parent; | 83 | this.parent = parent; |
| 80 | children = new ArrayList<EmacsWindow> (); | ||
| 81 | 84 | ||
| 82 | /* The window is unmapped by default. */ | 85 | /* Create the list of children. */ |
| 83 | view.setVisibility (View.GONE); | 86 | children = new ArrayList<EmacsWindow> (); |
| 84 | 87 | ||
| 85 | /* If parent is the root window, notice that there are new | 88 | if (parent != null) |
| 86 | children available for interested activites to pick up. */ | ||
| 87 | if (parent == null) | ||
| 88 | EmacsService.SERVICE.noticeAvailableChild (this); | ||
| 89 | else | ||
| 90 | { | 89 | { |
| 91 | /* Otherwise, directly add this window as a child of that | 90 | parent.children.add (this); |
| 92 | window's view. */ | 91 | parent.view.post (new Runnable () { |
| 93 | synchronized (parent) | 92 | @Override |
| 93 | public void | ||
| 94 | run () | ||
| 95 | { | ||
| 96 | parent.view.addView (view); | ||
| 97 | } | ||
| 98 | }); | ||
| 99 | } | ||
| 100 | else | ||
| 101 | EmacsService.SERVICE.runOnUiThread (new Runnable () { | ||
| 102 | @Override | ||
| 103 | public void | ||
| 104 | run () | ||
| 94 | { | 105 | { |
| 95 | parent.children.add (this); | 106 | EmacsWindowAttachmentManager manager; |
| 96 | parent.view.post (new Runnable () { | 107 | |
| 97 | @Override | 108 | manager = EmacsWindowAttachmentManager.MANAGER; |
| 98 | public void | 109 | |
| 99 | run () | 110 | /* If parent is the root window, notice that there are new |
| 100 | { | 111 | children available for interested activites to pick |
| 101 | parent.view.addView (view); | 112 | up. */ |
| 102 | } | 113 | |
| 103 | }); | 114 | manager.registerWindow (EmacsWindow.this); |
| 104 | } | 115 | } |
| 105 | } | 116 | }); |
| 106 | 117 | ||
| 107 | scratchGC = new EmacsGC ((short) 0); | 118 | scratchGC = new EmacsGC ((short) 0); |
| 108 | } | 119 | } |
| @@ -129,28 +140,35 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 129 | public void | 140 | public void |
| 130 | destroyHandle () throws IllegalStateException | 141 | destroyHandle () throws IllegalStateException |
| 131 | { | 142 | { |
| 132 | synchronized (this) | 143 | if (parent != null) |
| 133 | { | 144 | parent.children.remove (this); |
| 134 | if (!children.isEmpty ()) | 145 | |
| 135 | throw new IllegalStateException ("Trying to destroy window with " | 146 | EmacsActivity.invalidateFocus (); |
| 136 | + "children!"); | ||
| 137 | } | ||
| 138 | 147 | ||
| 139 | /* Notice that the child has been destroyed. */ | 148 | if (!children.isEmpty ()) |
| 140 | EmacsService.SERVICE.noticeChildDestroyed (this); | 149 | throw new IllegalStateException ("Trying to destroy window with " |
| 150 | + "children!"); | ||
| 141 | 151 | ||
| 142 | /* Remove the view from its parent and make it invisible. */ | 152 | /* Remove the view from its parent and make it invisible. */ |
| 143 | view.post (new Runnable () { | 153 | view.post (new Runnable () { |
| 144 | public void | 154 | public void |
| 145 | run () | 155 | run () |
| 146 | { | 156 | { |
| 157 | View parent; | ||
| 158 | EmacsWindowAttachmentManager manager; | ||
| 159 | |||
| 160 | if (EmacsActivity.focusedWindow == EmacsWindow.this) | ||
| 161 | EmacsActivity.focusedWindow = null; | ||
| 162 | |||
| 163 | manager = EmacsWindowAttachmentManager.MANAGER; | ||
| 147 | view.setVisibility (View.GONE); | 164 | view.setVisibility (View.GONE); |
| 148 | 165 | ||
| 149 | if (view.getParent () != null) | 166 | parent = (View) view.getParent (); |
| 150 | ((ViewGroup) view.getParent ()).removeView (view); | ||
| 151 | 167 | ||
| 152 | if (attached != null) | 168 | if (parent != null && attached == null) |
| 153 | attached.makeAvailable (); | 169 | ((ViewGroup) parent).removeView (view); |
| 170 | |||
| 171 | manager.detachWindow (EmacsWindow.this); | ||
| 154 | } | 172 | } |
| 155 | }); | 173 | }); |
| 156 | 174 | ||
| @@ -158,12 +176,15 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 158 | } | 176 | } |
| 159 | 177 | ||
| 160 | public void | 178 | public void |
| 161 | setActivity (EmacsActivity activity) | 179 | setConsumer (EmacsWindowAttachmentManager.WindowConsumer consumer) |
| 162 | { | 180 | { |
| 163 | synchronized (this) | 181 | attached = consumer; |
| 164 | { | 182 | } |
| 165 | activity = activity; | 183 | |
| 166 | } | 184 | public EmacsWindowAttachmentManager.WindowConsumer |
| 185 | getAttachedConsumer () | ||
| 186 | { | ||
| 187 | return attached; | ||
| 167 | } | 188 | } |
| 168 | 189 | ||
| 169 | public void | 190 | public void |
| @@ -233,7 +254,10 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 233 | public void | 254 | public void |
| 234 | run () | 255 | run () |
| 235 | { | 256 | { |
| 257 | |||
| 236 | view.setVisibility (View.VISIBLE); | 258 | view.setVisibility (View.VISIBLE); |
| 259 | /* Eventually this should check no-focus-on-map. */ | ||
| 260 | view.requestFocus (); | ||
| 237 | } | 261 | } |
| 238 | }); | 262 | }); |
| 239 | } | 263 | } |
| @@ -319,18 +343,47 @@ public class EmacsWindow extends EmacsHandleObject | |||
| 319 | public void | 343 | public void |
| 320 | onKeyDown (int keyCode, KeyEvent event) | 344 | onKeyDown (int keyCode, KeyEvent event) |
| 321 | { | 345 | { |
| 346 | int state; | ||
| 347 | |||
| 348 | state = event.getModifiers (); | ||
| 349 | state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); | ||
| 350 | |||
| 322 | EmacsNative.sendKeyPress (this.handle, | 351 | EmacsNative.sendKeyPress (this.handle, |
| 323 | event.getEventTime (), | 352 | event.getEventTime (), |
| 324 | event.getModifiers (), | 353 | event.getModifiers (), |
| 325 | keyCode); | 354 | keyCode, |
| 355 | /* Ignore meta-state understood by Emacs | ||
| 356 | for now, or Ctrl+C will not be | ||
| 357 | recognized as an ASCII key press | ||
| 358 | event. */ | ||
| 359 | event.getUnicodeChar (state)); | ||
| 326 | } | 360 | } |
| 327 | 361 | ||
| 328 | public void | 362 | public void |
| 329 | onKeyUp (int keyCode, KeyEvent event) | 363 | onKeyUp (int keyCode, KeyEvent event) |
| 330 | { | 364 | { |
| 365 | int state; | ||
| 366 | |||
| 367 | state = event.getModifiers (); | ||
| 368 | state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK); | ||
| 369 | |||
| 331 | EmacsNative.sendKeyRelease (this.handle, | 370 | EmacsNative.sendKeyRelease (this.handle, |
| 332 | event.getEventTime (), | 371 | event.getEventTime (), |
| 333 | event.getModifiers (), | 372 | event.getModifiers (), |
| 334 | keyCode); | 373 | keyCode, |
| 374 | event.getUnicodeChar (state)); | ||
| 375 | } | ||
| 376 | |||
| 377 | public void | ||
| 378 | onFocusChanged (boolean gainFocus) | ||
| 379 | { | ||
| 380 | EmacsActivity.invalidateFocus (); | ||
| 381 | } | ||
| 382 | |||
| 383 | public void | ||
| 384 | onActivityDetached () | ||
| 385 | { | ||
| 386 | /* Destroy the associated frame when the activity is detached. */ | ||
| 387 | EmacsNative.sendWindowAction (this.handle, 0); | ||
| 335 | } | 388 | } |
| 336 | }; | 389 | }; |
diff --git a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java new file mode 100644 index 00000000000..34be2ab8789 --- /dev/null +++ b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | /* Communication module for Android terminals. -*- c-file-style: "GNU" -*- | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | package org.gnu.emacs; | ||
| 21 | |||
| 22 | import java.util.LinkedList; | ||
| 23 | import java.util.List; | ||
| 24 | |||
| 25 | import android.content.Intent; | ||
| 26 | import android.util.Log; | ||
| 27 | |||
| 28 | /* Code to paper over the differences in lifecycles between | ||
| 29 | "activities" and windows. There are four interfaces to an instance | ||
| 30 | of this class: | ||
| 31 | |||
| 32 | registerWindowConsumer (WindowConsumer) | ||
| 33 | registerWindow (EmacsWindow) | ||
| 34 | removeWindowConsumer (WindowConsumer) | ||
| 35 | removeWindow (EmacsWindow) | ||
| 36 | |||
| 37 | A WindowConsumer is expected to allow an EmacsWindow to be attached | ||
| 38 | to it, and be created or destroyed. | ||
| 39 | |||
| 40 | Every time a window is created, registerWindow checks the list of | ||
| 41 | window consumers. If a consumer exists and does not currently have | ||
| 42 | a window of its own attached, it gets the new window. Otherwise, | ||
| 43 | the window attachment manager starts a new consumer. | ||
| 44 | |||
| 45 | Every time a consumer is registered, registerWindowConsumer checks | ||
| 46 | the list of available windows. If a window exists and is not | ||
| 47 | currently attached to a consumer, then the consumer gets it. | ||
| 48 | |||
| 49 | Finally, every time a window is removed, the consumer is | ||
| 50 | destroyed. */ | ||
| 51 | |||
| 52 | public class EmacsWindowAttachmentManager | ||
| 53 | { | ||
| 54 | public static EmacsWindowAttachmentManager MANAGER; | ||
| 55 | private final static String TAG = "EmacsWindowAttachmentManager"; | ||
| 56 | |||
| 57 | static | ||
| 58 | { | ||
| 59 | MANAGER = new EmacsWindowAttachmentManager (); | ||
| 60 | }; | ||
| 61 | |||
| 62 | public interface WindowConsumer | ||
| 63 | { | ||
| 64 | public void attachWindow (EmacsWindow window); | ||
| 65 | public EmacsWindow getAttachedWindow (); | ||
| 66 | public void detachWindow (); | ||
| 67 | public void destroy (); | ||
| 68 | }; | ||
| 69 | |||
| 70 | private List<WindowConsumer> consumers; | ||
| 71 | private List<EmacsWindow> windows; | ||
| 72 | |||
| 73 | public | ||
| 74 | EmacsWindowAttachmentManager () | ||
| 75 | { | ||
| 76 | consumers = new LinkedList<WindowConsumer> (); | ||
| 77 | windows = new LinkedList<EmacsWindow> (); | ||
| 78 | } | ||
| 79 | |||
| 80 | public void | ||
| 81 | registerWindowConsumer (WindowConsumer consumer) | ||
| 82 | { | ||
| 83 | Log.d (TAG, "registerWindowConsumer " + consumer); | ||
| 84 | |||
| 85 | consumers.add (consumer); | ||
| 86 | |||
| 87 | for (EmacsWindow window : windows) | ||
| 88 | { | ||
| 89 | if (window.getAttachedConsumer () == null) | ||
| 90 | { | ||
| 91 | Log.d (TAG, "registerWindowConsumer: attaching " + window); | ||
| 92 | consumer.attachWindow (window); | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | Log.d (TAG, "registerWindowConsumer: sendWindowAction 0, 0"); | ||
| 98 | EmacsNative.sendWindowAction ((short) 0, 0); | ||
| 99 | } | ||
| 100 | |||
| 101 | public void | ||
| 102 | registerWindow (EmacsWindow window) | ||
| 103 | { | ||
| 104 | Intent intent; | ||
| 105 | |||
| 106 | Log.d (TAG, "registerWindow " + window); | ||
| 107 | windows.add (window); | ||
| 108 | |||
| 109 | for (WindowConsumer consumer : consumers) | ||
| 110 | { | ||
| 111 | if (consumer.getAttachedWindow () == null) | ||
| 112 | { | ||
| 113 | Log.d (TAG, "registerWindow: attaching " + consumer); | ||
| 114 | consumer.attachWindow (window); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | intent = new Intent (EmacsService.SERVICE, | ||
| 120 | EmacsMultitaskActivity.class); | ||
| 121 | intent.addFlags (Intent.FLAG_ACTIVITY_NEW_DOCUMENT | ||
| 122 | | Intent.FLAG_ACTIVITY_NEW_TASK | ||
| 123 | | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||
| 124 | EmacsService.SERVICE.startActivity (intent); | ||
| 125 | Log.d (TAG, "registerWindow: startActivity"); | ||
| 126 | } | ||
| 127 | |||
| 128 | public void | ||
| 129 | removeWindowConsumer (WindowConsumer consumer) | ||
| 130 | { | ||
| 131 | EmacsWindow window; | ||
| 132 | |||
| 133 | Log.d (TAG, "removeWindowConsumer " + consumer); | ||
| 134 | |||
| 135 | window = consumer.getAttachedWindow (); | ||
| 136 | |||
| 137 | if (window != null) | ||
| 138 | { | ||
| 139 | Log.d (TAG, "removeWindowConsumer: detaching " + window); | ||
| 140 | |||
| 141 | consumer.detachWindow (); | ||
| 142 | window.onActivityDetached (); | ||
| 143 | } | ||
| 144 | |||
| 145 | Log.d (TAG, "removeWindowConsumer: removing " + consumer); | ||
| 146 | consumers.remove (consumer); | ||
| 147 | } | ||
| 148 | |||
| 149 | public void | ||
| 150 | detachWindow (EmacsWindow window) | ||
| 151 | { | ||
| 152 | WindowConsumer consumer; | ||
| 153 | |||
| 154 | Log.d (TAG, "detachWindow " + window); | ||
| 155 | |||
| 156 | if (window.getAttachedConsumer () != null) | ||
| 157 | { | ||
| 158 | consumer = window.getAttachedConsumer (); | ||
| 159 | |||
| 160 | Log.d (TAG, "detachWindow: removing" + consumer); | ||
| 161 | |||
| 162 | consumers.remove (consumer); | ||
| 163 | consumer.destroy (); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | }; | ||