Subject: Re: bug#14635: 24.3.50; Regression in Customize: no revert changes

From: Mauro Aranda <[email-masked]>
Date: Sat, 31 Oct 2020 11:56:59 -0300

Mauro Aranda <[email-masked]> writes:

> Eli Zaretskii <[email-masked]> writes:
>
>>> From: Mauro Aranda <[email-masked]>
>>> Date: Fri, 30 Oct 2020 11:03:39 -0300
>>> Cc: Drew Adams <[email-masked]>, [email-masked]
>>>
>>> > Doesn't customizing a face record the original value in some property
>>> > of the face symbol?  If so, reverting the customizations should use
>>> > those recorded values, I think.
>>>
>>> AFAICT, it doesn't right now.  I followed the recipe I gave, and then:
>>> (symbol-plist 'default)
>>> The relevant properties I see are:
>>> * face-defface-spec ==> ((t nil))
>>> which won't take us anywhere.
>>> * theme-face, which has the customized value for the user theme, and
>>> * customized-face, which again, has the customized value.
>>>
>>> But I see no immediate reason why we shouldn't start doing it, if you
>>> think it is OK to use that to solve this issue.  My only questions are
>>> if it would be best to do it in Customize or in faces.el, and if we
>>> should only special case the default face.
>>
>> I'd begin with doing this in Customize, since it is the only user of
>> this property.
>
> I'll try to do it.  Thank you.

I attach a patch that makes Customize store the original value of the
default face if the user ever changes it, and then uses it when
reverting.

Basically, Customize tell faces.el the exactly spec to set, by putting a
fake entry under the user theme (and later removing it).
From 88bcf54a4138acd6782c70ac8ffe9db5e098956a Mon Sep 17 00:00:00 2001
From: Mauro Aranda <[email-masked]>
Date: Sat, 31 Oct 2020 10:39:31 -0300
Subject: [PATCH] Fix reverting the default face to standard/themed state in
 GUIs

* lisp/cus-edit.el (custom-face-set, custom-face-mark-to-save)
(custom-face-save): Record the default (standard or themed) attributes
of the default face in a symbol property.
(custom-face-reset-saved, custom-face-mark-to-reset-standard): When
reverting the default face to the standard or themed state, use the
default attributes we recorded, instead of relying in the defface spec
of the default face, since that doesn't give enough information to
reset all attributes, like foreground, family, etc.  (Bug#14635)
---
 lisp/cus-edit.el | 50 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 769a69a50f..db748c1096 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -3895,6 +3895,18 @@ custom-face-set
       (setq comment nil)
       ;; Make the comment invisible by hand if it's empty
       (custom-comment-hide comment-widget))
+    ;; When modifying the default face, we need to save the standard or themed
+    ;; attrs, in case the user asks to revert to them in the future.
+    ;; In GUIs, when resetting the attributes of the default face, the frame
+    ;; parameters associated with this face won't change, unless explicitly
+    ;; passed a value.  Storing this known attrs allows us to tell faces.el to
+    ;; set those attributes to specified values, making the relevant frame
+    ;; parameters stay in sync with the default face.
+    (when (and (eq symbol 'default)
+               (not (get symbol 'custom-face-default-attrs))
+               (memq (custom-face-state symbol) '(standard themed)))
+      (put symbol 'custom-face-default-attrs
+           (custom-face-get-current-spec symbol)))
     (custom-push-theme 'theme-face symbol 'user 'set value)
     (face-spec-set symbol value 'customized-face)
     (put symbol 'face-comment comment)
@@ -3913,6 +3925,12 @@ custom-face-mark-to-save
       (setq comment nil)
       ;; Make the comment invisible by hand if it's empty
       (custom-comment-hide comment-widget))
+    ;; See the comments in `custom-face-set'.
+    (when (and (eq symbol 'default)
+               (not (get symbol 'custom-face-default-attrs))
+               (memq (custom-face-state symbol) '(standard themed)))
+      (put symbol 'custom-face-default-attrs
+           (custom-face-get-current-spec symbol)))
     (custom-push-theme 'theme-face symbol 'user 'set value)
     (face-spec-set symbol value (if standard 'reset 'saved-face))
     (put symbol 'face-comment comment)
@@ -3926,7 +3944,14 @@ custom-face-state-set-and-redraw
 
 (defun custom-face-save (widget)
   "Save the face edited by WIDGET."
-  (let ((form (widget-get widget :custom-form)))
+  (let ((form (widget-get widget :custom-form))
+        (symbol (widget-value widget)))
+    ;; See the comments in `custom-face-set'.
+    (when (and (eq symbol 'default)
+               (not (get symbol 'custom-face-default-attrs))
+               (memq (custom-face-state symbol) '(standard themed)))
+      (put symbol 'custom-face-default-attrs
+           (custom-face-get-current-spec symbol)))
     (if (memq form '(all lisp))
         (custom-face-mark-to-save widget)
       ;; The user is working on only a selected terminal type;
@@ -3949,10 +3974,20 @@ custom-face-reset-saved
 	 (saved-face (get face 'saved-face))
 	 (comment (get face 'saved-face-comment))
 	 (comment-widget (widget-get widget :comment-widget)))
+    ;; If resetting the default face and there isn't a saved value,
+    ;; push a fake user setting, so that reverting to the default
+    ;; attributes works.
     (custom-push-theme 'theme-face face 'user
-		       (if saved-face 'set 'reset)
-		       saved-face)
+                       (if (or saved-face (eq face 'default)) 'set 'reset)
+                       (or saved-face
+                           ;; If this is t, then MODE is 'reset,
+                           ;; and `custom-push-theme' ignores this argument.
+                           (not (eq face 'default))
+                           (get face 'custom-face-default-attrs)))
     (face-spec-set face saved-face 'saved-face)
+    (when (and (not saved-face) (eq face 'default))
+      ;; Remove the fake user setting.
+      (custom-push-theme 'theme-face face 'user 'reset))
     (put face 'face-comment comment)
     (put face 'customized-face-comment nil)
     (widget-value-set child saved-face)
@@ -3974,8 +4009,15 @@ custom-face-mark-to-reset-standard
 	 (comment-widget (widget-get widget :comment-widget)))
     (unless value
       (user-error "No standard setting for this face"))
-    (custom-push-theme 'theme-face symbol 'user 'reset)
+    ;; If erasing customizations for the default face, push a fake user setting,
+    ;; so that reverting to the default attributes works.
+    (custom-push-theme 'theme-face symbol 'user
+                       (if (eq symbol 'default) 'set 'reset)
+                       (or (not (eq symbol 'default))
+                           (get symbol 'custom-face-default-attrs)))
     (face-spec-set symbol value 'reset)
+    ;; Remove the fake user setting.
+    (custom-push-theme 'theme-face symbol 'user 'reset)
     (put symbol 'face-comment nil)
     (put symbol 'customized-face-comment nil)
     (if (and custom-reset-standard-faces-list
-- 
2.29.0