emacs-diffs
[Top][All Lists]
Advanced

[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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]