[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android ae5513ede52 1/2: Implement mouse cursors on Android 7.0
From: |
Po Lu |
Subject: |
feature/android ae5513ede52 1/2: Implement mouse cursors on Android 7.0 and later |
Date: |
Fri, 10 Mar 2023 02:18:10 -0500 (EST) |
branch: feature/android
commit ae5513ede52536df2cd823699d6168985915ce0f
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Implement mouse cursors on Android 7.0 and later
* java/org/gnu/emacs/EmacsWindow.java (defineCursor): New
function.
* src/android.c (struct android_emacs_cursor): New struct.
(android_init_emacs_cursor): New function.
(JNICALL): Call it.
(android_create_font_cursor, android_define_cursor)
(android_free_cursor): New functions.
* src/android.h (enum android_handle_type): Add cursor handle
type.
* src/androidfns.c (Fx_create_frame, android_create_tip_frame)
(enum mouse_cursor, struct mouse_cursor_types, mouse_cursor_types)
(struct mouse_cursor_data, android_set_mouse_color)
(syms_of_androidfns):
* src/androidgui.h (enum android_cursor_shape):
* src/androidterm.c (make_invisible_cursor)
(android_toggle_invisible_pointer, android_free_frame_resources)
(android_define_frame_cursor):
* src/androidterm.h (struct android_display_info)
(struct android_output): Port mouse cursor code over from X.
---
java/org/gnu/emacs/EmacsWindow.java | 16 +++
src/android.c | 118 +++++++++++++++++++
src/android.h | 1 +
src/androidfns.c | 221 +++++++++++++++++++++++++++++++++++-
src/androidgui.h | 28 ++++-
src/androidterm.c | 68 ++++++++++-
src/androidterm.h | 6 +-
7 files changed, 448 insertions(+), 10 deletions(-)
diff --git a/java/org/gnu/emacs/EmacsWindow.java
b/java/org/gnu/emacs/EmacsWindow.java
index 3569d93136b..6be609edcfe 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -1222,4 +1222,20 @@ public final class EmacsWindow extends EmacsHandleObject
}
});
}
+
+ public void
+ defineCursor (final EmacsCursor cursor)
+ {
+ /* Don't post this message if pointer icons aren't supported. */
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+ view.post (new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ view.setPointerIcon (cursor.icon);
+ }
+ });
+ }
};
diff --git a/src/android.c b/src/android.c
index 763e17e9430..e39c34136de 100644
--- a/src/android.c
+++ b/src/android.c
@@ -155,6 +155,13 @@ struct android_emacs_window
jmethodID translate_coordinates;
jmethodID set_dont_accept_focus;
jmethodID set_dont_focus_on_map;
+ jmethodID define_cursor;
+};
+
+struct android_emacs_cursor
+{
+ jclass class;
+ jmethodID constructor;
};
/* The API level of the current device. */
@@ -234,6 +241,9 @@ static struct android_emacs_drawable drawable_class;
/* Various methods associated with the EmacsWindow class. */
static struct android_emacs_window window_class;
+/* Various methods associated with the EmacsCursor class. */
+static struct android_emacs_cursor cursor_class;
+
/* The last event serial used. This is a 32 bit value, but it is
stored in unsigned long to be consistent with X. */
unsigned int event_serial;
@@ -2288,6 +2298,38 @@ android_init_emacs_window (void)
"(II)[I");
FIND_METHOD (set_dont_focus_on_map, "setDontFocusOnMap", "(Z)V");
FIND_METHOD (set_dont_accept_focus, "setDontAcceptFocus", "(Z)V");
+ FIND_METHOD (define_cursor, "defineCursor",
+ "(Lorg/gnu/emacs/EmacsCursor;)V");
+#undef FIND_METHOD
+}
+
+static void
+android_init_emacs_cursor (void)
+{
+ jclass old;
+
+ cursor_class.class
+ = (*android_java_env)->FindClass (android_java_env,
+ "org/gnu/emacs/EmacsCursor");
+ eassert (cursor_class.class);
+
+ old = cursor_class.class;
+ cursor_class.class
+ = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
+ (jobject) old);
+ ANDROID_DELETE_LOCAL_REF (old);
+
+ if (!cursor_class.class)
+ emacs_abort ();
+
+#define FIND_METHOD(c_name, name, signature) \
+ cursor_class.c_name \
+ = (*android_java_env)->GetMethodID (android_java_env, \
+ cursor_class.class, \
+ name, signature); \
+ assert (cursor_class.c_name);
+
+ FIND_METHOD (constructor, "<init>", "(SI)V");
#undef FIND_METHOD
}
@@ -2339,6 +2381,7 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object,
jarray argv,
android_init_graphics_point ();
android_init_emacs_drawable ();
android_init_emacs_window ();
+ android_init_emacs_cursor ();
/* Set HOME to the app data directory. */
setenv ("HOME", android_files_dir, 1);
@@ -6243,6 +6286,81 @@ android_asset_fstat (struct android_fd_or_asset asset,
return 0;
}
+
+
+/* Window cursor support. */
+
+android_cursor
+android_create_font_cursor (enum android_cursor_shape shape)
+{
+ android_cursor id;
+ short prev_max_handle;
+ jobject object;
+
+ /* First, allocate the cursor handle. */
+ prev_max_handle = max_handle;
+ id = android_alloc_id ();
+
+ if (!id)
+ error ("Out of cursor handles!");
+
+ /* Next, create the cursor. */
+ object = (*android_java_env)->NewObject (android_java_env,
+ cursor_class.class,
+ cursor_class.constructor,
+ (jshort) id,
+ (jint) shape);
+ if (!object)
+ {
+ (*android_java_env)->ExceptionClear (android_java_env);
+ max_handle = prev_max_handle;
+ memory_full (0);
+ }
+
+ android_handles[id].type = ANDROID_HANDLE_CURSOR;
+ android_handles[id].handle
+ = (*android_java_env)->NewGlobalRef (android_java_env, object);
+ (*android_java_env)->ExceptionClear (android_java_env);
+ ANDROID_DELETE_LOCAL_REF (object);
+
+ if (!android_handles[id].handle)
+ memory_full (0);
+
+ return id;
+}
+
+void
+android_define_cursor (android_window window, android_cursor cursor)
+{
+ jobject window1, cursor1;
+ jmethodID method;
+
+ window1 = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+ cursor1 = (cursor
+ ? android_resolve_handle (cursor, ANDROID_HANDLE_CURSOR)
+ : NULL);
+ method = window_class.define_cursor;
+
+ (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
+ window1,
+ window_class.class,
+ method, cursor1);
+ android_exception_check ();
+}
+
+void
+android_free_cursor (android_cursor cursor)
+{
+ if (android_handles[cursor].type != ANDROID_HANDLE_CURSOR)
+ {
+ __android_log_print (ANDROID_LOG_ERROR, __func__,
+ "Trying to destroy something not a CURSOR!");
+ emacs_abort ();
+ }
+
+ android_destroy_handle (cursor);
+}
+
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */
diff --git a/src/android.h b/src/android.h
index 450f3859df9..03592bd955d 100644
--- a/src/android.h
+++ b/src/android.h
@@ -63,6 +63,7 @@ enum android_handle_type
ANDROID_HANDLE_WINDOW,
ANDROID_HANDLE_GCONTEXT,
ANDROID_HANDLE_PIXMAP,
+ ANDROID_HANDLE_CURSOR,
};
extern jobject android_resolve_handle (android_handle,
diff --git a/src/androidfns.c b/src/androidfns.c
index 2724b9595c1..589ae4331cb 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -802,6 +802,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
FRAME_BACKGROUND_PIXEL (f) = -1;
f->output_data.android->cursor_pixel = -1;
f->output_data.android->cursor_foreground_pixel = -1;
+ f->output_data.android->mouse_pixel = -1;
black = build_string ("black");
FRAME_FOREGROUND_PIXEL (f)
@@ -812,6 +813,8 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
f->output_data.android->cursor_foreground_pixel
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+ f->output_data.android->mouse_pixel
+ = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
}
/* Set the name; the functions to which we pass f expect the name to
@@ -1798,6 +1801,7 @@ android_create_tip_frame (struct android_display_info
*dpyinfo,
FRAME_BACKGROUND_PIXEL (f) = -1;
f->output_data.android->cursor_pixel = -1;
f->output_data.android->cursor_foreground_pixel = -1;
+ f->output_data.android->mouse_pixel = -1;
black = build_string ("black");
FRAME_FOREGROUND_PIXEL (f)
@@ -1808,6 +1812,8 @@ android_create_tip_frame (struct android_display_info
*dpyinfo,
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
f->output_data.android->cursor_foreground_pixel
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+ f->output_data.android->mouse_pixel
+ = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
}
/* Set the name; the functions to which we pass f expect the name to
@@ -2632,13 +2638,147 @@ android_set_menu_bar_lines (struct frame *f,
Lisp_Object value,
adjust_frame_glyphs (f);
}
+
+
+/* These enums must stay in sync with the mouse_cursor_types array
+ below! */
+
+enum mouse_cursor
+ {
+ mouse_cursor_text,
+ mouse_cursor_nontext,
+ mouse_cursor_hourglass,
+ mouse_cursor_mode,
+ mouse_cursor_hand,
+ mouse_cursor_horizontal_drag,
+ mouse_cursor_vertical_drag,
+ mouse_cursor_left_edge,
+ mouse_cursor_top_left_corner,
+ mouse_cursor_top_edge,
+ mouse_cursor_top_right_corner,
+ mouse_cursor_right_edge,
+ mouse_cursor_bottom_right_corner,
+ mouse_cursor_bottom_edge,
+ mouse_cursor_bottom_left_corner,
+ mouse_cursor_max
+ };
+
+struct mouse_cursor_types
+{
+ /* Printable name for error messages (optional). */
+ const char *name;
+
+ /* Lisp variable controlling the cursor shape. */
+ /* FIXME: A couple of these variables are defined in the C code but
+ are not actually accessible from Lisp. They should probably be
+ made accessible or removed. */
+ Lisp_Object *shape_var_ptr;
+
+ /* The default shape. */
+ int default_shape;
+};
+
+/* This array must stay in sync with enum mouse_cursor above! */
+
+static const struct mouse_cursor_types mouse_cursor_types[] =
+ {
+ {"text", &Vx_pointer_shape, ANDROID_XC_XTERM, },
+ {"nontext", &Vx_nontext_pointer_shape, ANDROID_XC_LEFT_PTR, },
+ {"hourglass", &Vx_hourglass_pointer_shape, ANDROID_XC_WATCH, },
+ {"modeline", &Vx_mode_pointer_shape, ANDROID_XC_XTERM, },
+ {NULL, &Vx_sensitive_text_pointer_shape, ANDROID_XC_HAND2, },
+ {NULL, &Vx_window_horizontal_drag_shape, ANDROID_XC_SB_H_DOUBLE_ARROW, },
+ {NULL, &Vx_window_vertical_drag_shape, ANDROID_XC_SB_V_DOUBLE_ARROW, },
+ {NULL, &Vx_window_left_edge_shape, ANDROID_XC_LEFT_SIDE, },
+ {NULL, &Vx_window_top_left_corner_shape, ANDROID_XC_TOP_LEFT_CORNER, },
+ {NULL, &Vx_window_top_edge_shape, ANDROID_XC_TOP_SIDE, },
+ {NULL, &Vx_window_top_right_corner_shape, ANDROID_XC_TOP_RIGHT_CORNER, },
+ {NULL, &Vx_window_right_edge_shape, ANDROID_XC_RIGHT_SIDE, },
+ {NULL, &Vx_window_bottom_right_corner_shape,
+ ANDROID_XC_BOTTOM_RIGHT_CORNER, },
+ {NULL, &Vx_window_bottom_edge_shape, ANDROID_XC_BOTTOM_SIDE, },
+ {NULL, &Vx_window_bottom_left_corner_shape,
+ ANDROID_XC_BOTTOM_LEFT_CORNER, },
+ };
+
+struct mouse_cursor_data
+{
+ /* Cursor numbers chosen. */
+ unsigned int cursor_num[mouse_cursor_max];
+
+ /* Allocated Cursor values, or zero for failed attempts. */
+ android_cursor cursor[mouse_cursor_max];
+};
+
+
+
static void
android_set_mouse_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
- /* Changing the mouse color is unsupported under Android, so this is
- left intact. */
- android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+ struct android_output *x = f->output_data.android;
+ struct mouse_cursor_data cursor_data = { -1, -1 };
+ unsigned long pixel = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+ unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
+ int i;
+
+ /* Don't let pointers be invisible. */
+ if (mask_color == pixel)
+ pixel = FRAME_FOREGROUND_PIXEL (f);
+
+ x->mouse_pixel = pixel;
+
+ for (i = 0; i < mouse_cursor_max; i++)
+ {
+ Lisp_Object shape_var = *mouse_cursor_types[i].shape_var_ptr;
+ cursor_data.cursor_num[i]
+ = (!NILP (shape_var)
+ ? check_uinteger_max (shape_var, UINT_MAX)
+ : mouse_cursor_types[i].default_shape);
+ }
+
+ block_input ();
+
+ for (i = 0; i < mouse_cursor_max; i++)
+ cursor_data.cursor[i]
+ = android_create_font_cursor (cursor_data.cursor_num[i]);
+
+ if (FRAME_ANDROID_WINDOW (f))
+ {
+ f->output_data.android->current_cursor
+ = cursor_data.cursor[mouse_cursor_text];
+ android_define_cursor (FRAME_ANDROID_WINDOW (f),
+ f->output_data.android->current_cursor);
+ }
+
+#define INSTALL_CURSOR(FIELD, SHORT_INDEX) \
+ eassert (x->FIELD \
+ != cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX]); \
+ if (x->FIELD != 0) \
+ android_free_cursor (x->FIELD); \
+ x->FIELD = cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX];
+
+ INSTALL_CURSOR (text_cursor, text);
+ INSTALL_CURSOR (nontext_cursor, nontext);
+ INSTALL_CURSOR (hourglass_cursor, hourglass);
+ INSTALL_CURSOR (modeline_cursor, mode);
+ INSTALL_CURSOR (hand_cursor, hand);
+ INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag);
+ INSTALL_CURSOR (vertical_drag_cursor, vertical_drag);
+ INSTALL_CURSOR (left_edge_cursor, left_edge);
+ INSTALL_CURSOR (top_left_corner_cursor, top_left_corner);
+ INSTALL_CURSOR (top_edge_cursor, top_edge);
+ INSTALL_CURSOR (top_right_corner_cursor, top_right_corner);
+ INSTALL_CURSOR (right_edge_cursor, right_edge);
+ INSTALL_CURSOR (bottom_right_corner_cursor, bottom_right_corner);
+ INSTALL_CURSOR (bottom_edge_cursor, bottom_edge);
+ INSTALL_CURSOR (bottom_left_corner_cursor, bottom_left_corner);
+
+#undef INSTALL_CURSOR
+
+ unblock_input ();
+
+ update_face_from_frame_parameter (f, Qmouse_color, arg);
}
static void
@@ -2845,6 +2985,81 @@ syms_of_androidfns (void)
DEFSYM (Qtrue_color, "true-color");
DEFSYM (Qalways, "always");
+ DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_pointer_shape = Qnil;
+
+#if false /* This doesn't really do anything. */
+ DEFVAR_LISP ("x-nontext-pointer-shape", Vx_nontext_pointer_shape,
+ doc: /* SKIP: real doc in xfns.c. */);
+#endif
+ Vx_nontext_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-hourglass-pointer-shape", Vx_hourglass_pointer_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_hourglass_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-sensitive-text-pointer-shape",
+ Vx_sensitive_text_pointer_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_sensitive_text_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-horizontal-drag-cursor",
+ Vx_window_horizontal_drag_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_horizontal_drag_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-vertical-drag-cursor",
+ Vx_window_vertical_drag_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_vertical_drag_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-left-edge-cursor",
+ Vx_window_left_edge_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_left_edge_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-top-left-corner-cursor",
+ Vx_window_top_left_corner_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_top_left_corner_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-top-edge-cursor",
+ Vx_window_top_edge_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_top_edge_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-top-right-corner-cursor",
+ Vx_window_top_right_corner_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_top_right_corner_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-right-edge-cursor",
+ Vx_window_right_edge_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_right_edge_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-bottom-right-corner-cursor",
+ Vx_window_bottom_right_corner_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_bottom_right_corner_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-bottom-edge-cursor",
+ Vx_window_bottom_edge_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_bottom_edge_shape = Qnil;
+
+#if false /* This doesn't really do anything. */
+ DEFVAR_LISP ("x-mode-pointer-shape", Vx_mode_pointer_shape,
+ doc: /* SKIP: real doc in xfns.c. */);
+#endif
+ Vx_mode_pointer_shape = Qnil;
+
+ DEFVAR_LISP ("x-window-bottom-left-corner-cursor",
+ Vx_window_bottom_left_corner_shape,
+ doc: /* SKIP: real text in xfns.c. */);
+ Vx_window_bottom_left_corner_shape = Qnil;
+
DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel,
doc: /* SKIP: real doc in xfns.c. */);
Vx_cursor_fore_pixel = Qnil;
diff --git a/src/androidgui.h b/src/androidgui.h
index 5858a168080..b918d03ceca 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -36,6 +36,7 @@ typedef android_handle android_pixmap, Emacs_Pixmap;
typedef android_handle android_window, Emacs_Window;
typedef android_handle android_gcontext, GContext;
typedef android_handle android_drawable, Drawable;
+typedef android_handle android_cursor, Emacs_Cursor;
typedef unsigned int android_time;
@@ -162,10 +163,6 @@ struct android_swap_info
enum android_swap_action swap_action;
};
-/* Android doesn't support cursors, so define this to something
- unused. */
-typedef char Emacs_Cursor;
-
#define NativeRectangle Emacs_Rectangle
#define CONVERT_TO_NATIVE_RECT(xr, nr) ((xr) = (nr))
#define CONVERT_FROM_EMACS_RECT(xr, nr) ((nr) = (xr))
@@ -620,6 +617,29 @@ extern void android_update_extracted_text (android_window,
void *,
int);
extern int android_set_fullscreen (android_window, bool);
+enum android_cursor_shape
+ {
+ ANDROID_XC_XTERM = 1008,
+ ANDROID_XC_LEFT_PTR = 1000,
+ ANDROID_XC_WATCH = 1004,
+ ANDROID_XC_HAND2 = 1002,
+ ANDROID_XC_SB_H_DOUBLE_ARROW = 1014,
+ ANDROID_XC_SB_V_DOUBLE_ARROW = 1015,
+ ANDROID_XC_LEFT_SIDE = 1020,
+ ANDROID_XC_TOP_LEFT_CORNER = 1020,
+ ANDROID_XC_TOP_SIDE = 1020,
+ ANDROID_XC_TOP_RIGHT_CORNER = 1020,
+ ANDROID_XC_RIGHT_SIDE = 1020,
+ ANDROID_XC_BOTTOM_RIGHT_CORNER = 1020,
+ ANDROID_XC_BOTTOM_SIDE = 1020,
+ ANDROID_XC_BOTTOM_LEFT_CORNER = 1020,
+ ANDROID_XC_NULL = 0,
+ };
+
+extern android_cursor android_create_font_cursor (enum android_cursor_shape);
+extern void android_define_cursor (android_window, android_cursor);
+extern void android_free_cursor (android_cursor);
+
#endif
diff --git a/src/androidterm.c b/src/androidterm.c
index 2e2bf86706c..3a0f1ccc463 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -224,10 +224,38 @@ android_ring_bell (struct frame *f)
}
}
+static android_cursor
+make_invisible_cursor (struct android_display_info *dpyinfo)
+{
+ return android_create_font_cursor (ANDROID_XC_NULL);
+}
+
static void
-android_toggle_invisible_pointer (struct frame *f, bool invisible)
+android_toggle_visible_pointer (struct frame *f, bool invisible)
{
+ struct android_display_info *dpyinfo;
+
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ if (!dpyinfo->invisible_cursor)
+ dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
+
+ if (invisible)
+ android_define_cursor (FRAME_ANDROID_WINDOW (f),
+ dpyinfo->invisible_cursor);
+ else
+ android_define_cursor (FRAME_ANDROID_WINDOW (f),
+ f->output_data.android->current_cursor);
+ f->pointer_invisible = invisible;
+}
+
+static void
+android_toggle_invisible_pointer (struct frame *f, bool invisible)
+{
+ block_input ();
+ android_toggle_visible_pointer (f, invisible);
+ unblock_input ();
}
/* Start an update of frame F. This function is installed as a hook
@@ -2040,6 +2068,38 @@ android_free_frame_resources (struct frame *f)
android_free_gcs (f);
+ /* Free cursors. */
+ if (f->output_data.android->text_cursor)
+ android_free_cursor (f->output_data.android->text_cursor);
+ if (f->output_data.android->nontext_cursor)
+ android_free_cursor (f->output_data.android->nontext_cursor);
+ if (f->output_data.android->modeline_cursor)
+ android_free_cursor (f->output_data.android->modeline_cursor);
+ if (f->output_data.android->hand_cursor)
+ android_free_cursor (f->output_data.android->hand_cursor);
+ if (f->output_data.android->hourglass_cursor)
+ android_free_cursor (f->output_data.android->hourglass_cursor);
+ if (f->output_data.android->horizontal_drag_cursor)
+ android_free_cursor (f->output_data.android->horizontal_drag_cursor);
+ if (f->output_data.android->vertical_drag_cursor)
+ android_free_cursor (f->output_data.android->vertical_drag_cursor);
+ if (f->output_data.android->left_edge_cursor)
+ android_free_cursor (f->output_data.android->left_edge_cursor);
+ if (f->output_data.android->top_left_corner_cursor)
+ android_free_cursor (f->output_data.android->top_left_corner_cursor);
+ if (f->output_data.android->top_edge_cursor)
+ android_free_cursor (f->output_data.android->top_edge_cursor);
+ if (f->output_data.android->top_right_corner_cursor)
+ android_free_cursor (f->output_data.android->top_right_corner_cursor);
+ if (f->output_data.android->right_edge_cursor)
+ android_free_cursor (f->output_data.android->right_edge_cursor);
+ if (f->output_data.android->bottom_right_corner_cursor)
+ android_free_cursor (f->output_data.android->bottom_right_corner_cursor);
+ if (f->output_data.android->bottom_edge_cursor)
+ android_free_cursor (f->output_data.android->bottom_edge_cursor);
+ if (f->output_data.android->bottom_left_corner_cursor)
+ android_free_cursor (f->output_data.android->bottom_left_corner_cursor);
+
/* Free extra GCs allocated by android_setup_relief_colors. */
if (f->output_data.android->white_relief.gc)
{
@@ -3971,7 +4031,11 @@ android_draw_glyph_string (struct glyph_string *s)
static void
android_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
{
- /* Not supported, because cursors are not supported on Android. */
+ if (!f->pointer_invisible
+ && f->output_data.android->current_cursor != cursor)
+ android_define_cursor (FRAME_ANDROID_WINDOW (f), cursor);
+
+ f->output_data.android->current_cursor = cursor;
}
static void
diff --git a/src/androidterm.h b/src/androidterm.h
index 9964eb54880..2e59365b56d 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -136,6 +136,9 @@ struct android_display_info
/* ID of the last menu event received. -1 means Emacs is waiting
for a context menu event. */
int menu_event_id;
+
+ /* The invisible cursor used for pointer blanking. */
+ android_cursor invisible_cursor;
};
/* Structure representing a single tool (finger or stylus) pressed
@@ -176,6 +179,7 @@ struct android_output
/* Various colors. */
unsigned long cursor_pixel;
+ unsigned long mouse_pixel;
unsigned long cursor_foreground_pixel;
/* Foreground color for scroll bars. A value of -1 means use the
@@ -187,7 +191,7 @@ struct android_output
bars). */
unsigned long scroll_bar_background_pixel;
- /* Unused stuff (cursors). */
+ /* Cursors associated with this frame. */
Emacs_Cursor text_cursor;
Emacs_Cursor nontext_cursor;
Emacs_Cursor modeline_cursor;