Subject: bug#64347: 30.0.50; Some customize faces shown as edited with -Q

From: Mauro Aranda <[email-masked]>
Date: Sat, 15 Jul 2023 17:01:44 -0300

Eli Zaretskii <[email-masked]> writes:

 >> Date: Sun, 9 Jul 2023 20:12:38 -0300
 >> Cc: [email-masked], [email-masked]
 >> From: Mauro Aranda <[email-masked]>
 >>
 >> Eli Zaretskii <[email-masked]> writes:
 >>
 >>  > OK, but why does it have to do that on the original value? It could
 >>  > do that on a copy that serves for the display and editing, in which
 >>  > case the original value could be left intact if the user didn't 
change
 >>  > it or did change, but didn't click Apply.  (If the user does modify
 >>  > the original value, then any conversions are okay, since the variable
 >>  > is really "edited".)
 >>
 >> I think my description was inaccurate, because it seemed to imply that
 >> it is a destructive operation.  It is not, it leaves the original value
 >> intact.
 >>
 >> But when deciding to set a state, Custom always consults the spec built
 >> from the data the face Widget has.
 >
 > Can we change this last aspect, so that the state is set using the
 > original spec if the setting was not changed by the user?

OK, here's a patch for doing that.  It seems to me that after creating
the widget, the only reason to use the value that's represented in the
widget is if we loaded the spec from the :shown-value property (meaning
we are redrawing the widget and we want to keep a spec that was already
in the widget)
From 7ffb3f466cb3c0804f8cb0ec25171e6013f41dff Mon Sep 17 00:00:00 2001
From: Mauro Aranda <[email-masked]>
Date: Mon, 10 Jul 2023 10:47:23 -0300
Subject: [PATCH] Pass original spec just after creating the face-widget

* lisp/cus-edit.el (custom-face-get-current-spec-unfiltered): New
function, extracted from custom-face-get-current-spec.
(custom-face-get-current-spec): Use it.
(custom-face-state-set): Take an optional argument, to decide if we
should check against a filtered or unfiltered spec.
(custom-face-value-create): Use the new optional argument.  (Bug#64347)
---
 lisp/cus-edit.el | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index dbef5f47cd6..c5ddca9bc29 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -3717,7 +3717,8 @@ custom-face-widget-to-spec
 	 `((t ,(widget-value child)))
        (widget-value child)))))
 
-(defun custom-face-get-current-spec (face)
+(defun custom-face-get-current-spec-unfiltered (face)
+  "Return the current spec for face FACE, without filtering it."
   (let ((spec (or (get face 'customized-face)
 		  (get face 'saved-face)
 		  (get face 'face-defface-spec)
@@ -3728,7 +3729,11 @@ custom-face-get-current-spec
     ;; edit it as the user has specified it.
     (if (not (face-spec-match-p face spec (selected-frame)))
 	(setq spec `((t ,(face-attr-construct face (selected-frame))))))
-    (custom-pre-filter-face-spec spec)))
+    spec))
+
+(defun custom-face-get-current-spec (face)
+  "Return the current spec for face FACE, filtering it."
+  (custom-pre-filter-face-spec (custom-face-get-current-spec-unfiltered face)))
 
 (defun custom-toggle-hide-face (visibility-widget &rest _ignore)
   "Toggle the visibility of a `custom-face' parent widget.
@@ -3848,8 +3853,8 @@ custom-face-value-create
 	(unless (widget-get widget :custom-form)
 	  (widget-put widget :custom-form custom-face-default-form))
 
-	(let* ((spec (or (widget-get widget :shown-value)
-			 (custom-face-get-current-spec symbol)))
+	(let* ((shown-value (widget-get widget :shown-value))
+               (spec (or shown-value (custom-face-get-current-spec symbol)))
 	       (form (widget-get widget :custom-form))
 	       (indent (widget-get widget :indent))
 	       face-alist face-entry spec-default spec-match editor)
@@ -3890,7 +3895,7 @@ custom-face-value-create
 		   widget 'sexp :value spec))))
           (push editor children)
           (widget-put widget :children children)
-	  (custom-face-state-set widget))))))
+	  (custom-face-state-set widget (not shown-value)))))))
 
 (defun cus--face-link (widget _format)
   (widget-create-child-and-convert
@@ -4010,13 +4015,18 @@ custom-face-state
 	'changed
       state)))
 
-(defun custom-face-state-set (widget)
+(defun custom-face-state-set (widget &optional no-filter)
   "Set the state of WIDGET, a custom-face widget.
 If the user edited the widget, set the state to modified.  If not, the new
-state is one of the return values of `custom-face-state'."
+state is one of the return values of `custom-face-state'.
+Optional argument NO-FILTER means to check against an unfiltered spec."
   (let ((face (widget-value widget)))
     (widget-put widget :custom-state
-                (if (face-spec-match-p face (custom-face-widget-to-spec widget))
+                (if (face-spec-match-p
+                     face
+                     (if no-filter
+                         (custom-face-get-current-spec-unfiltered face)
+                       (custom-face-widget-to-spec widget)))
                     (custom-face-state face)
                   'modified))))
 
-- 
2.34.1