]> git.eshelyaron.com Git - emacs.git/commitdiff
Respond to display configuration updates on Android
authorPo Lu <luangruo@yahoo.com>
Thu, 10 Apr 2025 07:21:15 +0000 (15:21 +0800)
committerEshel Yaron <me@eshelyaron.com>
Fri, 11 Apr 2025 11:32:47 +0000 (13:32 +0200)
* java/org/gnu/emacs/EmacsNative.java
(sendConfigurationChanged): Declare function.

* java/org/gnu/emacs/EmacsSdk7FontDriver.java (Sdk7FontEntity)
(Sdk7FontObject): Do not access `metrics' field deleted from
`EmacsService'.

* java/org/gnu/emacs/EmacsService.java (EmacsService)
<metrics, resources>: Delete fields.
<dpiX, dpiY, dpiScaled>: New fields.
(onCreate): Adjust accordingly.  Record current display metrics
for subsequent comparison.
(onConfigurationChanged): New function.

* lisp/dynamic-setting.el (font-setting-change-default-font):
Enable on systems where font-get-system-font is not defined if
invoked with SET-FONT nil.

* src/android.c (sendConfigurationChanged): New function.

* src/androidgui.h (ANDROID_CONFIGURATION_CHANGED): New enumerator.
(struct android_configuration_changed): New structure.
(union android_event): Add `config' member.

* src/androidterm.c (handle_one_android_event): Handle
ANDROID_CONFIGURATION_CHANGED events.
(syms_of_androidterm): Define Qfont_render, and
Qdynamic_setting.  Provide the latter.

(cherry picked from commit 884ede7c959b1331e1ede0b1b80f01a06c048bf5)

java/org/gnu/emacs/EmacsNative.java
java/org/gnu/emacs/EmacsSdk7FontDriver.java
java/org/gnu/emacs/EmacsService.java
lisp/dynamic-setting.el
src/android.c
src/androidgui.h
src/androidterm.c

index 94df9ff39b4bbbb00cc30ffed490b0ed3844cbbd..49a21ce1c4d42c0fad6fdc74df3885422274d4b4 100644 (file)
@@ -196,6 +196,10 @@ public final class EmacsNative
   /* Send an ANDROID_NOTIFICATION_ACTION event.  */
   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);
+
   /* Return the file name associated with the specified file
      descriptor, or NULL if there is none.  */
   public static native byte[] getProcName (int fd);
index 2fc40551984e4904bcb36c579bb6855e3428e7e1..b426c3ba74e902fd8a052a7fe9e6b6bf8ebb8584 100644 (file)
@@ -29,6 +29,7 @@ import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.Canvas;
 
+import android.util.DisplayMetrics;
 import android.util.Log;
 
 \f
@@ -103,6 +104,8 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
     public
     Sdk7FontEntity (Sdk7Typeface typeface)
     {
+      DisplayMetrics metrics;
+
       foundry = "Google";
       family = typeface.familyName;
       adstyle = null;
@@ -110,7 +113,8 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
       slant = typeface.slant;
       spacing = typeface.spacing;
       width = typeface.width;
-      dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f);
+      metrics = EmacsService.SERVICE.getResources ().getDisplayMetrics ();
+      dpi = Math.round (metrics.scaledDensity * 160f);
 
       this.typeface = typeface;
     }
@@ -127,6 +131,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
     {
       float totalWidth;
       String testWidth, testString;
+      DisplayMetrics metrics;
 
       this.typeface = typeface;
       this.pixelSize = pixelSize;
@@ -137,7 +142,8 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
       slant = typeface.slant;
       spacing = typeface.spacing;
       width = typeface.width;
-      dpi = Math.round (EmacsService.SERVICE.metrics.scaledDensity * 160f);
+      metrics = EmacsService.SERVICE.getResources ().getDisplayMetrics ();
+      dpi = Math.round (metrics.scaledDensity * 160f);
 
       /* Compute the ascent and descent.  */
       typeface.typefacePaint.setTextSize (pixelSize);
index babf2626ba50d49e3960a1bebc559cea10cafd14..3630329839fb41a1cd932cb0a4d5ef51f0865310 100644 (file)
@@ -123,9 +123,6 @@ public final class EmacsService extends Service
   public static final int IC_MODE_TEXT     = 2;
   public static final int IC_MODE_PASSWORD = 3;
 
-  /* Display metrics used by font backends.  */
-  public DisplayMetrics metrics;
-
   /* Flag that says whether or not to print verbose debugging
      information when responding to an input method.  */
   public static final boolean DEBUG_IC = false;
@@ -149,8 +146,9 @@ public final class EmacsService extends Service
      thread.  */
   private Thread mainThread;
 
-  /* "Resources" object required by GContext bookkeeping.  */
-  public static Resources resources;
+  /* The display's horizontal and vertical density and that which is
+     consulted for font scaling.  */
+  private double dpiX, dpiY, dpiScaled;
 
   static
   {
@@ -236,10 +234,12 @@ public final class EmacsService extends Service
     final AssetManager manager;
     Context app_context;
     final String filesDir, libDir, cacheDir, classPath;
-    final double pixelDensityX;
-    final double pixelDensityY;
-    final double scaledDensity;
-    double tempScaledDensity;
+    final float pixelDensityX;
+    final float pixelDensityY;
+    final float scaledDensity;
+    float tempScaledDensity;
+    Resources resources;
+    DisplayMetrics metrics;
 
     super.onCreate ();
 
@@ -265,13 +265,18 @@ public final class EmacsService extends Service
        corresponds to 1 pixel, not 72 or 96 as used elsewhere.  This
        difference is codified in PT_PER_INCH defined in font.h.  */
 
-    if (tempScaledDensity < 160)
-      tempScaledDensity = 160;
+    if (tempScaledDensity < 160.0f)
+      tempScaledDensity = 160.0f;
 
     /* scaledDensity is const as required to refer to it from within
        the nested function below.  */
     scaledDensity = tempScaledDensity;
 
+    /* Save these fields for future reference.  */
+    dpiX = pixelDensityX;
+    dpiY = pixelDensityY;
+    dpiScaled = scaledDensity;
+
     /* Remove all tasks from previous Emacs sessions but the task
        created by the system at startup.  */
     EmacsWindowManager.MANAGER.removeOldTasks (this);
@@ -304,9 +309,8 @@ public final class EmacsService extends Service
            run ()
            {
              EmacsNative.setEmacsParams (manager, filesDir, libDir,
-                                         cacheDir, (float) pixelDensityX,
-                                         (float) pixelDensityY,
-                                         (float) scaledDensity,
+                                         cacheDir, pixelDensityX,
+                                         pixelDensityY, scaledDensity,
                                          classPath, EmacsService.this,
                                          Build.VERSION.SDK_INT);
            }
@@ -344,6 +348,40 @@ public final class EmacsService extends Service
     super.onLowMemory ();
   }
 
+  @Override
+  public void
+  onConfigurationChanged (Configuration newConfig)
+  {
+    DisplayMetrics metrics;
+    float pixelDensityX, pixelDensityY, scaledDensity;
+
+    metrics = getResources ().getDisplayMetrics ();
+
+    /* The display configuration may have been altered.  Retrieve the
+       revised display density and deliver an event if so.  */
+    pixelDensityX = metrics.xdpi;
+    pixelDensityY = metrics.ydpi;
+    scaledDensity = ((getScaledDensity (metrics)
+                     / metrics.density) * pixelDensityX);
+
+    /* A density below 160 probably indicates a system bug.  See
+       onCreate for more commentary.  */
+    if (scaledDensity < 160.0f)
+      scaledDensity = 160.0f;
+
+    if (pixelDensityX != dpiX || pixelDensityY != dpiY
+       || scaledDensity != dpiScaled)
+      {
+       dpiX = pixelDensityX;
+       dpiY = pixelDensityY;
+       dpiScaled = scaledDensity;
+       EmacsNative.sendConfigurationChanged (pixelDensityX, pixelDensityY,
+                                             scaledDensity);
+      }
+
+    super.onConfigurationChanged (newConfig);
+  }
+
 \f
 
   /* Functions from here on must only be called from the Emacs
index 3681df0b8f5db8e62141d564bccbc69caaeafc6e..c38f4656e37a04187686a7a74020246adc02e687 100644 (file)
@@ -46,7 +46,8 @@ the current form for the frame (i.e. hinting or somesuch changed)."
   (let ((new-font (and (fboundp 'font-get-system-font)
                       (font-get-system-font)))
        (frame-list (frames-on-display-list display-or-frame)))
-    (when (and new-font (display-graphic-p display-or-frame))
+    (when (and (or (not set-font) new-font)
+               (display-graphic-p display-or-frame))
       (clear-font-cache)
       (if set-font
          ;; Set the font on all current and future frames, as though
index 0be3e10dea4b7bfa881d5e84ee50c862a3616a16..5c78dbd917183562e90b53cbee2bc0a78d974c3b 100644 (file)
@@ -2819,6 +2819,25 @@ NATIVE_NAME (sendNotificationAction) (JNIEnv *env, jobject object,
   return event_serial;
 }
 
+JNIEXPORT jlong JNICALL
+NATIVE_NAME (sendConfigurationChanged) (JNIEnv *env, jobject object,
+                                       jfloat dpi_x, jfloat dpi_y,
+                                       jfloat dpi_scaled)
+{
+  JNI_STACK_ALIGNMENT_PROLOGUE;
+
+  union android_event event;
+
+  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;
+  android_write_event (&event);
+  return event_serial;
+}
+
 JNIEXPORT jboolean JNICALL
 NATIVE_NAME (shouldForwardMultimediaButtons) (JNIEnv *env,
                                              jobject object)
index 55c139d403d7e9c65490705a2468b7ad7452be70..b09d5eaabceffaead23b1e86e3551b9dc025488d 100644 (file)
@@ -288,6 +288,7 @@ enum android_event_type
     ANDROID_DND_TEXT_EVENT,
     ANDROID_NOTIFICATION_DELETED,
     ANDROID_NOTIFICATION_ACTION,
+    ANDROID_CONFIGURATION_CHANGED,
   };
 
 struct android_any_event
@@ -595,6 +596,26 @@ struct android_notification_event
   size_t length;
 };
 
+struct android_configuration_changed_event
+{
+  /* Type of the event.  */
+  enum android_event_type type;
+
+  /* The event serial.  */
+  unsigned long serial;
+
+  /* The window that gave rise to the event (None).  */
+  android_window window;
+
+  /* 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.  */
+  double dpi_scaled;
+};
+
 union android_event
 {
   enum android_event_type type;
@@ -635,6 +656,11 @@ union android_event
   /* X provides no equivalent interface for displaying
      notifications.  */
   struct android_notification_event notification;
+
+  /* The equivalent under X is provided through XSettings, which is a
+     byzantine protocol that extends client messages and is therefore
+     not worthwhile to emulate.  */
+  struct android_configuration_changed_event config;
 };
 
 enum
index 884d8f8d71817ad7ea843dea532125b79406d976..96f595f3bdfcf1ed8fa4037e4dd6000672e0f257 100644 (file)
@@ -1824,6 +1824,22 @@ handle_one_android_event (struct android_display_info *dpyinfo,
       free (event->notification.action);
       goto OTHER;
 
+    case ANDROID_CONFIGURATION_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
+      __android_log_print (ANDROID_LOG_VERBOSE, __func__,
+                          "New display configuration: "
+                          "resx = %.2f resy = %.2f font_resolution = %.2f",
+                          dpyinfo->resx, dpyinfo->resy, dpyinfo->font_resolution);
+#endif /* notdef */
+      inev.ie.kind = CONFIG_CHANGED_EVENT;
+      inev.ie.frame_or_window = XCAR (dpyinfo->name_list_element);
+      inev.ie.arg = Qfont_render;
+      goto OTHER;
+
     default:
       goto OTHER;
     }
@@ -7014,6 +7030,11 @@ for instance, `early-init.el', or they will be of no effect.  */);
   /* Key symbols.  */
   DEFSYM (Qselect, "select");
   DEFSYM (Qreturn, "return");
+
+  /* Display configuration updates.  */
+  DEFSYM (Qfont_render, "font-render");
+  DEFSYM (Qdynamic_setting, "dynamic-setting");
+  Fprovide (Qdynamic_setting, Qnil);
 }
 
 void