]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement mouse cursors on Android 7.0 and later
authorPo Lu <luangruo@yahoo.com>
Fri, 10 Mar 2023 07:16:05 +0000 (15:16 +0800)
committerPo Lu <luangruo@yahoo.com>
Fri, 10 Mar 2023 07:16:05 +0000 (15:16 +0800)
* 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
src/android.c
src/android.h
src/androidfns.c
src/androidgui.h
src/androidterm.c
src/androidterm.h

index 3569d93136b5db26bacf4c606183cda1ffe5ee29..6be609edcfe38cf8989f54ae392a02501cc13d88 100644 (file)
@@ -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);
+         }
+       });
+  }
 };
index 763e17e9430b01be4f36d43278c1ca8fa390b7b7..e39c34136de3d289a1f19760ec255546d8c10466 100644 (file)
@@ -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;
 }
 
+\f
+
+/* 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.  */
index 450f3859df961a18859a50c2f0a6df18be1b9315..03592bd955d6db1acbe6ea85b4447ee695a92e27 100644 (file)
@@ -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,
index 2724b9595c144874effa4bc35ef2d5c92f007848..589ae4331cbb6df6fe326ab869d0193d823bc589 100644 (file)
@@ -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);
 }
 
+\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];
+};
+
+\f
+
 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;
index 5858a16808036643f4db8af61a296915ecf18bf0..b918d03ceca2948f6753401a64debfb6a5b04f18 100644 (file)
@@ -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
 
 \f
index 2e2bf86706c85cd0ad4435c4188b5be3115468a3..3a0f1ccc463f994c9163bbfd39e6cfea508058c1 100644 (file)
@@ -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
index 9964eb54880f008e6eb15516ce5cd6b542df336f..2e59365b56dde31eceb6a6fab32843aa5b0be205 100644 (file)
@@ -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;