Communicate frame titles to the window manager on Android
* 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.
This commit is contained in:
parent
f560e75933
commit
9443f8145e
7 changed files with 192 additions and 5 deletions
|
@ -27,6 +27,7 @@
|
|||
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 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
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 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
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 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 ()
|
||||
|
|
|
@ -169,6 +169,11 @@ private static class Coordinate
|
|||
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 @@ else if (EmacsWindow.this.isMapped)
|
|||
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 @@ else if (EmacsWindow.this.isMapped)
|
|||
fullscreen = isFullscreen;
|
||||
tem = getAttachedConsumer ();
|
||||
|
||||
if (tem != null)
|
||||
if (tem != null && tem instanceof EmacsActivity)
|
||||
{
|
||||
activity = (EmacsActivity) tem;
|
||||
activity.syncFullscreenWith (EmacsWindow.this);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue