From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: =?UTF-8?Q?Cl=C3=A9ment?= Pit-Claudel Newsgroups: gmane.emacs.bugs Subject: bug#41200: Displaying a tooltip with x-show-tip gets very slow as more faces are defined Date: Fri, 15 May 2020 10:59:36 -0400 Message-ID: <789d786d-a07a-65c1-c0e4-433e4c18d64e@gmail.com> References: <8fd8896a-cd5c-66f4-4792-f65cac4dc4f5@gmail.com> <83lflx896q.fsf@gnu.org> <837dxd31cb.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------BE1646C852BDDA7C590FE83E" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="98526"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 Cc: 41200@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri May 15 17:00:13 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jZboq-000POd-O8 for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 15 May 2020 17:00:12 +0200 Original-Received: from localhost ([::1]:56848 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jZbop-0005Ri-Qz for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 15 May 2020 11:00:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47674) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jZbog-0005RV-FD for bug-gnu-emacs@gnu.org; Fri, 15 May 2020 11:00:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:55154) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jZbog-0005Cu-5b for bug-gnu-emacs@gnu.org; Fri, 15 May 2020 11:00:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1jZbog-000138-2s for bug-gnu-emacs@gnu.org; Fri, 15 May 2020 11:00:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: =?UTF-8?Q?Cl=C3=A9ment?= Pit-Claudel Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 15 May 2020 15:00:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 41200 X-GNU-PR-Package: emacs Original-Received: via spool by 41200-submit@debbugs.gnu.org id=B41200.15895547873970 (code B ref 41200); Fri, 15 May 2020 15:00:01 +0000 Original-Received: (at 41200) by debbugs.gnu.org; 15 May 2020 14:59:47 +0000 Original-Received: from localhost ([127.0.0.1]:38467 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jZboQ-00011x-4H for submit@debbugs.gnu.org; Fri, 15 May 2020 10:59:46 -0400 Original-Received: from mail-qk1-f173.google.com ([209.85.222.173]:44660) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jZboO-00011g-I0 for 41200@debbugs.gnu.org; Fri, 15 May 2020 10:59:45 -0400 Original-Received: by mail-qk1-f173.google.com with SMTP id b6so2774746qkh.11 for <41200@debbugs.gnu.org>; Fri, 15 May 2020 07:59:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=UsMYgset5nGusdhgmMfFdgV2cZxg5QQZrABcZZzB3bI=; b=HVfHUsFIx6L+dKdSGKIJhAPIjtlqRh8E4G5r59F5Ki1wKX95lxChfG+Qs/PjzleQlo LF7FEIcBiouN6zTyBbpTH+yf5sZ/shRf5gIKpmVcseXAiuNishrNJK4tQ3DXk3q2+a+7 2k5xXhw07BoppL9ozUOLvPe1AIFdnn/ol1+l5+WvJ+fe+fgbgcrpT1+pDDgUNZuPu99N lq+wlXtw4BDG/pAXudo0/WJQbIrtF7uUu5QjbrLDBjup2/srdwXh9lbGvOxEJfaP4SMd bMbjv691oXQBR/IbeUPCSAUb+ufGDzHzGqHwCd46vk4jq0yMOu5h6a+/oTnHtDMdwGjG chYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=UsMYgset5nGusdhgmMfFdgV2cZxg5QQZrABcZZzB3bI=; b=EyR+Qbf2BLtOmnqZknwtiDvw9bN3evziAI4/nD/Dkv12leMUNE+kqygS1Z7WmSIzQ5 IAhNnGEf64d3Tw5hZ3PfYHCQ/5kuC6cXEcR+fAh4P1gdRyn9xeDlC7PHdr5sWYralMQw HpCQlytXJTyjQ6EFKM7qxmKuLBFKWi25+LExaLmOaEFNkFo+FEsJz+hmLc1I1/sYtmmN kG2dF/IQXOW7LGOx4/MFIb+jWn7WS0qgbOuCg1EbK3fKke6QRs4TgLZ5fGO/6hNcdZxp fYhKBZBxkagizqZIoLc7d5tCHYS4HFrczgqkf+eIWY8AucpGbPhrV1Ff1Yq60KRPl0HX sFyw== X-Gm-Message-State: AOAM531kOxHr4ARLexsLzZ1N3viXJmVyYPqtUD7zbKTzOMiLpi3Gw99c 4RwKiFE2MpyBMe3teCazxD9ItZWP X-Google-Smtp-Source: ABdhPJxA9wPQgdWbw0o8XcE8Hu8rjal6RpPOraOra2aiwHwW0W5IO15PI2RL7dQvQHX4x6M1zJas/w== X-Received: by 2002:a05:620a:4c9:: with SMTP id 9mr2136702qks.487.1589554778632; Fri, 15 May 2020 07:59:38 -0700 (PDT) Original-Received: from ?IPv6:2601:184:4180:66e7:4d17:b25e:8d9:2188? ([2601:184:4180:66e7:4d17:b25e:8d9:2188]) by smtp.googlemail.com with ESMTPSA id x20sm2199987qtc.3.2020.05.15.07.59.37 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 15 May 2020 07:59:37 -0700 (PDT) In-Reply-To: <837dxd31cb.fsf@gnu.org> Content-Language: en-GB X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:180336 Archived-At: This is a multi-part message in MIME format. --------------BE1646C852BDDA7C590FE83E Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Hi Eli, Thanks a lot for the review. I have attached an updated version of the patch. On 15/05/2020 07.05, Eli Zaretskii wrote: > I'd like to keep the old face-new-frame-defaults and frame-face-alist > for compatibility, but mention in the doc strings that they no longer > return modifiable values, and perhaps deprecate them. Done for frame-face-alist. But how can one do a read-only variable? Using the new variable watchers facility? >> * The name face_hash isn't ideal, since there's already a distinct notion of face hashes (hash codes). Can you think of a better name? > > face_hash_table? Thanks, good idea. I also liked Stefan's frame_face_map. >> + // QUESTION: is this where this should be initialized? > > Yes, I think so. But do we need to do anything when frame is deleted > as well? I'm not sure (I don't know how garbage collection works on the C side in Elisp; I assumed the map would be collected). >> -DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, >> +// QUESTION: Should I add an ELisp version of frame-face-hash? > > You mean, frame-face-alist, right? Yes, most definitely: I imagine a > lot of code out there uses that, and we wouldn't want to break that. Done. I looked around, but I didn't find many uses at all (for example, there are none in ELPA). I think this is likely because the function is documented as "For internal use only." There are no uses of face-new-frame-defaults in ELPA either; online, I found many copies of lisp-mode and emacs-lisp-mode, which refer it, and a few functions derived from edebug-eval-defun, which references it. > And I'm not sure we should have it only in Lisp: perhaps we should > maintain the alist as well, and add/remove to/from it when a face is > added or removed in the hash table. Otherwise this change of > internals will have painful effect on packages that use the current > APIs. frame-face-alist is likely less crucial than face-new-frame-defaults, because it was already a function, so the return value has to be mutated in place to modify it (it couldn't be directly assigned). For both of these, however, how would we ensure that the alist remains in sync with the hashmap (that is, how do we catch modifications?) >> + Lisp_Object lface = HASH_KEY(table, idx); >> + Lisp_Object face_id = Fget (lface, Qface); >> + // FIXME why is (get 'tab-line 'face) 0? > > A bug, I guess. As far as I can see, these IDs are assigned by Finternal_make_lisp_face, and I *think* it is never called for tab-line? Should I make sure that it is? If so, where from? > >> + if (!FIXNATP (face_id)) >> + // FIXME: I'm not sure what to do in this case > > I'm not sure I understand why do you need to look at the existing > face's 'face' property? The original code didn't. The original code iterated over face-frame-alist in the order in which entries were added to it. If I understand correctly, iteration order isn't guaranteed on hash tables (is it?), so I had to find a different source of truth for these. > >> DEFVAR_LISP ("face-new-frame-defaults", Vface_new_frame_defaults, >> doc: /* List of global face definitions (for internal use only.) */); >> - Vface_new_frame_defaults = Qnil; >> + Vface_new_frame_defaults = >> + make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE, >> + DEFAULT_REHASH_THRESHOLD, Qnil, Qnil); > > Why do we need to start with a non-default hash-table? I wanted to use `eq' instead of `eql' as the test (is that what you were asking?) --------------BE1646C852BDDA7C590FE83E Content-Type: text/x-patch; charset=UTF-8; name="0001-Store-frame-faces-in-hash-tables-instead-of-alists.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Store-frame-faces-in-hash-tables-instead-of-alists.patc"; filename*1="h" >From 86ea2f96e4e3a2161f68f13b251620b98489fd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Pit-Claudel?= Date: Tue, 12 May 2020 21:48:32 -0400 Subject: [PATCH] Store frame faces in hash tables instead of alists * lisp/emacs-lisp/edebug.el (edebug-eval-defun): * lisp/progmodes/elisp-mode.el (elisp--eval-defun-1): * lisp/frame.el (frame-set-background-mode): * lisp/faces.el (face-list): Update to work with hash tables instead of alists. (frame-face-alist): Reimplement using frame-face-map. * src/frame.h (struct frame): Remove face_alist, add face_map. (fset_face_alist): Remove. (fset_face_map): New function. * src/frame.c (make_frame): Initialize f->face_map. (Fmake_terminal_frame): Update to work with hash tables instead of alists. * src/xfaces.c (lface_from_face_name_no_resolve): (Finternal_make_lisp_face): (update_face_from_frame_parameter): Update to work with hash tables instead of alists. * src/xfaces.c (Fframe_face_map): New function. (Fframe_face_alist): Move to face.el. (init_xfaces): Compute face IDs from they face property, not from their position in face_alist. (syms_of_xfaces): Remove frame_face_alist, add frame_face_map; change Vface_new_frame_defaults into a hash table. --- lisp/emacs-lisp/edebug.el | 3 +- lisp/faces.el | 13 +++++++- lisp/frame.el | 2 +- lisp/progmodes/elisp-mode.el | 3 +- src/frame.c | 20 +++++++---- src/frame.h | 8 ++--- src/xfaces.c | 65 +++++++++++++++++++----------------- 7 files changed, 67 insertions(+), 47 deletions(-) diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index 78461185d3..97ca964eef 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -488,8 +488,7 @@ edebug-eval-defun (set-default (nth 1 form) (eval (nth 2 form) lexical-binding))) ((eq (car form) 'defface) ;; Reset the face. - (setq face-new-frame-defaults - (assq-delete-all (nth 1 form) face-new-frame-defaults)) + (remhash (nth 1 form) face-new-frame-defaults) (put (nth 1 form) 'face-defface-spec nil) (put (nth 1 form) 'face-documentation (nth 3 form)) ;; See comments in `eval-defun-1' for purpose of code below diff --git a/lisp/faces.el b/lisp/faces.el index e707f6f4b6..c45921bb48 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -176,10 +176,21 @@ face-font-registry-alternatives ;;; Creation, copying. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun frame-face-alist (&optional frame) + "Return an alist of frame-local faces defined on FRAME. +This alist is a copy of the contents of `frame-face-map'. +For internal use only." + (declare (obsolete frame-face-map "28.1")) + (let ((faces)) + (maphash (lambda (face spec) (push (cons face spec) faces)) + (frame-face-map frame)) + faces)) (defun face-list () "Return a list of all defined faces." - (mapcar #'car face-new-frame-defaults)) + (let ((faces nil)) + (maphash (lambda (face _) (push face faces)) face-new-frame-defaults) + faces)) (defun make-face (face) "Define a new face with name FACE, a symbol. diff --git a/lisp/frame.el b/lisp/frame.el index 6c2f774709..14c9112aad 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1227,7 +1227,7 @@ frame-set-background-mode ;; during startup with -rv on the command ;; line for the initial frame, because frames ;; are not recorded in the pdump file. - (assq face (frame-face-alist)) + (gethash face (frame-face-map)) (face-spec-match-p face (face-user-default-spec face) ;; FIXME: why selected-frame and diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index b737134f90..dc8688c864 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -1304,8 +1304,7 @@ elisp--eval-defun-1 ((eq (car form) 'custom-declare-face) ;; Reset the face. (let ((face-symbol (eval (nth 1 form) lexical-binding))) - (setq face-new-frame-defaults - (assq-delete-all face-symbol face-new-frame-defaults)) + (remhash face-new-frame-defaults face-symbol) (put face-symbol 'face-defface-spec nil) (put face-symbol 'face-override-spec nil)) form) diff --git a/src/frame.c b/src/frame.c index c871e4fd99..514b390910 100644 --- a/src/frame.c +++ b/src/frame.c @@ -946,6 +946,10 @@ make_frame (bool mini_p) rw->total_lines = mini_p ? 9 : 10; rw->pixel_height = rw->total_lines * FRAME_LINE_HEIGHT (f); + fset_face_map + (f, make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE, + DEFAULT_REHASH_THRESHOLD, Qnil, false)); + if (mini_p) { mw->top_line = rw->total_lines; @@ -1254,7 +1258,7 @@ DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, { struct frame *f; struct terminal *t = NULL; - Lisp_Object frame, tem; + Lisp_Object frame; struct frame *sf = SELECTED_FRAME (); #ifdef MSDOS @@ -1336,14 +1340,16 @@ DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, store_in_alist (&parms, Qminibuffer, Qt); Fmodify_frame_parameters (frame, parms); - /* Make the frame face alist be frame-specific, so that each + /* Make the frame face hash be frame-specific, so that each frame could change its face definitions independently. */ - fset_face_alist (f, Fcopy_alist (sf->face_alist)); - /* Simple Fcopy_alist isn't enough, because we need the contents of - the vectors which are the CDRs of associations in face_alist to + fset_face_map (f, Fcopy_hash_table (sf->face_map)); + /* Simple copy_hash_table isn't enough, because we need the contents of + the vectors which are the values in face_map to be copied as well. */ - for (tem = f->face_alist; CONSP (tem); tem = XCDR (tem)) - XSETCDR (XCAR (tem), Fcopy_sequence (XCDR (XCAR (tem)))); + ptrdiff_t idx = 0; + struct Lisp_Hash_Table *table = XHASH_TABLE (f->face_map); + for (idx = 0; idx < table->count; ++idx) + set_hash_value_slot (table, idx, Fcopy_sequence (HASH_VALUE (table, idx))); f->can_set_window_size = true; f->after_make_frame = true; diff --git a/src/frame.h b/src/frame.h index 476bac67fa..f8915b3c1a 100644 --- a/src/frame.h +++ b/src/frame.h @@ -158,8 +158,8 @@ #define EMACS_FRAME_H There are four additional elements of nil at the end, to terminate. */ Lisp_Object menu_bar_items; - /* Alist of elements (FACE-NAME . FACE-VECTOR-DATA). */ - Lisp_Object face_alist; + /* Hash table of FACE-NAME keys and FACE-VECTOR-DATA values. */ + Lisp_Object face_map; /* A vector that records the entire structure of this frame's menu bar. For the format of the data, see extensive comments in xmenu.c. @@ -661,9 +661,9 @@ fset_condemned_scroll_bars (struct frame *f, Lisp_Object val) f->condemned_scroll_bars = val; } INLINE void -fset_face_alist (struct frame *f, Lisp_Object val) +fset_face_map (struct frame *f, Lisp_Object val) { - f->face_alist = val; + f->face_map = val; } #if defined (HAVE_WINDOW_SYSTEM) INLINE void diff --git a/src/xfaces.c b/src/xfaces.c index 7d7aff95c1..89e9a10a0a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1843,13 +1843,11 @@ lface_from_face_name_no_resolve (struct frame *f, Lisp_Object face_name, Lisp_Object lface; if (f) - lface = assq_no_quit (face_name, f->face_alist); + lface = Fgethash (face_name, f->face_map, Qnil); else - lface = assq_no_quit (face_name, Vface_new_frame_defaults); + lface = Fgethash (face_name, Vface_new_frame_defaults, Qnil); - if (CONSP (lface)) - lface = XCDR (lface); - else if (signal_p) + if (signal_p && NILP (lface)) signal_error ("Invalid face", face_name); check_lface (lface); @@ -2736,8 +2734,7 @@ DEFUN ("internal-make-lisp-face", Finternal_make_lisp_face, { global_lface = make_vector (LFACE_VECTOR_SIZE, Qunspecified); ASET (global_lface, 0, Qface); - Vface_new_frame_defaults = Fcons (Fcons (face, global_lface), - Vface_new_frame_defaults); + Fputhash (face, global_lface, Vface_new_frame_defaults); /* Assign the new Lisp face a unique ID. The mapping from Lisp face id to Lisp face is given by the vector lface_id_to_name. @@ -2763,7 +2760,7 @@ DEFUN ("internal-make-lisp-face", Finternal_make_lisp_face, { lface = make_vector (LFACE_VECTOR_SIZE, Qunspecified); ASET (lface, 0, Qface); - fset_face_alist (f, Fcons (Fcons (face, lface), f->face_alist)); + Fputhash (face, lface, f->face_map); } else for (i = 1; i < LFACE_VECTOR_SIZE; ++i) @@ -3508,7 +3505,7 @@ update_face_from_frame_parameter (struct frame *f, Lisp_Object param, /* If there are no faces yet, give up. This is the case when called from Fx_create_frame, and we do the necessary things later in face-set-after-frame-defaults. */ - if (NILP (f->face_alist)) + if (XFIXNAT (Fhash_table_count (f->face_map)) == 0) return; if (EQ (param, Qforeground_color)) @@ -4174,14 +4171,13 @@ DEFUN ("internal-lisp-face-empty-p", Finternal_lisp_face_empty_p, return i == LFACE_VECTOR_SIZE ? Qt : Qnil; } - -DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, +DEFUN ("frame-face-map", Fframe_face_map, Sframe_face_map, 0, 1, 0, - doc: /* Return an alist of frame-local faces defined on FRAME. + doc: /* Return a hash table of frame-local faces defined on FRAME. For internal use only. */) (Lisp_Object frame) { - return decode_live_frame (frame)->face_alist; + return decode_live_frame (frame)->face_map; } @@ -6678,30 +6674,37 @@ DEFUN ("show-face-resources", Fshow_face_resources, Sshow_face_resources, #ifdef HAVE_PDUMPER /* All the faces defined during loadup are recorded in - face-new-frame-defaults, with the last face first in the list. We - need to set next_lface_id to the next face ID number, so that any - new faces defined in this session will have face IDs different from - those defined during loadup. We also need to set up the - lface_id_to_name[] array for the faces that were defined during - loadup. */ + face-new-frame-defaults. We need to set next_lface_id to the next + face ID number, so that any new faces defined in this session will + have face IDs different from those defined during loadup. We also + need to set up the lface_id_to_name[] array for the faces that were + defined during loadup. */ void init_xfaces (void) { - if (CONSP (Vface_new_frame_defaults)) + int nfaces = XFIXNAT (Fhash_table_count (Vface_new_frame_defaults)); + if (nfaces > 0) { /* Allocate the lface_id_to_name[] array. */ - lface_id_to_name_size = next_lface_id = - XFIXNAT (Flength (Vface_new_frame_defaults)); + lface_id_to_name_size = next_lface_id = nfaces; lface_id_to_name = xnmalloc (next_lface_id, sizeof *lface_id_to_name); /* Store the faces. */ - Lisp_Object tail; - int i = next_lface_id - 1; - for (tail = Vface_new_frame_defaults; CONSP (tail); tail = XCDR (tail)) + struct Lisp_Hash_Table* table = XHASH_TABLE (Vface_new_frame_defaults); + for (ptrdiff_t idx = 0; idx < nfaces; ++idx) { - Lisp_Object lface = XCAR (tail); - eassert (i >= 0); - lface_id_to_name[i--] = XCAR (lface); + Lisp_Object lface = HASH_KEY (table, idx); + Lisp_Object face_id = Fget (lface, Qface); + // FIXME why is (get 'tab-line 'face) 0? + if (!FIXNATP (face_id)) + // FIXME: I'm not sure what to do in this case + printf ("Face %s has no id\n", SDATA (SYMBOL_NAME (lface))); + else + { + int id = XFIXNAT (face_id); + eassert (id >= 0); + lface_id_to_name[id] = lface; + } } } face_attr_sym[0] = Qface; @@ -6855,7 +6858,7 @@ syms_of_xfaces (void) defsubr (&Sinternal_copy_lisp_face); defsubr (&Sinternal_merge_in_global_face); defsubr (&Sface_font); - defsubr (&Sframe_face_alist); + defsubr (&Sframe_face_map); defsubr (&Sdisplay_supports_face_attributes_p); defsubr (&Scolor_distance); defsubr (&Sinternal_set_font_selection_order); @@ -6881,7 +6884,9 @@ syms_of_xfaces (void) DEFVAR_LISP ("face-new-frame-defaults", Vface_new_frame_defaults, doc: /* List of global face definitions (for internal use only.) */); - Vface_new_frame_defaults = Qnil; + Vface_new_frame_defaults = + make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE, + DEFAULT_REHASH_THRESHOLD, Qnil, false); DEFVAR_LISP ("face-default-stipple", Vface_default_stipple, doc: /* Default stipple pattern used on monochrome displays. -- 2.17.1 --------------BE1646C852BDDA7C590FE83E--