the frame @var{frame}. If @var{hide} is non-@code{nil}, then the
on-screen keyboard is hidden; otherwise, it is displayed.
+It returns whether or not the on screen keyboard @strong{may} have
+been displayed, which should be used to determine whether or not to
+hide the on-screen keyboard later.
+
This has no effect if the system automatically detects when to display
the on-screen keyboard, or when it does not provide any on-screen
keyboard.
surfaceChanged (SurfaceHolder holder, int format,
int width, int height)
{
- Log.d (TAG, "surfaceChanged: " + view + ", " + view.pendingConfigure);
+ Canvas canvas;
- /* Make sure not to swap buffers if there is pending
- configuration, because otherwise the redraw callback will not
- run correctly. */
+ Log.d (TAG, "surfaceChanged: " + view + ", ");
- if (view.pendingConfigure == 0)
- view.swapBuffers ();
+ view.swapBuffers (true);
}
@Override
/* Drop the lock when doing this, or a deadlock can
result. */
- view.swapBuffers ();
+ view.swapBuffers (true);
}
@Override
}
}
- /* And this is the callback used on Android 26 and later. It is
- used because it can tell the system when drawing completes. */
-
- private class Callback2 extends Callback implements SurfaceHolder.Callback2
- {
- @Override
- public void
- surfaceRedrawNeeded (SurfaceHolder holder)
- {
- /* This version is not supported. */
- return;
- }
-
- @Override
- public void
- surfaceRedrawNeededAsync (SurfaceHolder holder,
- Runnable drawingFinished)
- {
- Runnable old;
-
- Log.d (TAG, "surfaceRedrawNeededAsync: " + view.pendingConfigure);
-
- /* The system calls this function when it wants to know whether
- or not Emacs is still configuring itself in response to a
- resize.
-
- If the view did not send an outstanding ConfigureNotify
- event, then call drawingFinish immediately. Else, give it to
- the view to execute after drawing completes. */
-
- if (view.pendingConfigure == 0)
- drawingFinished.run ();
- else
- /* And set this runnable to run once drawing completes. */
- view.drawingFinished = drawingFinished;
- }
- }
-
public
EmacsSurfaceView (final EmacsView view)
{
this.surfaceChangeLock = new Object ();
this.view = view;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
- getHolder ().addCallback (new Callback ());
- else
- getHolder ().addCallback (new Callback2 ());
+ getHolder ().addCallback (new Callback ());
}
public boolean
/* The InputMethodManager for this view's context. */
private InputMethodManager imManager;
- /* Runnable that will run once drawing completes. */
- public Runnable drawingFinished;
-
- /* Serial of the last ConfigureNotify event sent that Emacs has not
- yet responded to. 0 if there is no such outstanding event. */
- public long pendingConfigure;
-
/* Whether or not this view is attached to a window. */
public boolean isAttachedToWindow;
displayed whenever possible. */
public boolean isCurrentlyTextEditor;
+ /* An empty rectangle. */
+ public static final Rect emptyRect;
+
+ static
+ {
+ emptyRect = new Rect ();
+ };
+
public
EmacsView (EmacsWindow window)
{
int count, i;
View child;
Rect windowRect;
+ int wantedWidth, wantedHeight;
count = getChildCount ();
- if (changed || mustReportLayout)
- {
- mustReportLayout = false;
- pendingConfigure
- = window.viewLayout (left, top, right, bottom);
- }
-
measuredWidth = right - left;
measuredHeight = bottom - top;
Log.d (TAG, "onLayout: " + child);
if (child == surfaceView)
- /* The child is the surface view, so give it the entire
- view. */
child.layout (0, 0, right - left, bottom - top);
else if (child.getVisibility () != GONE)
{
windowRect.right, windowRect.bottom);
}
}
+
+ /* Now report the layout change to the window. */
+
+ if (changed || mustReportLayout)
+ {
+ mustReportLayout = false;
+ window.viewLayout (left, top, right, bottom);
+ }
}
public void
synchronized (damageRegion)
{
- if (damageRegion.isEmpty ())
+ if (!force && damageRegion.isEmpty ())
return;
bitmap = getBitmap ();
synchronized (surfaceView.surfaceChangeLock)
{
- damageRect = damageRegion.getBounds ();
+ if (!force)
+ damageRect = damageRegion.getBounds ();
+ else
+ damageRect = emptyRect;
if (!surfaceView.isCreated ())
return;
isCurrentlyTextEditor = false;
}
- public void
- windowUpdated (long serial)
- {
- Log.d (TAG, "windowUpdated: serial is " + serial);
-
- if (pendingConfigure <= serial
- /* Detect wraparound. */
- || pendingConfigure - serial >= 0x7fffffff)
- {
- pendingConfigure = 0;
-
- if (drawingFinished != null)
- drawingFinished.run ();
-
- drawingFinished = null;
- }
- }
-
@Override
public InputConnection
onCreateInputConnection (EditorInfo info)
keyboard on behalf of the frame FRAME if HIDE is nil. Else, hide
the on screen keyboard.
+Return whether or not the on screen keyboard may have been
+displayed; that is, return t on systems with an on screen
+keyboard, and nil on those without.
+
FRAME must already have the input focus for this to work
reliably."
(let ((frame-type (framep-on-display frame)))
(cond ((eq frame-type 'android)
- (android-toggle-on-screen-keyboard frame hide)))))
+ (android-toggle-on-screen-keyboard frame hide) t)
+ (t nil))))
\f
;;;; Frame geometry values
;; Try to display the on screen keyboard whenever entering the
;; mini-buffer, and hide it whenever leaving.
+(defvar minibuffer-on-screen-keyboard-timer nil
+ "Timer run upon exiting the minibuffer.
+It will hide the on screen keyboard when necessary.")
+
+(defvar minibuffer-on-screen-keyboard-displayed nil
+ "Whether or not the on-screen keyboard has been displayed.
+Set inside `minibuffer-setup-on-screen-keyboard'.")
+
(defun minibuffer-setup-on-screen-keyboard ()
"Maybe display the on-screen keyboard in the current frame.
Display the on-screen keyboard in the current frame if the
last device to have sent an input event is not a keyboard.
This is run upon minibuffer setup."
+ ;; Don't hide the on screen keyboard later on.
+ (when minibuffer-on-screen-keyboard-timer
+ (cancel-timer minibuffer-on-screen-keyboard-timer)
+ (setq minibuffer-on-screen-keyboard-timer nil))
+ (setq minibuffer-on-screen-keyboard-displayed nil)
(when (not (memq (device-class last-event-frame
last-event-device)
'(keyboard core-keyboard)))
- (frame-toggle-on-screen-keyboard (selected-frame) nil)))
+ (setq minibuffer-on-screen-keyboard-displayed
+ (frame-toggle-on-screen-keyboard (selected-frame) nil))))
(defun minibuffer-exit-on-screen-keyboard ()
"Hide the on-screen keyboard if it was displayed.
-This is run upon minibuffer exit."
- (frame-toggle-on-screen-keyboard (selected-frame) t))
+Hide the on-screen keyboard in a timer set to run in 0.1 seconds.
+It will be cancelled if the minibuffer is displayed again within
+that timeframe.
+
+Do not hide the on screen keyboard inside a recursive edit.
+Likewise, do not hide the on screen keyboard if point in the
+window that will be selected after exiting the minibuffer is not
+on read-only text.
+
+The latter is implemented in `touch-screen.el'."
+ (unless (or (not minibuffer-on-screen-keyboard-displayed)
+ (> (recursion-depth) 1))
+ (when minibuffer-on-screen-keyboard-timer
+ (cancel-timer minibuffer-on-screen-keyboard-timer))
+ (setq minibuffer-on-screen-keyboard-timer
+ (run-with-timer 0.1 nil #'frame-toggle-on-screen-keyboard
+ (selected-frame) t))))
(add-hook 'minibuffer-setup-hook #'minibuffer-setup-on-screen-keyboard)
(add-hook 'minibuffer-exit-hook #'minibuffer-exit-on-screen-keyboard)
(goto-char (1+ (window-end nil t))))
(redisplay))))))))))))
+(defun touch-screen-window-selection-changed (frame)
+ "Notice that FRAME's selected window has changed.
+If point is now on read only text, hide the on screen keyboard.
+Otherwise, cancel any timer that is supposed to hide the keyboard
+in response to the minibuffer being closed."
+ (with-selected-frame frame
+ (if (or buffer-read-only
+ (get-text-property (point) 'read-only))
+ (frame-toggle-on-screen-keyboard (selected-frame) t)
+ ;; Prevent hiding the minibuffer from hiding the on screen
+ ;; keyboard.
+ (when minibuffer-on-screen-keyboard-timer
+ (cancel-timer minibuffer-on-screen-keyboard-timer)
+ (setq minibuffer-on-screen-keyboard-timer nil)))))
+
(defun touch-screen-handle-point-up (point)
"Notice that POINT has been removed from the screen.
POINT should be the point currently tracked as
(when (memq command touch-screen-set-point-commands)
(if (not (or buffer-read-only
(get-text-property (point) 'read-only)))
- (frame-toggle-on-screen-keyboard (selected-frame) nil)
+ ;; Once the on-screen keyboard has been opened,
+ ;; add `touch-screen-window-selection-changed'
+ ;; as a window selection change function This
+ ;; allows the on screen keyboard to be hidden
+ ;; if the selected window's point becomes read
+ ;; only at some point in the future.
+ (progn
+ (add-hook 'window-selection-change-functions
+ #'touch-screen-window-selection-changed)
+ (frame-toggle-on-screen-keyboard (selected-frame) nil))
;; Otherwise, hide the on screen keyboard now.
(frame-toggle-on-screen-keyboard (selected-frame) t))))))))))
jclass class;
jmethodID swap_buffers;
jmethodID toggle_on_screen_keyboard;
- jmethodID window_updated;
};
/* The API level of the current device. */
FIND_METHOD (swap_buffers, "swapBuffers", "()V");
FIND_METHOD (toggle_on_screen_keyboard,
"toggleOnScreenKeyboard", "(Z)V");
- FIND_METHOD (window_updated, "windowUpdated", "(J)V");
#undef FIND_METHOD
}
android_exception_check ();
}
-/* Tell the window system that all configure events sent to WINDOW
- have been fully processed, and that it is now okay to display its
- new contents. SERIAL is the serial of the last configure event
- processed. */
-
-void
-android_window_updated (android_window window, unsigned long serial)
-{
- jobject object;
- jmethodID method;
-
- object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
- method = window_class.window_updated;
-
- (*android_java_env)->CallVoidMethod (android_java_env, object,
- method, (jlong) serial);
- android_exception_check ();
-}
-
\f
/* When calling the system's faccessat, make sure to clear the flag
extern void android_get_keysym_name (int, char *, size_t);
extern void android_wait_event (void);
extern void android_toggle_on_screen_keyboard (android_window, bool);
-extern void android_window_updated (android_window, unsigned long);
extern _Noreturn void android_restart_emacs (void);
extern int android_get_current_api_level (void);
android_clear_under_internal_border (f);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
-
- /* Now stash the serial of this configure event somewhere,
- and call android_window_updated with it once the redraw
- completes. */
- FRAME_OUTPUT_DATA (f)->last_configure_serial
- = configureEvent.xconfigure.serial;
}
- else
- /* Reply to this ConfigureNotify event immediately. */
- android_window_updated (FRAME_ANDROID_WINDOW (f),
- configureEvent.xconfigure.serial);
goto OTHER;
/* The frame is now complete, as its contents have been drawn. */
FRAME_ANDROID_COMPLETE_P (f) = true;
- /* If there was an outstanding configure event, then tell system
- that the update has finished and the new contents can now be
- displayed. */
- if (FRAME_OUTPUT_DATA (f)->last_configure_serial)
- android_window_updated (FRAME_ANDROID_WINDOW (f),
- FRAME_OUTPUT_DATA (f)->last_configure_serial);
- FRAME_OUTPUT_DATA (f)->last_configure_serial = 0;
-
/* Shrink the scanline buffer used by the font backend. */
sfntfont_android_shrink_scanline_buffer ();
unblock_input ();
/* List of all tools (either styluses or fingers) pressed onto the
frame. */
struct android_touch_point *touch_points;
-
- /* Event serial of the last ConfigureNotify event received that has
- not yet been drawn. This is used to synchronize resize with the
- window system. 0 if no such outstanding event exists. */
- unsigned long last_configure_serial;
};
enum