mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-05 22:20:24 -08:00
Support `toolkit-theme-set-functions' on Android and execute hooks safely
* java/org/gnu/emacs/EmacsNative.java (setEmacsParams): New arg UIMODE. (sendConfigurationChanged): New args DETAIL and UI_MODE. * java/org/gnu/emacs/EmacsNoninteractive.java (main1): Provide an undefined UI mode. * java/org/gnu/emacs/EmacsService.java (EmacsService): New field uiMode. (onCreate): Initialize this field at start-up and provide the same to setEmacsParams. (onConfigurationChanged): If the UI mode has been altered, generate a configuration changed event to match. * src/android.c (android_ui_mode): New variable. (setEmacsParams): New argument UI_MODE. Initialize the same from this variable. * src/androidgui.h (enum android_configuration_changed): New enum. (struct android_configuration_changed_event): New field `DETAIL'. Convert fields providing specifics into a union of display density information and a UI mode integer. * src/androidterm.c (handle_one_android_event): Handle both manners of configuration change events. (android_term_init): Initialize Vtoolkit_theme from UI mode provided at start-up. * src/frame.c (syms_of_frame): Always define Vtoolkit_theme. Define Qtoolkit_theme_set_functions. * src/gtkutil.c (xg_update_dark_mode_for_all_displays): * src/w32term.c (w32_read_socket): Generate special toolkit theme events, rather than executing hooks directly within the read_socket callback. * src/keyboard.c (kbd_buffer_get_event) <TOOLKIT_THEME_CHANGED_EVENT>: Run Qtoolkit_theme_set_functions and set Vtoolkit_theme from event->ie.arg. * src/termhooks.h (enum event_kind): New event TOOLKIT_THEME_CHANGED_EVENT.
This commit is contained in:
parent
435c3948a4
commit
7550791287
13 changed files with 132 additions and 52 deletions
4
etc/NEWS
4
etc/NEWS
|
|
@ -3573,10 +3573,10 @@ automatically toggling between them.
|
|||
|
||||
---
|
||||
*** 'toolkit-theme-set-functions' called when the toolkit theme is set for Emacs.
|
||||
When the theme is set on PGTK or MS-Windows builds,
|
||||
When the theme is set on PGTK, Android, or MS-Windows systems,
|
||||
'toolkit-theme-set-functions' is called. The result is stored in the
|
||||
variable 'toolkit-theme' as either symbol 'dark' or 'light', but may be
|
||||
expanded to future toolkit-specific symbols in the future.
|
||||
extended to encompass other toolkit-specific symbols in the future.
|
||||
|
||||
|
||||
* Changes in Emacs 31.1 on Non-Free Operating Systems
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ public final class EmacsNative
|
|||
scaledDensity is the DPI value used to translate point sizes to
|
||||
pixel sizes when loading fonts.
|
||||
|
||||
uiMode holds the bits of the system's UI mode specification
|
||||
defining the active system theme.
|
||||
|
||||
classPath must be the classpath of this app_process process, or
|
||||
NULL.
|
||||
|
||||
|
|
@ -74,6 +77,7 @@ public final class EmacsNative
|
|||
float pixelDensityX,
|
||||
float pixelDensityY,
|
||||
float scaledDensity,
|
||||
int uiMode,
|
||||
String classPath,
|
||||
EmacsService emacsService,
|
||||
int apiLevel);
|
||||
|
|
@ -197,8 +201,9 @@ public final class EmacsNative
|
|||
public static native void sendNotificationAction (String tag, String action);
|
||||
|
||||
/* Send an ANDROID_CONFIGURATION_CHANGED event. */
|
||||
public static native void sendConfigurationChanged (float dpiX, float dpiY,
|
||||
float dpiScaled);
|
||||
public static native void sendConfigurationChanged (int detail, float dpiX,
|
||||
float dpiY, float dpiScaled,
|
||||
int ui_mode);
|
||||
|
||||
/* Return the file name associated with the specified file
|
||||
descriptor, or NULL if there is none. */
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public final class EmacsNoninteractive
|
|||
cacheDir = context.getCacheDir ().getCanonicalPath ();
|
||||
EmacsNative.setEmacsParams (assets, filesDir,
|
||||
libDir, cacheDir, 0.0f,
|
||||
0.0f, 0.0f, null, null,
|
||||
0.0f, 0.0f, 0x0, null, null,
|
||||
Build.VERSION.SDK_INT);
|
||||
|
||||
/* Now find the dump file that Emacs should use, if it has already
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ public final class EmacsService extends Service
|
|||
consulted for font scaling. */
|
||||
private double dpiX, dpiY, dpiScaled;
|
||||
|
||||
/* The display's previously observed UI mode as it relates to the
|
||||
system theme. */
|
||||
private int uiMode;
|
||||
|
||||
static
|
||||
{
|
||||
servicingQuery = new AtomicInteger ();
|
||||
|
|
@ -240,6 +244,7 @@ public final class EmacsService extends Service
|
|||
float tempScaledDensity;
|
||||
Resources resources;
|
||||
DisplayMetrics metrics;
|
||||
Configuration configuration;
|
||||
|
||||
super.onCreate ();
|
||||
|
||||
|
|
@ -254,6 +259,8 @@ public final class EmacsService extends Service
|
|||
tempScaledDensity = ((getScaledDensity (metrics)
|
||||
/ metrics.density)
|
||||
* pixelDensityX);
|
||||
configuration = resources.getConfiguration ();
|
||||
uiMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
resolver = getContentResolver ();
|
||||
mainThread = Thread.currentThread ();
|
||||
|
||||
|
|
@ -311,7 +318,8 @@ public final class EmacsService extends Service
|
|||
EmacsNative.setEmacsParams (manager, filesDir, libDir,
|
||||
cacheDir, pixelDensityX,
|
||||
pixelDensityY, scaledDensity,
|
||||
classPath, EmacsService.this,
|
||||
uiMode, classPath,
|
||||
EmacsService.this,
|
||||
Build.VERSION.SDK_INT);
|
||||
}
|
||||
}, extraStartupArguments);
|
||||
|
|
@ -375,8 +383,14 @@ public final class EmacsService extends Service
|
|||
dpiX = pixelDensityX;
|
||||
dpiY = pixelDensityY;
|
||||
dpiScaled = scaledDensity;
|
||||
EmacsNative.sendConfigurationChanged (pixelDensityX, pixelDensityY,
|
||||
scaledDensity);
|
||||
EmacsNative.sendConfigurationChanged (0, pixelDensityX, pixelDensityY,
|
||||
scaledDensity, 0);
|
||||
}
|
||||
|
||||
if ((newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) != uiMode)
|
||||
{
|
||||
uiMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
EmacsNative.sendConfigurationChanged (1, 0.0f, 0.0f, 0.0f, uiMode);
|
||||
}
|
||||
|
||||
super.onConfigurationChanged (newConfig);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,9 @@ double android_pixel_density_x, android_pixel_density_y;
|
|||
font sizes. */
|
||||
double android_scaled_pixel_density;
|
||||
|
||||
/* The display's current UI mode. */
|
||||
int android_ui_mode;
|
||||
|
||||
/* The Android application data directory. */
|
||||
static char *android_files_dir;
|
||||
|
||||
|
|
@ -1476,6 +1479,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
|||
jfloat pixel_density_x,
|
||||
jfloat pixel_density_y,
|
||||
jfloat scaled_density,
|
||||
jint ui_mode,
|
||||
jobject class_path,
|
||||
jobject emacs_service_object,
|
||||
jint api_level)
|
||||
|
|
@ -1501,6 +1505,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
|||
android_pixel_density_x = pixel_density_x;
|
||||
android_pixel_density_y = pixel_density_y;
|
||||
android_scaled_pixel_density = scaled_density;
|
||||
android_ui_mode = ui_mode;
|
||||
|
||||
__android_log_print (ANDROID_LOG_INFO, __func__,
|
||||
"Initializing "PACKAGE_STRING"...\nPlease report bugs to "
|
||||
|
|
@ -2821,8 +2826,9 @@ NATIVE_NAME (sendNotificationAction) (JNIEnv *env, jobject object,
|
|||
|
||||
JNIEXPORT jlong JNICALL
|
||||
NATIVE_NAME (sendConfigurationChanged) (JNIEnv *env, jobject object,
|
||||
jfloat dpi_x, jfloat dpi_y,
|
||||
jfloat dpi_scaled)
|
||||
int detail, jfloat dpi_x,
|
||||
jfloat dpi_y, jfloat dpi_scaled,
|
||||
int ui_mode)
|
||||
{
|
||||
JNI_STACK_ALIGNMENT_PROLOGUE;
|
||||
|
||||
|
|
@ -2831,9 +2837,24 @@ NATIVE_NAME (sendConfigurationChanged) (JNIEnv *env, jobject object,
|
|||
event.config.type = ANDROID_CONFIGURATION_CHANGED;
|
||||
event.config.serial = ++event_serial;
|
||||
event.config.window = ANDROID_NONE;
|
||||
event.config.dpi_x = dpi_x;
|
||||
event.config.dpi_y = dpi_y;
|
||||
event.config.dpi_scaled = dpi_scaled;
|
||||
event.config.detail = detail;
|
||||
|
||||
switch (detail)
|
||||
{
|
||||
case ANDROID_PIXEL_DENSITY_CHANGED:
|
||||
event.config.u.pixel_density.dpi_x = dpi_x;
|
||||
event.config.u.pixel_density.dpi_y = dpi_y;
|
||||
event.config.u.pixel_density.dpi_scaled = dpi_scaled;
|
||||
break;
|
||||
|
||||
case ANDROID_UI_MODE_CHANGED:
|
||||
event.config.u.ui_mode = ui_mode;
|
||||
break;
|
||||
|
||||
default:
|
||||
emacs_abort ();
|
||||
}
|
||||
|
||||
android_write_event (&event);
|
||||
return event_serial;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ extern ssize_t android_readlinkat (int, const char *restrict, char *restrict,
|
|||
|
||||
extern double android_pixel_density_x, android_pixel_density_y;
|
||||
extern double android_scaled_pixel_density;
|
||||
extern int android_ui_mode;
|
||||
|
||||
static_assert (sizeof (android_handle) == sizeof (jobject));
|
||||
#define android_resolve_handle(handle) ((jobject) (handle))
|
||||
|
|
|
|||
|
|
@ -596,6 +596,17 @@ struct android_notification_event
|
|||
size_t length;
|
||||
};
|
||||
|
||||
enum android_configuration_change_type
|
||||
{
|
||||
ANDROID_PIXEL_DENSITY_CHANGED,
|
||||
ANDROID_UI_MODE_CHANGED,
|
||||
};
|
||||
|
||||
#define UI_MODE_NIGHT_MASK 0x00000030
|
||||
#define UI_MODE_NIGHT_NO 0x00000010
|
||||
#define UI_MODE_NIGHT_YES 0x00000020
|
||||
#define UI_MODE_NIGHT_UNDEFINED 0x00000000
|
||||
|
||||
struct android_configuration_changed_event
|
||||
{
|
||||
/* Type of the event. */
|
||||
|
|
@ -607,13 +618,23 @@ struct android_configuration_changed_event
|
|||
/* The window that gave rise to the event (None). */
|
||||
android_window window;
|
||||
|
||||
/* What type of change this event represents. */
|
||||
enum android_configuration_change_type detail;
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* The density of the display along the horizontal and vertical
|
||||
axes. */
|
||||
double dpi_x, dpi_y;
|
||||
|
||||
/* The density to take into account when converting between point and
|
||||
pixel dimensions. */
|
||||
/* The density to take into account when converting between point
|
||||
and pixel dimensions. */
|
||||
double dpi_scaled;
|
||||
} pixel_density;
|
||||
|
||||
/* A change in the reported user interface UI mode. */
|
||||
int ui_mode;
|
||||
} u;
|
||||
};
|
||||
|
||||
union android_event
|
||||
|
|
|
|||
|
|
@ -1825,11 +1825,15 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
|||
goto OTHER;
|
||||
|
||||
case ANDROID_CONFIGURATION_CHANGED:
|
||||
|
||||
if (event->config.detail == ANDROID_PIXEL_DENSITY_CHANGED)
|
||||
{
|
||||
/* Update the display configuration from the event. */
|
||||
dpyinfo->resx = event->config.dpi_x;
|
||||
dpyinfo->resy = event->config.dpi_y;
|
||||
dpyinfo->font_resolution = event->config.dpi_scaled;
|
||||
#ifdef notdef
|
||||
dpyinfo->resx = event->config.u.pixel_density.dpi_x;
|
||||
dpyinfo->resy = event->config.u.pixel_density.dpi_y;
|
||||
dpyinfo->font_resolution
|
||||
= event->config.u.pixel_density.dpi_scaled;
|
||||
#if notdef
|
||||
__android_log_print (ANDROID_LOG_VERBOSE, __func__,
|
||||
"New display configuration: "
|
||||
"resx = %.2f resy = %.2f font_resolution = %.2f",
|
||||
|
|
@ -1838,6 +1842,15 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
|||
inev.ie.kind = CONFIG_CHANGED_EVENT;
|
||||
inev.ie.frame_or_window = XCAR (dpyinfo->name_list_element);
|
||||
inev.ie.arg = Qfont_render;
|
||||
}
|
||||
else if (event->config.detail == ANDROID_UI_MODE_CHANGED)
|
||||
{
|
||||
android_ui_mode = event->config.u.ui_mode;
|
||||
inev.ie.kind = TOOLKIT_THEME_CHANGED_EVENT;
|
||||
inev.ie.arg = (android_ui_mode == UI_MODE_NIGHT_YES
|
||||
? Qdark : Qlight);
|
||||
}
|
||||
|
||||
goto OTHER;
|
||||
|
||||
default:
|
||||
|
|
@ -6753,6 +6766,8 @@ android_term_init (void)
|
|||
dpyinfo->resx = android_pixel_density_x;
|
||||
dpyinfo->resy = android_pixel_density_y;
|
||||
dpyinfo->font_resolution = android_scaled_pixel_density;
|
||||
Vtoolkit_theme = (android_ui_mode == UI_MODE_NIGHT_YES
|
||||
? Qdark : Qlight);
|
||||
#endif /* !ANDROID_STUBIFY */
|
||||
|
||||
/* https://lists.gnu.org/r/emacs-devel/2015-11/msg00194.html */
|
||||
|
|
|
|||
|
|
@ -7619,16 +7619,15 @@ The default is \\+`inhibit' in NS builds and nil everywhere else. */);
|
|||
#endif /* !HAVE_EXT_TOOL_BAR || USE_GTK */
|
||||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
|
||||
#if (defined(HAVE_PGTK) && defined(HAVE_GSETTINGS)) || defined (WINDOWSNT)
|
||||
DEFVAR_LISP ("toolkit-theme", Vtoolkit_theme,
|
||||
doc: /* The current toolkit theme.
|
||||
Either the symbol `light' or the symbol `dark', reflecting the system's
|
||||
current theme preference. This variable is updated automatically when
|
||||
the system theme changes.
|
||||
|
||||
This variable is only available on PGTK and MS-Windows builds. */);
|
||||
This variable is only set on PGTK, Android, and MS-Windows builds. */);
|
||||
Vtoolkit_theme = Qnil;
|
||||
DEFSYM (Qlight, "light");
|
||||
DEFSYM (Qdark, "dark");
|
||||
#endif
|
||||
DEFSYM (Qtoolkit_theme_set_functions, "toolkit-theme-set-functions");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1476,14 +1476,12 @@ xg_update_dark_mode_for_all_displays (bool dark_mode_p)
|
|||
xg_set_gtk_theme_dark_mode (dark_mode_p, settings);
|
||||
}
|
||||
|
||||
Vtoolkit_theme = dark_mode_p ? Qdark : Qlight;
|
||||
Lisp_Object hook = intern ("toolkit-theme-set-functions");
|
||||
if (!NILP (Fboundp (hook)))
|
||||
{
|
||||
Lisp_Object args[2];
|
||||
args[0] = hook;
|
||||
args[1] = Vtoolkit_theme;
|
||||
Frun_hook_with_args (2, args);
|
||||
struct input_event inev;
|
||||
EVENT_INIT (inev);
|
||||
inev.kind = TOOLKIT_THEME_CHANGED_EVENT;
|
||||
inev.arg = msg.msg.wParam ? Qdark : Qlight;
|
||||
kbd_buffer_store_event (&inev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4242,6 +4242,15 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
}
|
||||
#endif /* HAVE_ANDROID */
|
||||
|
||||
case TOOLKIT_THEME_CHANGED_EVENT:
|
||||
kbd_fetch_ptr = next_kbd_event (event);
|
||||
input_pending = readable_events (0);
|
||||
|
||||
Vtoolkit_theme = event->ie.arg;
|
||||
CALLN (Frun_hook_with_args, Qtoolkit_theme_set_functions,
|
||||
event->ie.arg);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_EXT_MENU_BAR
|
||||
case MENU_BAR_ACTIVATE_EVENT:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -341,6 +341,10 @@ enum event_kind
|
|||
which the monitors changed. */
|
||||
, MONITORS_CHANGED_EVENT
|
||||
|
||||
/* In a TOOLKIT_THEME_CHANGED_EVENT, .arg is the value to which the
|
||||
toolkit theme was altered. */
|
||||
, TOOLKIT_THEME_CHANGED_EVENT
|
||||
|
||||
#ifdef HAVE_HAIKU
|
||||
/* In a NOTIFICATION_CLICKED_EVENT, .arg is an integer identifying
|
||||
the notification that was clicked. */
|
||||
|
|
|
|||
|
|
@ -6085,15 +6085,8 @@ w32_read_socket (struct terminal *terminal,
|
|||
|
||||
case WM_EMACS_SET_TOOLKIT_THEME:
|
||||
{
|
||||
Vtoolkit_theme = msg.msg.wParam ? Qdark : Qlight;
|
||||
Lisp_Object hook = intern ("toolkit-theme-set-functions");
|
||||
if (!NILP (Fboundp (hook)))
|
||||
{
|
||||
Lisp_Object args[2];
|
||||
args[0] = hook;
|
||||
args[1] = Vtoolkit_theme;
|
||||
Frun_hook_with_args (2, args);
|
||||
}
|
||||
inev.kind = TOOLKIT_THEME_CHANGED_EVENT;
|
||||
inev.arg = msg.msg.wParam ? Qdark : Qlight;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue