]> git.eshelyaron.com Git - emacs.git/commitdiff
Communicate frame titles to the window manager on Android
authorPo Lu <luangruo@yahoo.com>
Mon, 13 May 2024 06:40:15 +0000 (14:40 +0800)
committerEshel Yaron <me@eshelyaron.com>
Mon, 13 May 2024 08:39:00 +0000 (10:39 +0200)
* java/org/gnu/emacs/EmacsActivity.java (detachWindow)
(attachWindow): Call updateWmName.
(updateWmName): New function; transfer wm name from the window
attached to the task's description.

* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow)
<wmName>: New field.
(setWmName): New function.

* src/android.c (android_init_emacs_window): Link to new
function.
(android_set_wm_name): New function.

* src/android.h (struct android_emacs_service): Delete unused
entries.

* src/androidfns.c (android_set_name_internal, android_set_name)
(android_implicitly_set_name, android_explicitly_set_name)
(android_set_title): Port from X.

* src/androidterm.c (android_term_init): Compute default frame
title.

* src/androidterm.h (struct android_display_info) <x_id_name>:
New field.

(cherry picked from commit 9443f8145e1db86664a4af318b3bd1448094040e)

java/org/gnu/emacs/EmacsActivity.java
java/org/gnu/emacs/EmacsWindow.java
src/android.c
src/android.h
src/androidfns.c
src/androidterm.c
src/androidterm.h

index 118c3375ad57922029b9bd544aa8322d9dd675ed..7d02e4f4834c0d1cf20d4f42ec03703c2e6e437c 100644 (file)
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 
 import android.app.Activity;
+import android.app.ActivityManager.TaskDescription;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -166,6 +167,10 @@ public class EmacsActivity extends Activity
        layout.removeView (window.view);
        window = null;
 
+       /* Reset the WM name.  */
+       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+         updateWmName ();
+
        invalidateFocus (0);
       }
   }
@@ -205,6 +210,11 @@ public class EmacsActivity extends Activity
          invalidateFocus (1);
        }
       });
+
+    /* Synchronize the window's window manager name with this activity's
+       task in the recents list.  */
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+      updateWmName ();
   }
 
   @Override
@@ -522,6 +532,29 @@ public class EmacsActivity extends Activity
       }
   }
 
+  /* Update the name of this activity's task description from the
+     current window, or reset the same if no window is attached.  */
+
+  @SuppressWarnings ("deprecation")
+  public final void
+  updateWmName ()
+  {
+    String wmName;
+    TaskDescription description;
+
+    if (window == null || window.wmName == null)
+      wmName = "Emacs";
+    else
+      wmName = window.wmName;
+
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
+      description = new TaskDescription (wmName);
+    else
+      description = (new TaskDescription.Builder ()
+                    .setLabel (wmName).build ());
+    setTaskDescription (description);
+  }
+
   @Override
   public final void
   onAttachedToWindow ()
index aa1f3e9d96d63535b2b9dcb2494fb05dbed84491..d18212759dba63b5d0aa9dacd75ccaf558742d59 100644 (file)
@@ -169,6 +169,11 @@ public final class EmacsWindow extends EmacsHandleObject
      and whether this window has previously been attached to a task.  */
   public boolean preserve, previouslyAttached;
 
+  /* The window manager name of this window, which supplies the name of
+     activities in which it is displayed as a toplevel window, or
+     NULL.  */
+  public String wmName;
+
   public
   EmacsWindow (final EmacsWindow parent, int x, int y,
               int width, int height, boolean overrideRedirect)
@@ -1562,6 +1567,36 @@ public final class EmacsWindow extends EmacsHandleObject
     return dontFocusOnMap;
   }
 
+  public void
+  setWmName (final String wmName)
+  {
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
+      return;
+
+    EmacsService.SERVICE.runOnUiThread (new Runnable () {
+       @Override
+       public void
+       run ()
+       {
+         EmacsActivity activity;
+         Object tem;
+
+         EmacsWindow.this.wmName = wmName;
+
+         /* If an activity is already attached, replace its task
+            description.  */
+
+         tem = getAttachedConsumer ();
+
+         if (tem != null && tem instanceof EmacsActivity)
+           {
+             activity = (EmacsActivity) tem;
+             activity.updateWmName ();
+           }
+       }
+      });
+  }
+
   public int[]
   translateCoordinates (int x, int y)
   {
@@ -1631,7 +1666,7 @@ public final class EmacsWindow extends EmacsHandleObject
          fullscreen = isFullscreen;
          tem = getAttachedConsumer ();
 
-         if (tem != null)
+         if (tem != null && tem instanceof EmacsActivity)
            {
              activity = (EmacsActivity) tem;
              activity.syncFullscreenWith (EmacsWindow.this);
index 72ef9e689efc14b11903831e3daa5bc8f43f9fbc..17b5d6d411590bcc9064689de10d46033b5eb8c6 100644 (file)
@@ -115,6 +115,7 @@ struct android_emacs_window
   jmethodID recreate_activity;
   jmethodID clear_window;
   jmethodID clear_area;
+  jmethodID set_wm_name;
 };
 
 struct android_emacs_cursor
@@ -1842,6 +1843,7 @@ android_init_emacs_window (void)
   FIND_METHOD (recreate_activity, "recreateActivity", "()V");
   FIND_METHOD (clear_window, "clearWindow", "()V");
   FIND_METHOD (clear_area, "clearArea", "(IIII)V");
+  FIND_METHOD (set_wm_name, "setWmName", "(Ljava/lang/String;)V");
 #undef FIND_METHOD
 }
 
@@ -5603,6 +5605,27 @@ android_set_dont_accept_focus (android_window handle,
   android_exception_check ();
 }
 
+/* Set the WM name of HANDLE to STRING, a Java string.  This name
+   provides the task description of activities that receive HANDLE.  */
+
+void
+android_set_wm_name (android_window handle, jstring name)
+{
+  jmethodID method;
+  jobject window;
+
+  window = android_resolve_handle (handle);
+  method = window_class.set_wm_name;
+
+  if (android_get_current_api_level () < 21)
+    return;
+
+  (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, window,
+                                                window_class.class, method,
+                                                name);
+  android_exception_check ();
+}
+
 void
 android_get_keysym_name (int keysym, char *name_return, size_t size)
 {
index a582a9b7dff9665566e13f4a6036ddfd4f6452e7..78482d64de41b428561dba2a568f37bd2e1fe713 100644 (file)
@@ -118,6 +118,7 @@ extern bool android_detect_keyboard (void);
 
 extern void android_set_dont_focus_on_map (android_window, bool);
 extern void android_set_dont_accept_focus (android_window, bool);
+extern void android_set_wm_name (android_window, jstring);
 
 extern int android_verify_jni_string (const char *);
 extern jstring android_build_string (Lisp_Object, ...);
@@ -275,8 +276,6 @@ struct android_emacs_service
   jmethodID draw_rectangle;
   jmethodID draw_line;
   jmethodID draw_point;
-  jmethodID clear_window;
-  jmethodID clear_area;
   jmethodID ring_bell;
   jmethodID query_tree;
   jmethodID get_screen_width;
index df425e5779e358d397af3cc82d154364f4acca2c..1c2690394a67c2caf84f9b400bd909be868857ec 100644 (file)
@@ -211,18 +211,90 @@ android_set_parent_frame (struct frame *f, Lisp_Object new_value,
   FRAME_TERMINAL (f)->fullscreen_hook (f);
 }
 
+/* Set the WM name to NAME for frame F. Also set the icon name.
+   If the frame already has an icon name, use that, otherwise set the
+   icon name to NAME.  */
+
+static void
+android_set_name_internal (struct frame *f, Lisp_Object name)
+{
+  jstring java_name;
+
+  if (FRAME_ANDROID_WINDOW (f))
+    {
+      java_name = android_build_string (name, NULL);
+      android_set_wm_name (FRAME_ANDROID_WINDOW (f), java_name);
+      ANDROID_DELETE_LOCAL_REF (java_name);
+    }
+}
+
+/* Change the name of frame F to NAME.  If NAME is nil, set F's name to
+       x_id_name.
+
+   If EXPLICIT is true, that indicates that lisp code is setting the
+       name; if NAME is a string, set F's name to NAME and set
+       F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
+
+   If EXPLICIT is false, that indicates that Emacs redisplay code is
+       suggesting a new name, which lisp code should override; if
+       F->explicit_name is set, ignore the new name; otherwise, set it.  */
+
+static void
+android_set_name (struct frame *f, Lisp_Object name, bool explicit)
+{
+  /* Make sure that requests from lisp code override requests from
+     Emacs redisplay code.  */
+  if (explicit)
+    {
+      /* If we're switching from explicit to implicit, we had better
+        update the mode lines and thereby update the title.  */
+      if (f->explicit_name && NILP (name))
+       update_mode_lines = 37;
+
+      f->explicit_name = ! NILP (name);
+    }
+  else if (f->explicit_name)
+    return;
+
+  /* If NAME is nil, set the name to the x_id_name.  */
+  if (NILP (name))
+    {
+      /* Check for no change needed in this very common case
+        before we do any consing.  */
+      if (!strcmp (FRAME_DISPLAY_INFO (f)->x_id_name,
+                  SSDATA (f->name)))
+       return;
+      name = build_string (FRAME_DISPLAY_INFO (f)->x_id_name);
+    }
+  else
+    CHECK_STRING (name);
+
+  /* Don't change the name if it's already NAME.  */
+  if (! NILP (Fstring_equal (name, f->name)))
+    return;
+
+  fset_name (f, name);
+
+  /* For setting the frame title, the title parameter should override
+     the name parameter.  */
+  if (! NILP (f->title))
+    name = f->title;
+
+  android_set_name_internal (f, name);
+}
+
 void
 android_implicitly_set_name (struct frame *f, Lisp_Object arg,
                             Lisp_Object oldval)
 {
-
+  android_set_name (f, arg, false);
 }
 
 void
 android_explicitly_set_name (struct frame *f, Lisp_Object arg,
                             Lisp_Object oldval)
 {
-
+  android_set_name (f, arg, true);
 }
 
 /* Set the number of lines used for the tool bar of frame F to VALUE.
@@ -2988,6 +3060,8 @@ android_set_title (struct frame *f, Lisp_Object name,
     name = f->name;
   else
     CHECK_STRING (name);
+
+  android_set_name_internal (f, name);
 }
 
 static void
index 67c20ec5245505bccaf5e7da5e0a7e03e19b8e0a..94a115a66a609a020d37d78eaf77e2e0af8c3f5e 100644 (file)
@@ -6649,6 +6649,26 @@ android_term_init (void)
 
   terminal->name = xstrdup ("android");
 
+  {
+    Lisp_Object system_name = Fsystem_name ();
+    static char const title[] = "GNU Emacs";
+    if (STRINGP (system_name))
+      {
+       static char const at[] = " at ";
+       ptrdiff_t nbytes = sizeof (title) + sizeof (at);
+       if (ckd_add (&nbytes, nbytes, SBYTES (system_name)))
+         memory_full (SIZE_MAX);
+       dpyinfo->x_id_name = xmalloc (nbytes);
+       sprintf (dpyinfo->x_id_name, "%s%s%s", title, at,
+                SDATA (system_name));
+      }
+    else
+      {
+       dpyinfo->x_id_name = xmalloc (sizeof (title));
+       strcpy (dpyinfo->x_id_name, title);
+      }
+  }
+
   /* The display "connection" is now set up, and it must never go
      away.  */
   terminal->reference_count = 30000;
index f4459c45dc9e842da0b6fd51b122705c14980f09..c8f1ab655a94db2ca50668d2169b368000db28fd 100644 (file)
@@ -90,6 +90,9 @@ struct android_display_info
   /* Minimum font height over all fonts in font_table.  */
   int smallest_font_height;
 
+  /* Default name for all frames on this display.  */
+  char *x_id_name;
+
   /* The number of fonts opened for this display.  */
   int n_fonts;