aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYuuki Harano2021-11-11 00:39:53 +0900
committerYuuki Harano2021-11-11 00:39:53 +0900
commit4dd1f56f29fc598a8339a345c2f8945250600602 (patch)
treeaf341efedffe027e533b1bcc0dbf270532e48285 /src
parent4c49ec7f865bdad1629d2f125f71f4e506b258f2 (diff)
parent810fa21d26453f898de9747ece7205dfe6de9d08 (diff)
downloademacs-4dd1f56f29fc598a8339a345c2f8945250600602.tar.gz
emacs-4dd1f56f29fc598a8339a345c2f8945250600602.zip
Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs into feature/pgtk
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in79
-rw-r--r--src/alloc.c46
-rw-r--r--src/atimer.c42
-rw-r--r--src/bidi.c29
-rw-r--r--src/buffer.c83
-rw-r--r--src/buffer.h11
-rw-r--r--src/callint.c10
-rw-r--r--src/callproc.c2
-rw-r--r--src/casefiddle.c57
-rw-r--r--src/character.h2
-rw-r--r--src/cmds.c2
-rw-r--r--src/coding.c47
-rw-r--r--src/comp.c369
-rw-r--r--src/composite.c55
-rw-r--r--src/composite.h4
-rw-r--r--src/conf_post.h1
-rw-r--r--src/data.c4
-rw-r--r--src/dispextern.h18
-rw-r--r--src/dispnew.c21
-rw-r--r--src/editfns.c7
-rw-r--r--src/emacs-module.h.in13
-rw-r--r--src/emacs.c50
-rw-r--r--src/eval.c97
-rw-r--r--src/fileio.c8
-rw-r--r--src/fns.c24
-rw-r--r--src/font.c155
-rw-r--r--src/font.h2
-rw-r--r--src/fontset.c6
-rw-r--r--src/frame.c45
-rw-r--r--src/frame.h4
-rw-r--r--src/fringe.c10
-rw-r--r--src/gtkutil.c51
-rw-r--r--src/image.c466
-rw-r--r--src/insdel.c9
-rw-r--r--src/intervals.c20
-rw-r--r--src/keyboard.c303
-rw-r--r--src/keyboard.h2
-rw-r--r--src/keymap.c278
-rw-r--r--src/lisp.h76
-rw-r--r--src/lread.c187
-rw-r--r--src/macfont.m44
-rw-r--r--src/menu.c23
-rw-r--r--src/minibuf.c151
-rw-r--r--src/module-env-28.h4
-rw-r--r--src/module-env-29.h3
-rw-r--r--src/msdos.c2
-rw-r--r--src/nsfns.m80
-rw-r--r--src/nsfont.m1215
-rw-r--r--src/nsimage.m49
-rw-r--r--src/nsmenu.m122
-rw-r--r--src/nsterm.h102
-rw-r--r--src/nsterm.m1990
-rw-r--r--src/pdumper.c53
-rw-r--r--src/pdumper.h5
-rw-r--r--src/print.c30
-rw-r--r--src/process.c63
-rw-r--r--src/regex-emacs.c4
-rw-r--r--src/search.c101
-rw-r--r--src/syntax.c10
-rw-r--r--src/sysstdio.h2
-rw-r--r--src/systhread.h13
-rw-r--r--src/term.c35
-rw-r--r--src/termchar.h4
-rw-r--r--src/termhooks.h2
-rw-r--r--src/timefns.c5
-rw-r--r--src/unexcw.c6
-rw-r--r--src/verbose.mk.in4
-rw-r--r--src/vm-limit.c2
-rw-r--r--src/w16select.c2
-rw-r--r--src/w32.c69
-rw-r--r--src/w32.h9
-rw-r--r--src/w32fns.c148
-rw-r--r--src/w32font.c4
-rw-r--r--src/w32heap.c42
-rw-r--r--src/w32inevt.c6
-rw-r--r--src/w32proc.c10
-rw-r--r--src/w32term.c79
-rw-r--r--src/window.c68
-rw-r--r--src/xdisp.c604
-rw-r--r--src/xfaces.c24
-rw-r--r--src/xfns.c17
-rw-r--r--src/xmenu.c8
-rw-r--r--src/xterm.c259
-rw-r--r--src/xterm.h1
-rw-r--r--src/xwidget.c1492
-rw-r--r--src/xwidget.h29
86 files changed, 6720 insertions, 2970 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 8c28e825da2..d646001ccea 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -55,6 +55,8 @@ lwlibdir = ../lwlib
55# Configuration files for .o files to depend on. 55# Configuration files for .o files to depend on.
56config_h = config.h $(srcdir)/conf_post.h 56config_h = config.h $(srcdir)/conf_post.h
57 57
58HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
59
58## ns-app if NS self contained app, else empty. 60## ns-app if NS self contained app, else empty.
59OTHER_FILES = @OTHER_FILES@ 61OTHER_FILES = @OTHER_FILES@
60 62
@@ -122,7 +124,7 @@ LIB_MATH=@LIB_MATH@
122## -lpthread, or empty. 124## -lpthread, or empty.
123LIB_PTHREAD=@LIB_PTHREAD@ 125LIB_PTHREAD=@LIB_PTHREAD@
124 126
125LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ 127LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@
126 128
127XCB_LIBS=@XCB_LIBS@ 129XCB_LIBS=@XCB_LIBS@
128XFT_LIBS=@XFT_LIBS@ 130XFT_LIBS=@XFT_LIBS@
@@ -221,6 +223,8 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
221RSVG_LIBS= @RSVG_LIBS@ 223RSVG_LIBS= @RSVG_LIBS@
222RSVG_CFLAGS= @RSVG_CFLAGS@ 224RSVG_CFLAGS= @RSVG_CFLAGS@
223 225
226WEBP_CFLAGS= @WEBP_CFLAGS@
227
224WEBKIT_LIBS= @WEBKIT_LIBS@ 228WEBKIT_LIBS= @WEBKIT_LIBS@
225WEBKIT_CFLAGS= @WEBKIT_CFLAGS@ 229WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
226 230
@@ -329,7 +333,8 @@ GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
329 333
330LIBGMP = @LIBGMP@ 334LIBGMP = @LIBGMP@
331 335
332LIBGCCJIT = @LIBGCCJIT_LIB@ 336LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@
337LIBGCCJIT_CFLAGS = @LIBGCCJIT_CFLAGS@
333 338
334## dynlib.o if necessary, else empty 339## dynlib.o if necessary, else empty
335DYNLIB_OBJ = @DYNLIB_OBJ@ 340DYNLIB_OBJ = @DYNLIB_OBJ@
@@ -370,9 +375,9 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
370 -I$(lib) -I$(top_srcdir)/lib \ 375 -I$(lib) -I$(top_srcdir)/lib \
371 $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ 376 $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
372 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ 377 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
373 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ 378 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(LIBGCCJIT_CFLAGS) $(DBUS_CFLAGS) \
374 $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \ 379 $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
375 $(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \ 380 $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \
376 $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ 381 $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
377 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ 382 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
378 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ 383 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
@@ -451,6 +456,9 @@ ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
451 456
452# Must be first, before dep inclusion! 457# Must be first, before dep inclusion!
453all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) 458all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES)
459ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
460all: ../native-lisp
461endif
454.PHONY: all 462.PHONY: all
455 463
456dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \ 464dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \
@@ -519,7 +527,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE
519 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ 527 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
520 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ 528 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
521 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ 529 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
522 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT) 530 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS)
523 531
524## FORCE it so that admin/unidata can decide whether this file is 532## FORCE it so that admin/unidata can decide whether this file is
525## up-to-date. Although since charprop depends on bootstrap-emacs, 533## up-to-date. Although since charprop depends on bootstrap-emacs,
@@ -547,7 +555,13 @@ charscript = ${lispintdir}/charscript.el
547${charscript}: FORCE 555${charscript}: FORCE
548 $(MAKE) -C ../admin/unidata $(notdir $@) 556 $(MAKE) -C ../admin/unidata $(notdir $@)
549 557
550${lispintdir}/characters.elc: ${charscript:.el=.elc} 558emoji-zwj = ${lispintdir}/emoji-zwj.el
559${emoji-zwj}: FORCE
560 $(MAKE) -C ../admin/unidata $(notdir $@)
561
562${lispintdir}/characters.elc: ${charscript:.el=.elc} ${emoji-zwj:.el=.elc}
563
564SYSTEM_TYPE = @SYSTEM_TYPE@
551 565
552## The dumped Emacs is as functional and more efficient than 566## The dumped Emacs is as functional and more efficient than
553## bootstrap-emacs, so we replace the latter with the former. 567## bootstrap-emacs, so we replace the latter with the former.
@@ -557,6 +571,9 @@ ${lispintdir}/characters.elc: ${charscript:.el=.elc}
557emacs$(EXEEXT): temacs$(EXEEXT) \ 571emacs$(EXEEXT): temacs$(EXEEXT) \
558 lisp.mk $(etc)/DOC $(lisp) \ 572 lisp.mk $(etc)/DOC $(lisp) \
559 $(lispsource)/international/charprop.el ${charsets} 573 $(lispsource)/international/charprop.el ${charsets}
574ifeq ($(SYSTEM_TYPE),cygwin)
575 find ${top_builddir} -name '*.eln' | rebase -v -O -T -
576endif
560ifeq ($(DUMPING),unexec) 577ifeq ($(DUMPING),unexec)
561 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=dump 578 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=dump
562 ifneq ($(PAXCTL_dumped),) 579 ifneq ($(PAXCTL_dumped),)
@@ -631,7 +648,7 @@ endif
631## This goes on to affect various things, and the emacs binary fails 648## This goes on to affect various things, and the emacs binary fails
632## to start if Vinstallation_directory has the wrong value. 649## to start if Vinstallation_directory has the wrong value.
633temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ 650temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \
634 $(charsets) $(charscript) $(MAKE_PDUMPER_FINGERPRINT) 651 $(charsets) $(charscript) ${emoji-zwj} $(MAKE_PDUMPER_FINGERPRINT)
635 $(AM_V_CCLD)$(CC) -o $@.tmp \ 652 $(AM_V_CCLD)$(CC) -o $@.tmp \
636 $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \ 653 $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(LDFLAGS) \
637 $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES) 654 $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(W32_RES_LINK) $(LIBES)
@@ -768,6 +785,51 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS
768 @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="$(bootstrap_exe)"\ 785 @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="$(bootstrap_exe)"\
769 THEFILE=$< $<c 786 THEFILE=$< $<c
770 787
788ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
789## The following rules are used only when building a source tarball
790## for the first time, when the native-lisp/ directory doesn't yet
791## exist and needs to be created and populated with the preloaded
792## *.eln files.
793
794## List of *.eln files we need to produce in addition to the preloaded
795## ones in $(lisp).
796elnlisp := \
797 emacs-lisp/autoload.eln \
798 emacs-lisp/byte-opt.eln \
799 emacs-lisp/bytecomp.eln \
800 emacs-lisp/cconv.eln \
801 international/charscript.eln \
802 emacs-lisp/comp.eln \
803 emacs-lisp/comp-cstr.eln \
804 international/emoji-zwj.eln
805elnlisp := $(addprefix ${lispsource}/,${elnlisp}) $(lisp:.elc=.eln)
806
807%.eln: %.el | emacs$(EXEEXT) $(pdmp)
808 @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="../src/emacs$(EXEEXT)"\
809 THEFILE=$< $<n
810
811## FIXME: this is fragile! We lie to Make about the files produced by
812## this rule, and we rely on the absence of the native-lisp directory
813## to trigger it. This means that if anything goes wrong during
814## native compilation, the only way to trigger it again is to remove
815## the directory and re-native-compile everything. The main
816## underlying problem is that the name of the subdirectory of
817## native-lisp where the *.eln files will be produced, and the exact
818## names of those *.eln files, cannot be known in advance; we must ask
819## Emacs to produce them.
820../native-lisp: | $(pdmp)
821 @if test ! -d $@; then \
822 mkdir $@ && $(MAKE) $(AM_V_NO_PD) $(elnlisp); \
823 if test $(SYSTEM_TYPE) = cygwin; then \
824 find $@ -name '*.eln' | rebase -v -O -T -; \
825 fi; \
826 LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \
827 --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) \
828 && cp -f emacs$(EXEEXT) bootstrap-emacs$(EXEEXT) \
829 && cp -f $(pdmp) $(bootstrap_pdmp); \
830 fi
831endif
832
771## VCSWITNESS points to the file that holds info about the current checkout. 833## VCSWITNESS points to the file that holds info about the current checkout.
772## We use it as a heuristic to decide when to rebuild loaddefs.el. 834## We use it as a heuristic to decide when to rebuild loaddefs.el.
773## If empty it is ignored; the parent makefile can set it to some other value. 835## If empty it is ignored; the parent makefile can set it to some other value.
@@ -793,6 +855,9 @@ ifeq ($(DUMPING),unexec)
793else 855else
794 @: In the pdumper case, make compile-first after the dump 856 @: In the pdumper case, make compile-first after the dump
795 cp -f temacs$(EXEEXT) bootstrap-emacs$(EXEEXT) 857 cp -f temacs$(EXEEXT) bootstrap-emacs$(EXEEXT)
858ifeq ($(DO_CODESIGN),yes)
859 codesign -s - -f bootstrap-emacs$(EXEEXT)
860endif
796endif 861endif
797 862
798ifeq ($(DUMPING),pdumper) 863ifeq ($(DUMPING),pdumper)
diff --git a/src/alloc.c b/src/alloc.c
index ff3670eeb1d..2d25f8205ae 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -765,7 +765,7 @@ xmalloc (size_t size)
765 val = lmalloc (size, false); 765 val = lmalloc (size, false);
766 MALLOC_UNBLOCK_INPUT; 766 MALLOC_UNBLOCK_INPUT;
767 767
768 if (!val && size) 768 if (!val)
769 memory_full (size); 769 memory_full (size);
770 MALLOC_PROBE (size); 770 MALLOC_PROBE (size);
771 return val; 771 return val;
@@ -782,7 +782,7 @@ xzalloc (size_t size)
782 val = lmalloc (size, true); 782 val = lmalloc (size, true);
783 MALLOC_UNBLOCK_INPUT; 783 MALLOC_UNBLOCK_INPUT;
784 784
785 if (!val && size) 785 if (!val)
786 memory_full (size); 786 memory_full (size);
787 MALLOC_PROBE (size); 787 MALLOC_PROBE (size);
788 return val; 788 return val;
@@ -796,15 +796,15 @@ xrealloc (void *block, size_t size)
796 void *val; 796 void *val;
797 797
798 MALLOC_BLOCK_INPUT; 798 MALLOC_BLOCK_INPUT;
799 /* We must call malloc explicitly when BLOCK is 0, since some 799 /* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
800 reallocs don't do this. */ 800 platforms lacking support for realloc (NULL, size). */
801 if (! block) 801 if (! block)
802 val = lmalloc (size, false); 802 val = lmalloc (size, false);
803 else 803 else
804 val = lrealloc (block, size); 804 val = lrealloc (block, size);
805 MALLOC_UNBLOCK_INPUT; 805 MALLOC_UNBLOCK_INPUT;
806 806
807 if (!val && size) 807 if (!val)
808 memory_full (size); 808 memory_full (size);
809 MALLOC_PROBE (size); 809 MALLOC_PROBE (size);
810 return val; 810 return val;
@@ -1030,7 +1030,7 @@ lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
1030#endif 1030#endif
1031 1031
1032 MALLOC_UNBLOCK_INPUT; 1032 MALLOC_UNBLOCK_INPUT;
1033 if (!val && nbytes) 1033 if (!val)
1034 memory_full (nbytes); 1034 memory_full (nbytes);
1035 MALLOC_PROBE (nbytes); 1035 MALLOC_PROBE (nbytes);
1036 return val; 1036 return val;
@@ -1329,16 +1329,20 @@ laligned (void *p, size_t size)
1329 || size % LISP_ALIGNMENT != 0); 1329 || size % LISP_ALIGNMENT != 0);
1330} 1330}
1331 1331
1332/* Like malloc and realloc except that if SIZE is Lisp-aligned, make 1332/* Like malloc and realloc except return null only on failure,
1333 sure the result is too, if necessary by reallocating (typically 1333 the result is Lisp-aligned if SIZE is, and lrealloc's pointer
1334 with larger and larger sizes) until the allocator returns a 1334 argument must be nonnull. Code allocating C heap memory
1335 Lisp-aligned pointer. Code that needs to allocate C heap memory
1336 for a Lisp object should use one of these functions to obtain a 1335 for a Lisp object should use one of these functions to obtain a
1337 pointer P; that way, if T is an enum Lisp_Type value and L == 1336 pointer P; that way, if T is an enum Lisp_Type value and L ==
1338 make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T. 1337 make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
1339 1338
1339 If CLEARIT, arrange for the allocated memory to be cleared.
1340 This might use calloc, as calloc can be faster than malloc+memset.
1341
1340 On typical modern platforms these functions' loops do not iterate. 1342 On typical modern platforms these functions' loops do not iterate.
1341 On now-rare (and perhaps nonexistent) platforms, the loops in 1343 On now-rare (and perhaps nonexistent) platforms, the code can loop,
1344 reallocating (typically with larger and larger sizes) until the
1345 allocator returns a Lisp-aligned pointer. This loop in
1342 theory could repeat forever. If an infinite loop is possible on a 1346 theory could repeat forever. If an infinite loop is possible on a
1343 platform, a build would surely loop and the builder can then send 1347 platform, a build would surely loop and the builder can then send
1344 us a bug report. Adding a counter to try to detect any such loop 1348 us a bug report. Adding a counter to try to detect any such loop
@@ -1352,8 +1356,13 @@ lmalloc (size_t size, bool clearit)
1352 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0) 1356 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
1353 { 1357 {
1354 void *p = aligned_alloc (LISP_ALIGNMENT, size); 1358 void *p = aligned_alloc (LISP_ALIGNMENT, size);
1355 if (clearit && p) 1359 if (p)
1356 memclear (p, size); 1360 {
1361 if (clearit)
1362 memclear (p, size);
1363 }
1364 else if (! (MALLOC_0_IS_NONNULL || size))
1365 return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
1357 return p; 1366 return p;
1358 } 1367 }
1359#endif 1368#endif
@@ -1361,7 +1370,7 @@ lmalloc (size_t size, bool clearit)
1361 while (true) 1370 while (true)
1362 { 1371 {
1363 void *p = clearit ? calloc (1, size) : malloc (size); 1372 void *p = clearit ? calloc (1, size) : malloc (size);
1364 if (laligned (p, size)) 1373 if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
1365 return p; 1374 return p;
1366 free (p); 1375 free (p);
1367 size_t bigger = size + LISP_ALIGNMENT; 1376 size_t bigger = size + LISP_ALIGNMENT;
@@ -1376,7 +1385,7 @@ lrealloc (void *p, size_t size)
1376 while (true) 1385 while (true)
1377 { 1386 {
1378 p = realloc (p, size); 1387 p = realloc (p, size);
1379 if (laligned (p, size)) 1388 if (laligned (p, size) && (size || p))
1380 return p; 1389 return p;
1381 size_t bigger = size + LISP_ALIGNMENT; 1390 size_t bigger = size + LISP_ALIGNMENT;
1382 if (size < bigger) 1391 if (size < bigger)
@@ -1929,8 +1938,7 @@ allocate_string_data (struct Lisp_String *s,
1929 The character is at byte offset CIDX_BYTE in the string. 1938 The character is at byte offset CIDX_BYTE in the string.
1930 The character being replaced is CLEN bytes long, 1939 The character being replaced is CLEN bytes long,
1931 and the character that will replace it is NEW_CLEN bytes long. 1940 and the character that will replace it is NEW_CLEN bytes long.
1932 Return the address of where the caller should store the 1941 Return the address where the caller should store the new character. */
1933 the new character. */
1934 1942
1935unsigned char * 1943unsigned char *
1936resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte, 1944resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte,
@@ -7321,7 +7329,7 @@ Frames, windows, buffers, and subprocesses count as vectors
7321 make_int (strings_consed)); 7329 make_int (strings_consed));
7322} 7330}
7323 7331
7324#ifdef GNU_LINUX 7332#if defined GNU_LINUX && defined __GLIBC__
7325DEFUN ("malloc-info", Fmalloc_info, Smalloc_info, 0, 0, "", 7333DEFUN ("malloc-info", Fmalloc_info, Smalloc_info, 0, 0, "",
7326 doc: /* Report malloc information to stderr. 7334 doc: /* Report malloc information to stderr.
7327This function outputs to stderr an XML-formatted 7335This function outputs to stderr an XML-formatted
@@ -7681,7 +7689,7 @@ N should be nonnegative. */);
7681 defsubr (&Sgarbage_collect_maybe); 7689 defsubr (&Sgarbage_collect_maybe);
7682 defsubr (&Smemory_info); 7690 defsubr (&Smemory_info);
7683 defsubr (&Smemory_use_counts); 7691 defsubr (&Smemory_use_counts);
7684#ifdef GNU_LINUX 7692#if defined GNU_LINUX && defined __GLIBC__
7685 defsubr (&Smalloc_info); 7693 defsubr (&Smalloc_info);
7686#endif 7694#endif
7687 defsubr (&Ssuspicious_object); 7695 defsubr (&Ssuspicious_object);
diff --git a/src/atimer.c b/src/atimer.c
index d12eb4ad1ea..197b504bf51 100644
--- a/src/atimer.c
+++ b/src/atimer.c
@@ -305,20 +305,25 @@ set_alarm (void)
305#ifdef HAVE_ITIMERSPEC 305#ifdef HAVE_ITIMERSPEC
306 if (0 <= timerfd || alarm_timer_ok) 306 if (0 <= timerfd || alarm_timer_ok)
307 { 307 {
308 bool exit = false;
308 struct itimerspec ispec; 309 struct itimerspec ispec;
309 ispec.it_value = atimers->expiration; 310 ispec.it_value = atimers->expiration;
310 ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; 311 ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0;
311# ifdef HAVE_TIMERFD 312# ifdef HAVE_TIMERFD
312 if (timerfd >= 0) { 313 if (timerfd >= 0)
313 if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0) 314 {
314 { 315 if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0)
315 add_timer_wait_descriptor (timerfd); 316 {
316 return; 317 add_timer_wait_descriptor (timerfd);
317 } 318 exit = true;
318 } 319 }
320 }
319# endif 321# endif
320 if (alarm_timer_ok 322 if (alarm_timer_ok
321 && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) 323 && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0)
324 exit = true;
325
326 if (exit)
322 return; 327 return;
323 } 328 }
324#endif 329#endif
@@ -335,9 +340,8 @@ set_alarm (void)
335 memset (&it, 0, sizeof it); 340 memset (&it, 0, sizeof it);
336 it.it_value = make_timeval (interval); 341 it.it_value = make_timeval (interval);
337 setitimer (ITIMER_REAL, &it, 0); 342 setitimer (ITIMER_REAL, &it, 0);
338#else /* not HAVE_SETITIMER */
339 alarm (max (interval.tv_sec, 1));
340#endif /* not HAVE_SETITIMER */ 343#endif /* not HAVE_SETITIMER */
344 alarm (max (interval.tv_sec, 1));
341 } 345 }
342} 346}
343 347
@@ -589,15 +593,17 @@ init_atimer (void)
589 timerfd = (egetenv ("EMACS_IGNORE_TIMERFD") || have_buggy_timerfd () ? -1 : 593 timerfd = (egetenv ("EMACS_IGNORE_TIMERFD") || have_buggy_timerfd () ? -1 :
590 timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC)); 594 timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC));
591# endif 595# endif
592 if (timerfd < 0) 596 /* We're starting the alarms even if we have timerfd, because
593 { 597 timerfd events do not fire while Emacs Lisp is busy and doesn't
594 struct sigevent sigev; 598 call thread_select. This might or might not mean that the
595 sigev.sigev_notify = SIGEV_SIGNAL; 599 timerfd code doesn't really give us anything and should be
596 sigev.sigev_signo = SIGALRM; 600 removed, see discussion in bug#19776. */
597 sigev.sigev_value.sival_ptr = &alarm_timer; 601 struct sigevent sigev;
598 alarm_timer_ok 602 sigev.sigev_notify = SIGEV_SIGNAL;
599 = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; 603 sigev.sigev_signo = SIGALRM;
600 } 604 sigev.sigev_value.sival_ptr = &alarm_timer;
605 alarm_timer_ok
606 = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0;
601#endif 607#endif
602 free_atimers = stopped_atimers = atimers = NULL; 608 free_atimers = stopped_atimers = atimers = NULL;
603 609
diff --git a/src/bidi.c b/src/bidi.c
index 1413ba6b888..890a60acc43 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -3564,11 +3564,19 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
3564} 3564}
3565 3565
3566/* Utility function for looking for strong directional characters 3566/* Utility function for looking for strong directional characters
3567 whose bidi type was overridden by a directional override. */ 3567 whose bidi type was overridden by directional override or embedding
3568 or isolate control characters. */
3568ptrdiff_t 3569ptrdiff_t
3569bidi_find_first_overridden (struct bidi_it *bidi_it) 3570bidi_find_first_overridden (struct bidi_it *bidi_it)
3570{ 3571{
3571 ptrdiff_t found_pos = ZV; 3572 ptrdiff_t found_pos = ZV;
3573 /* Maximum bidi levels we allow for L2R and R2L characters. Note
3574 that these are levels after resolving explicit embeddings,
3575 overrides, and isolates, i.e. before resolving implicit levels. */
3576 int max_l2r = bidi_it->paragraph_dir == L2R ? 0 : 2;
3577 int max_r2l = 1;
3578 /* Same for WEAK and NEUTRAL_ON types. */
3579 int max_weak = bidi_it->paragraph_dir == L2R ? 1 : 2;
3572 3580
3573 do 3581 do
3574 { 3582 {
@@ -3576,11 +3584,28 @@ bidi_find_first_overridden (struct bidi_it *bidi_it)
3576 because the directional overrides are applied by the 3584 because the directional overrides are applied by the
3577 former. */ 3585 former. */
3578 bidi_type_t type = bidi_resolve_weak (bidi_it); 3586 bidi_type_t type = bidi_resolve_weak (bidi_it);
3587 unsigned level = bidi_it->level_stack[bidi_it->stack_idx].level;
3588 bidi_category_t category = bidi_get_category (bidi_it->orig_type);
3579 3589
3590 /* Detect strong L or R types that have been overridden by
3591 explicit overrides. */
3580 if ((type == STRONG_R && bidi_it->orig_type == STRONG_L) 3592 if ((type == STRONG_R && bidi_it->orig_type == STRONG_L)
3581 || (type == STRONG_L 3593 || (type == STRONG_L
3582 && (bidi_it->orig_type == STRONG_R 3594 && (bidi_it->orig_type == STRONG_R
3583 || bidi_it->orig_type == STRONG_AL))) 3595 || bidi_it->orig_type == STRONG_AL))
3596 /* Detect strong L or R types or WEAK_EN types that were
3597 pushed into higher embedding levels (and will thus
3598 reorder) by explicit embeddings and isolates. */
3599 || ((bidi_it->orig_type == STRONG_L
3600 || bidi_it->orig_type == WEAK_EN)
3601 && level > max_l2r)
3602 || ((bidi_it->orig_type == STRONG_R
3603 || bidi_it->orig_type == STRONG_AL)
3604 && level > max_r2l)
3605 /* Detect other weak or neutral types whose level was
3606 tweaked by explicit embeddings and isolates. */
3607 || ((category == WEAK || bidi_it->orig_type == NEUTRAL_ON)
3608 && level > max_weak))
3584 found_pos = bidi_it->charpos; 3609 found_pos = bidi_it->charpos;
3585 } while (found_pos == ZV 3610 } while (found_pos == ZV
3586 && bidi_it->charpos < ZV 3611 && bidi_it->charpos < ZV
diff --git a/src/buffer.c b/src/buffer.c
index b177c5eaa7f..9d8892a797a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1434,7 +1434,7 @@ and `buffer-file-truename' are non-nil. */)
1434DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p, 1434DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
1435 Srestore_buffer_modified_p, 1, 1, 0, 1435 Srestore_buffer_modified_p, 1, 1, 0,
1436 doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line. 1436 doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line.
1437This function also locks and unlocks the file visited by the buffer, 1437This function also locks or unlocks the file visited by the buffer,
1438if both `buffer-file-truename' and `buffer-file-name' are non-nil. 1438if both `buffer-file-truename' and `buffer-file-name' are non-nil.
1439 1439
1440It is not ensured that mode lines will be updated to show the modified 1440It is not ensured that mode lines will be updated to show the modified
@@ -1768,6 +1768,7 @@ cleaning up all windows currently displaying the buffer to be killed. */)
1768 /* Run hooks with the buffer to be killed as the current buffer. */ 1768 /* Run hooks with the buffer to be killed as the current buffer. */
1769 { 1769 {
1770 ptrdiff_t count = SPECPDL_INDEX (); 1770 ptrdiff_t count = SPECPDL_INDEX ();
1771 bool modified;
1771 1772
1772 record_unwind_protect_excursion (); 1773 record_unwind_protect_excursion ();
1773 set_buffer_internal (b); 1774 set_buffer_internal (b);
@@ -1782,9 +1783,12 @@ cleaning up all windows currently displaying the buffer to be killed. */)
1782 return unbind_to (count, Qnil); 1783 return unbind_to (count, Qnil);
1783 } 1784 }
1784 1785
1786 /* Is this a modified buffer that's visiting a file? */
1787 modified = !NILP (BVAR (b, filename))
1788 && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b);
1789
1785 /* Query if the buffer is still modified. */ 1790 /* Query if the buffer is still modified. */
1786 if (INTERACTIVE && !NILP (BVAR (b, filename)) 1791 if (INTERACTIVE && modified)
1787 && BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
1788 { 1792 {
1789 AUTO_STRING (format, "Buffer %s modified; kill anyway? "); 1793 AUTO_STRING (format, "Buffer %s modified; kill anyway? ");
1790 tem = do_yes_or_no_p (CALLN (Fformat, format, BVAR (b, name))); 1794 tem = do_yes_or_no_p (CALLN (Fformat, format, BVAR (b, name)));
@@ -1792,6 +1796,23 @@ cleaning up all windows currently displaying the buffer to be killed. */)
1792 return unbind_to (count, Qnil); 1796 return unbind_to (count, Qnil);
1793 } 1797 }
1794 1798
1799 /* Delete the autosave file, if requested. */
1800 if (modified
1801 && kill_buffer_delete_auto_save_files
1802 && delete_auto_save_files
1803 && !NILP (Frecent_auto_save_p ())
1804 && STRINGP (BVAR (b, auto_save_file_name))
1805 && !NILP (Ffile_exists_p (BVAR (b, auto_save_file_name)))
1806 /* If `auto-save-visited-mode' is on, then we're auto-saving
1807 to the visited file -- don't delete it.. */
1808 && NILP (Fstring_equal (BVAR (b, auto_save_file_name),
1809 BVAR (b, filename))))
1810 {
1811 tem = do_yes_or_no_p (build_string ("Delete auto-save file? "));
1812 if (!NILP (tem))
1813 call0 (intern ("delete-auto-save-file-if-necessary"));
1814 }
1815
1795 /* If the hooks have killed the buffer, exit now. */ 1816 /* If the hooks have killed the buffer, exit now. */
1796 if (!BUFFER_LIVE_P (b)) 1817 if (!BUFFER_LIVE_P (b))
1797 return unbind_to (count, Qt); 1818 return unbind_to (count, Qt);
@@ -1888,24 +1909,6 @@ cleaning up all windows currently displaying the buffer to be killed. */)
1888 replace_buffer_in_windows_safely (buffer); 1909 replace_buffer_in_windows_safely (buffer);
1889 Vinhibit_quit = tem; 1910 Vinhibit_quit = tem;
1890 1911
1891 /* Delete any auto-save file, if we saved it in this session.
1892 But not if the buffer is modified. */
1893 if (STRINGP (BVAR (b, auto_save_file_name))
1894 && BUF_AUTOSAVE_MODIFF (b) != 0
1895 && BUF_SAVE_MODIFF (b) < BUF_AUTOSAVE_MODIFF (b)
1896 && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
1897 && NILP (Fsymbol_value (intern ("auto-save-visited-file-name"))))
1898 {
1899 Lisp_Object delete;
1900 delete = Fsymbol_value (intern ("delete-auto-save-files"));
1901 if (! NILP (delete))
1902 internal_delete_file (BVAR (b, auto_save_file_name));
1903 }
1904
1905 /* Deleting an auto-save file could have killed our buffer. */
1906 if (!BUFFER_LIVE_P (b))
1907 return Qt;
1908
1909 if (b->base_buffer) 1912 if (b->base_buffer)
1910 { 1913 {
1911 INTERVAL i; 1914 INTERVAL i;
@@ -2802,7 +2805,7 @@ current buffer is cleared. */)
2802} 2805}
2803 2806
2804DEFUN ("kill-all-local-variables", Fkill_all_local_variables, 2807DEFUN ("kill-all-local-variables", Fkill_all_local_variables,
2805 Skill_all_local_variables, 0, 0, 0, 2808 Skill_all_local_variables, 0, 1, 0,
2806 doc: /* Switch to Fundamental mode by killing current buffer's local variables. 2809 doc: /* Switch to Fundamental mode by killing current buffer's local variables.
2807Most local variable bindings are eliminated so that the default values 2810Most local variable bindings are eliminated so that the default values
2808become effective once more. Also, the syntax table is set from 2811become effective once more. Also, the syntax table is set from
@@ -2813,18 +2816,20 @@ This function also forces redisplay of the mode line.
2813Every function to select a new major mode starts by 2816Every function to select a new major mode starts by
2814calling this function. 2817calling this function.
2815 2818
2816As a special exception, local variables whose names have 2819As a special exception, local variables whose names have a non-nil
2817a non-nil `permanent-local' property are not eliminated by this function. 2820`permanent-local' property are not eliminated by this function. If
2821the optional KILL-PERMANENT argument is non-nil, clear out these local
2822variables, too.
2818 2823
2819The first thing this function does is run 2824The first thing this function does is run
2820the normal hook `change-major-mode-hook'. */) 2825the normal hook `change-major-mode-hook'. */)
2821 (void) 2826 (Lisp_Object kill_permanent)
2822{ 2827{
2823 run_hook (Qchange_major_mode_hook); 2828 run_hook (Qchange_major_mode_hook);
2824 2829
2825 /* Actually eliminate all local bindings of this buffer. */ 2830 /* Actually eliminate all local bindings of this buffer. */
2826 2831
2827 reset_buffer_local_variables (current_buffer, 0); 2832 reset_buffer_local_variables (current_buffer, !NILP (kill_permanent));
2828 2833
2829 /* Force mode-line redisplay. Useful here because all major mode 2834 /* Force mode-line redisplay. Useful here because all major mode
2830 commands call this function. */ 2835 commands call this function. */
@@ -2995,7 +3000,7 @@ overlays_in (EMACS_INT beg, EMACS_INT end, bool extend,
2995 ptrdiff_t next = ZV; 3000 ptrdiff_t next = ZV;
2996 ptrdiff_t prev = BEGV; 3001 ptrdiff_t prev = BEGV;
2997 bool inhibit_storing = 0; 3002 bool inhibit_storing = 0;
2998 bool end_is_Z = end == Z; 3003 bool end_is_Z = end == ZV;
2999 3004
3000 for (struct Lisp_Overlay *tail = current_buffer->overlays_before; 3005 for (struct Lisp_Overlay *tail = current_buffer->overlays_before;
3001 tail; tail = tail->next) 3006 tail; tail = tail->next)
@@ -3840,7 +3845,9 @@ fix_overlays_before (struct buffer *bp, ptrdiff_t prev, ptrdiff_t pos)
3840 or the found one ends before PREV, 3845 or the found one ends before PREV,
3841 or the found one is the last one in the list, 3846 or the found one is the last one in the list,
3842 we don't have to fix anything. */ 3847 we don't have to fix anything. */
3843 if (!tail || end < prev || !tail->next) 3848 if (!tail)
3849 return;
3850 if (end < prev || !tail->next)
3844 return; 3851 return;
3845 3852
3846 right_pair = parent; 3853 right_pair = parent;
@@ -4268,9 +4275,10 @@ DEFUN ("overlays-in", Foverlays_in, Soverlays_in, 2, 2, 0,
4268 doc: /* Return a list of the overlays that overlap the region BEG ... END. 4275 doc: /* Return a list of the overlays that overlap the region BEG ... END.
4269Overlap means that at least one character is contained within the overlay 4276Overlap means that at least one character is contained within the overlay
4270and also contained within the specified region. 4277and also contained within the specified region.
4278
4271Empty overlays are included in the result if they are located at BEG, 4279Empty overlays are included in the result if they are located at BEG,
4272between BEG and END, or at END provided END denotes the position at the 4280between BEG and END, or at END provided END denotes the position at the
4273end of the buffer. */) 4281end of the accessible part of the buffer. */)
4274 (Lisp_Object beg, Lisp_Object end) 4282 (Lisp_Object beg, Lisp_Object end)
4275{ 4283{
4276 ptrdiff_t len, noverlays; 4284 ptrdiff_t len, noverlays;
@@ -5801,7 +5809,10 @@ Note that this is overridden by the variable
5801`truncate-partial-width-windows' if that variable is non-nil 5809`truncate-partial-width-windows' if that variable is non-nil
5802and this buffer is not full-frame width. 5810and this buffer is not full-frame width.
5803 5811
5804Minibuffers set this variable to nil. */); 5812Minibuffers set this variable to nil.
5813
5814Don't set this to a non-nil value when `visual-line-mode' is
5815turned on, as it could produce confusing results. */);
5805 5816
5806 DEFVAR_PER_BUFFER ("word-wrap", &BVAR (current_buffer, word_wrap), Qnil, 5817 DEFVAR_PER_BUFFER ("word-wrap", &BVAR (current_buffer, word_wrap), Qnil,
5807 doc: /* Non-nil means to use word-wrapping for continuation lines. 5818 doc: /* Non-nil means to use word-wrapping for continuation lines.
@@ -6365,6 +6376,18 @@ nil NORECORD argument since it may lead to infinite recursion. */);
6365 Vbuffer_list_update_hook = Qnil; 6376 Vbuffer_list_update_hook = Qnil;
6366 DEFSYM (Qbuffer_list_update_hook, "buffer-list-update-hook"); 6377 DEFSYM (Qbuffer_list_update_hook, "buffer-list-update-hook");
6367 6378
6379 DEFVAR_BOOL ("kill-buffer-delete-auto-save-files",
6380 kill_buffer_delete_auto_save_files,
6381 doc: /* If non-nil, offer to delete any autosave file when killing a buffer.
6382
6383If `delete-auto-save-files' is nil, any autosave deletion is inhibited. */);
6384 kill_buffer_delete_auto_save_files = 0;
6385
6386 DEFVAR_BOOL ("delete-auto-save-files", delete_auto_save_files,
6387 doc: /* Non-nil means delete auto-save file when a buffer is saved.
6388This is the default. If nil, auto-save file deletion is inhibited. */);
6389 delete_auto_save_files = 1;
6390
6368 defsubr (&Sbuffer_live_p); 6391 defsubr (&Sbuffer_live_p);
6369 defsubr (&Sbuffer_list); 6392 defsubr (&Sbuffer_list);
6370 defsubr (&Sget_buffer); 6393 defsubr (&Sget_buffer);
diff --git a/src/buffer.h b/src/buffer.h
index 24e9c3fcbc8..8623bed08e6 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -60,6 +60,14 @@ enum { BEG = 1, BEG_BYTE = BEG };
60 60
61/* Macros for the addresses of places in the buffer. */ 61/* Macros for the addresses of places in the buffer. */
62 62
63/* WARNING: Use the 'char *' pointers to buffer text with care in code
64 that could GC: GC can relocate buffer text, invalidating such
65 pointers. It is best to use character or byte position instead,
66 delaying the access through BYTE_POS_ADDR etc. pointers to the
67 latest possible moment. If you must use the 'char *' pointers
68 (e.g., for speed), be sure to adjust them after any call that could
69 potentially GC. */
70
63/* Address of beginning of buffer. */ 71/* Address of beginning of buffer. */
64#define BEG_ADDR (current_buffer->text->beg) 72#define BEG_ADDR (current_buffer->text->beg)
65 73
@@ -1002,6 +1010,9 @@ SET_BUF_PT_BOTH (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t byte)
1002 or convert between a byte position and an address. 1010 or convert between a byte position and an address.
1003 These functions do not check that the position is in range. */ 1011 These functions do not check that the position is in range. */
1004 1012
1013/* See the important WARNING above about using the 'char *' pointers
1014 returned by these functions. */
1015
1005/* Return the address of byte position N in current buffer. */ 1016/* Return the address of byte position N in current buffer. */
1006 1017
1007INLINE unsigned char * 1018INLINE unsigned char *
diff --git a/src/callint.c b/src/callint.c
index 6f8a7f13f61..44dae361c1f 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -606,7 +606,7 @@ invoke it (via an `interactive' spec that contains, for instance, an
606 break; 606 break;
607 607
608 case 'e': /* The invoking event. */ 608 case 'e': /* The invoking event. */
609 if (next_event >= key_count) 609 if (!inhibit_mouse_event_check && next_event >= key_count)
610 error ("%s must be bound to an event with parameters", 610 error ("%s must be bound to an event with parameters",
611 (SYMBOLP (function) 611 (SYMBOLP (function)
612 ? SSDATA (SYMBOL_NAME (function)) 612 ? SSDATA (SYMBOL_NAME (function))
@@ -900,6 +900,14 @@ Its purpose is to give temporary modes such as Isearch mode
900a way to turn themselves off when a mouse command switches windows. */); 900a way to turn themselves off when a mouse command switches windows. */);
901 Vmouse_leave_buffer_hook = Qnil; 901 Vmouse_leave_buffer_hook = Qnil;
902 902
903 DEFVAR_BOOL ("inhibit-mouse-event-check", inhibit_mouse_event_check,
904 doc: /* Whether the interactive spec "e" requires a mouse gesture event.
905If non-nil, `(interactive "e")' doesn't signal an error when the command
906was invoked by an input event that is not a mouse gesture: a click, a drag,
907etc. To create the event data when the input was some other event,
908use `event-start', `event-end', and `event-click-count'. */);
909 inhibit_mouse_event_check = false;
910
903 defsubr (&Sinteractive); 911 defsubr (&Sinteractive);
904 defsubr (&Scall_interactively); 912 defsubr (&Scall_interactively);
905 defsubr (&Sfuncall_interactively); 913 defsubr (&Sfuncall_interactively);
diff --git a/src/callproc.c b/src/callproc.c
index 675b78daf3e..fa43f973844 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -232,6 +232,8 @@ directory where the process is run (see below). If you want to make the
232input come from an Emacs buffer, use `call-process-region' instead. 232input come from an Emacs buffer, use `call-process-region' instead.
233 233
234Third argument DESTINATION specifies how to handle program's output. 234Third argument DESTINATION specifies how to handle program's output.
235(\"Output\" here means both standard output and standard error
236output.)
235If DESTINATION is a buffer, or t that stands for the current buffer, 237If DESTINATION is a buffer, or t that stands for the current buffer,
236 it means insert output in that buffer before point. 238 it means insert output in that buffer before point.
237If DESTINATION is nil, it means discard output; 0 means discard 239If DESTINATION is nil, it means discard output; 0 means discard
diff --git a/src/casefiddle.c b/src/casefiddle.c
index a7a25414909..81e9ed153fb 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -54,6 +54,9 @@ struct casing_context
54 54
55 /* Whether the context is within a word. */ 55 /* Whether the context is within a word. */
56 bool inword; 56 bool inword;
57
58 /* What the last operation was. */
59 bool downcase_last;
57}; 60};
58 61
59/* Initialize CTX structure for casing characters. */ 62/* Initialize CTX structure for casing characters. */
@@ -143,10 +146,14 @@ case_character_impl (struct casing_str_buf *buf,
143 146
144 /* Handle simple, one-to-one case. */ 147 /* Handle simple, one-to-one case. */
145 if (flag == CASE_DOWN) 148 if (flag == CASE_DOWN)
146 cased = downcase (ch); 149 {
150 cased = downcase (ch);
151 ctx->downcase_last = true;
152 }
147 else 153 else
148 { 154 {
149 bool cased_is_set = false; 155 bool cased_is_set = false;
156 ctx->downcase_last = false;
150 if (!NILP (ctx->titlecase_char_table)) 157 if (!NILP (ctx->titlecase_char_table))
151 { 158 {
152 prop = CHAR_TABLE_REF (ctx->titlecase_char_table, ch); 159 prop = CHAR_TABLE_REF (ctx->titlecase_char_table, ch);
@@ -297,6 +304,16 @@ do_casify_multibyte_string (struct casing_context *ctx, Lisp_Object obj)
297 return obj; 304 return obj;
298} 305}
299 306
307static int
308ascii_casify_character (bool downcase, int c)
309{
310 Lisp_Object cased = CHAR_TABLE_REF (downcase?
311 uniprop_table (Qlowercase) :
312 uniprop_table (Quppercase),
313 c);
314 return FIXNATP (cased) ? XFIXNAT (cased) : c;
315}
316
300static Lisp_Object 317static Lisp_Object
301do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj) 318do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
302{ 319{
@@ -310,11 +327,12 @@ do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
310 cased = case_single_character (ctx, ch); 327 cased = case_single_character (ctx, ch);
311 if (ch == cased) 328 if (ch == cased)
312 continue; 329 continue;
313 cased = make_char_unibyte (cased); 330 /* If down/upcasing changed an ASCII character into a non-ASCII
314 /* If the char can't be converted to a valid byte, just don't 331 character (this can happen in some locales, like the Turkish
315 change it. */ 332 "I"), downcase using the ASCII char table. */
316 if (SINGLE_BYTE_CHAR_P (cased)) 333 if (ASCII_CHAR_P (ch) && !SINGLE_BYTE_CHAR_P (cased))
317 SSET (obj, i, cased); 334 cased = ascii_casify_character (ctx->downcase_last, ch);
335 SSET (obj, i, make_char_unibyte (cased));
318 } 336 }
319 return obj; 337 return obj;
320} 338}
@@ -339,10 +357,13 @@ casify_object (enum case_action flag, Lisp_Object obj)
339 357
340DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, 358DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
341 doc: /* Convert argument to upper case and return that. 359 doc: /* Convert argument to upper case and return that.
342The argument may be a character or string. The result has the same type. 360The argument may be a character or string. The result has the same
361type. (See `downcase' for further details about the type.)
362
343The argument object is not altered--the value is a copy. If argument 363The argument object is not altered--the value is a copy. If argument
344is a character, characters which map to multiple code points when 364is a character, characters which map to multiple code points when
345cased, e.g. fi, are returned unchanged. 365cased, e.g. fi, are returned unchanged.
366
346See also `capitalize', `downcase' and `upcase-initials'. */) 367See also `capitalize', `downcase' and `upcase-initials'. */)
347 (Lisp_Object obj) 368 (Lisp_Object obj)
348{ 369{
@@ -351,7 +372,15 @@ See also `capitalize', `downcase' and `upcase-initials'. */)
351 372
352DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0, 373DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0,
353 doc: /* Convert argument to lower case and return that. 374 doc: /* Convert argument to lower case and return that.
354The argument may be a character or string. The result has the same type. 375The argument may be a character or string. The result has the same type,
376including the multibyteness of the string.
377
378This means that if this function is called with a unibyte string
379argument, and downcasing it would turn it into a multibyte string
380(according to the current locale), the downcasing is done using ASCII
381\"C\" rules instead. To accurately downcase according to the current
382locale, the string must be converted into multibyte first.
383
355The argument object is not altered--the value is a copy. */) 384The argument object is not altered--the value is a copy. */)
356 (Lisp_Object obj) 385 (Lisp_Object obj)
357{ 386{
@@ -362,7 +391,10 @@ DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0,
362 doc: /* Convert argument to capitalized form and return that. 391 doc: /* Convert argument to capitalized form and return that.
363This means that each word's first character is converted to either 392This means that each word's first character is converted to either
364title case or upper case, and the rest to lower case. 393title case or upper case, and the rest to lower case.
365The argument may be a character or string. The result has the same type. 394
395The argument may be a character or string. The result has the same
396type. (See `downcase' for further details about the type.)
397
366The argument object is not altered--the value is a copy. If argument 398The argument object is not altered--the value is a copy. If argument
367is a character, characters which map to multiple code points when 399is a character, characters which map to multiple code points when
368cased, e.g. fi, are returned unchanged. */) 400cased, e.g. fi, are returned unchanged. */)
@@ -377,7 +409,10 @@ DEFUN ("upcase-initials", Fupcase_initials, Supcase_initials, 1, 1, 0,
377 doc: /* Convert the initial of each word in the argument to upper case. 409 doc: /* Convert the initial of each word in the argument to upper case.
378This means that each word's first character is converted to either 410This means that each word's first character is converted to either
379title case or upper case, and the rest are left unchanged. 411title case or upper case, and the rest are left unchanged.
380The argument may be a character or string. The result has the same type. 412
413The argument may be a character or string. The result has the same
414type. (See `downcase' for further details about the type.)
415
381The argument object is not altered--the value is a copy. If argument 416The argument object is not altered--the value is a copy. If argument
382is a character, characters which map to multiple code points when 417is a character, characters which map to multiple code points when
383cased, e.g. fi, are returned unchanged. */) 418cased, e.g. fi, are returned unchanged. */)
@@ -651,6 +686,8 @@ syms_of_casefiddle (void)
651 DEFSYM (Qbounds, "bounds"); 686 DEFSYM (Qbounds, "bounds");
652 DEFSYM (Qidentity, "identity"); 687 DEFSYM (Qidentity, "identity");
653 DEFSYM (Qtitlecase, "titlecase"); 688 DEFSYM (Qtitlecase, "titlecase");
689 DEFSYM (Qlowercase, "lowercase");
690 DEFSYM (Quppercase, "uppercase");
654 DEFSYM (Qspecial_uppercase, "special-uppercase"); 691 DEFSYM (Qspecial_uppercase, "special-uppercase");
655 DEFSYM (Qspecial_lowercase, "special-lowercase"); 692 DEFSYM (Qspecial_lowercase, "special-lowercase");
656 DEFSYM (Qspecial_titlecase, "special-titlecase"); 693 DEFSYM (Qspecial_titlecase, "special-titlecase");
diff --git a/src/character.h b/src/character.h
index 1a745484daa..6ee6bcab205 100644
--- a/src/character.h
+++ b/src/character.h
@@ -82,6 +82,8 @@ enum
82 LEFT_ANGLE_BRACKET = 0x3008, 82 LEFT_ANGLE_BRACKET = 0x3008,
83 RIGHT_ANGLE_BRACKET = 0x3009, 83 RIGHT_ANGLE_BRACKET = 0x3009,
84 OBJECT_REPLACEMENT_CHARACTER = 0xFFFC, 84 OBJECT_REPLACEMENT_CHARACTER = 0xFFFC,
85 TAG_SPACE = 0xE0020,
86 CANCEL_TAG = 0xE007F,
85}; 87};
86 88
87extern int char_string (unsigned, unsigned char *); 89extern int char_string (unsigned, unsigned char *);
diff --git a/src/cmds.c b/src/cmds.c
index c8a96d918cd..00fde0ef79b 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -455,7 +455,7 @@ internal_self_insert (int c, EMACS_INT n)
455 ptrdiff_t to; 455 ptrdiff_t to;
456 if (INT_ADD_WRAPV (PT, chars_to_delete, &to)) 456 if (INT_ADD_WRAPV (PT, chars_to_delete, &to))
457 to = PTRDIFF_MAX; 457 to = PTRDIFF_MAX;
458 replace_range (PT, to, string, 1, 1, 1, 0); 458 replace_range (PT, to, string, 1, 1, 1, 0, false);
459 Fforward_char (make_fixnum (n)); 459 Fforward_char (make_fixnum (n));
460 } 460 }
461 else if (n > 1) 461 else if (n > 1)
diff --git a/src/coding.c b/src/coding.c
index 87b55aecc05..7030a53869a 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -8250,6 +8250,39 @@ decode_coding_object (struct coding_system *coding,
8250} 8250}
8251 8251
8252 8252
8253/* Encode the text in the range FROM/FROM_BYTE and TO/TO_BYTE in
8254 SRC_OBJECT into DST_OBJECT by coding context CODING.
8255
8256 SRC_OBJECT is a buffer, a string, or Qnil.
8257
8258 If it is a buffer, the text is at point of the buffer. FROM and TO
8259 are positions in the buffer.
8260
8261 If it is a string, the text is at the beginning of the string.
8262 FROM and TO are indices into the string.
8263
8264 If it is nil, the text is at coding->source. FROM and TO are
8265 indices into coding->source.
8266
8267 DST_OBJECT is a buffer, Qt, or Qnil.
8268
8269 If it is a buffer, the encoded text is inserted at point of the
8270 buffer. If the buffer is the same as SRC_OBJECT, the source text
8271 is replaced with the encoded text.
8272
8273 If it is Qt, a string is made from the encoded text, and set in
8274 CODING->dst_object. However, if CODING->raw_destination is non-zero,
8275 the encoded text is instead returned in CODING->destination as a C string,
8276 and the caller is responsible for freeing CODING->destination. This
8277 feature is meant to be used when the caller doesn't need the result as
8278 a Lisp string, and wants to avoid unnecessary consing of large strings.
8279
8280 If it is Qnil, the encoded text is stored at CODING->destination.
8281 The caller must allocate CODING->dst_bytes bytes at
8282 CODING->destination by xmalloc. If the encoded text is longer than
8283 CODING->dst_bytes, CODING->destination is reallocated by xrealloc
8284 (and CODING->dst_bytes is enlarged accordingly). */
8285
8253void 8286void
8254encode_coding_object (struct coding_system *coding, 8287encode_coding_object (struct coding_system *coding,
8255 Lisp_Object src_object, 8288 Lisp_Object src_object,
@@ -8275,11 +8308,14 @@ encode_coding_object (struct coding_system *coding,
8275 8308
8276 attrs = CODING_ID_ATTRS (coding->id); 8309 attrs = CODING_ID_ATTRS (coding->id);
8277 8310
8278 if (EQ (src_object, dst_object)) 8311 bool same_buffer = false;
8312 if (EQ (src_object, dst_object) && BUFFERP (src_object))
8279 { 8313 {
8280 struct Lisp_Marker *tail; 8314 struct Lisp_Marker *tail;
8281 8315
8282 for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next) 8316 same_buffer = true;
8317
8318 for (tail = BUF_MARKERS (XBUFFER (src_object)); tail; tail = tail->next)
8283 { 8319 {
8284 tail->need_adjustment 8320 tail->need_adjustment
8285 = tail->charpos == (tail->insertion_type ? from : to); 8321 = tail->charpos == (tail->insertion_type ? from : to);
@@ -8298,7 +8334,7 @@ encode_coding_object (struct coding_system *coding,
8298 else 8334 else
8299 insert_1_both ((char *) coding->source + from, chars, bytes, 0, 0, 0); 8335 insert_1_both ((char *) coding->source + from, chars, bytes, 0, 0, 0);
8300 8336
8301 if (EQ (src_object, dst_object)) 8337 if (same_buffer)
8302 { 8338 {
8303 set_buffer_internal (XBUFFER (src_object)); 8339 set_buffer_internal (XBUFFER (src_object));
8304 saved_pt = PT, saved_pt_byte = PT_BYTE; 8340 saved_pt = PT, saved_pt_byte = PT_BYTE;
@@ -8329,7 +8365,7 @@ encode_coding_object (struct coding_system *coding,
8329 { 8365 {
8330 code_conversion_save (0, 0); 8366 code_conversion_save (0, 0);
8331 set_buffer_internal (XBUFFER (src_object)); 8367 set_buffer_internal (XBUFFER (src_object));
8332 if (EQ (src_object, dst_object)) 8368 if (same_buffer)
8333 { 8369 {
8334 saved_pt = PT, saved_pt_byte = PT_BYTE; 8370 saved_pt = PT, saved_pt_byte = PT_BYTE;
8335 coding->src_object = del_range_1 (from, to, 1, 1); 8371 coding->src_object = del_range_1 (from, to, 1, 1);
@@ -10394,8 +10430,7 @@ encode_file_name (Lisp_Object fname)
10394 cause subtle bugs because the system would silently use a 10430 cause subtle bugs because the system would silently use a
10395 different filename than expected. Perform this check after 10431 different filename than expected. Perform this check after
10396 encoding to not miss NUL bytes introduced through encoding. */ 10432 encoding to not miss NUL bytes introduced through encoding. */
10397 CHECK_TYPE (memchr (SSDATA (encoded), '\0', SBYTES (encoded)) == NULL, 10433 CHECK_STRING_NULL_BYTES (encoded);
10398 Qfilenamep, fname);
10399 return encoded; 10434 return encoded;
10400} 10435}
10401 10436
diff --git a/src/comp.c b/src/comp.c
index c3803464827..5b947fc99b6 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -71,6 +71,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
71#undef gcc_jit_context_new_binary_op 71#undef gcc_jit_context_new_binary_op
72#undef gcc_jit_context_new_call 72#undef gcc_jit_context_new_call
73#undef gcc_jit_context_new_call_through_ptr 73#undef gcc_jit_context_new_call_through_ptr
74#undef gcc_jit_context_new_cast
74#undef gcc_jit_context_new_comparison 75#undef gcc_jit_context_new_comparison
75#undef gcc_jit_context_new_field 76#undef gcc_jit_context_new_field
76#undef gcc_jit_context_new_function 77#undef gcc_jit_context_new_function
@@ -151,8 +152,10 @@ DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_context_new_global,
151DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_function_new_local, 152DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_function_new_local,
152 (gcc_jit_function *func, gcc_jit_location *loc, gcc_jit_type *type, 153 (gcc_jit_function *func, gcc_jit_location *loc, gcc_jit_type *type,
153 const char *name)); 154 const char *name));
155#if defined (LIBGCCJIT_HAVE_gcc_jit_global_set_initializer)
154DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_global_set_initializer, 156DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_global_set_initializer,
155 (gcc_jit_lvalue *global, const void *blob, size_t num_bytes)); 157 (gcc_jit_lvalue *global, const void *blob, size_t num_bytes));
158#endif
156DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_lvalue_access_field, 159DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_lvalue_access_field,
157 (gcc_jit_lvalue *struct_or_union, gcc_jit_location *loc, 160 (gcc_jit_lvalue *struct_or_union, gcc_jit_location *loc,
158 gcc_jit_field *field)); 161 gcc_jit_field *field));
@@ -176,6 +179,9 @@ DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_call,
176DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_call_through_ptr, 179DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_call_through_ptr,
177 (gcc_jit_context *ctxt, gcc_jit_location *loc, 180 (gcc_jit_context *ctxt, gcc_jit_location *loc,
178 gcc_jit_rvalue *fn_ptr, int numargs, gcc_jit_rvalue **args)); 181 gcc_jit_rvalue *fn_ptr, int numargs, gcc_jit_rvalue **args));
182DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_cast,
183 (gcc_jit_context *ctxt, gcc_jit_location *loc,
184 gcc_jit_rvalue *rvalue, gcc_jit_type *type));
179DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_comparison, 185DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_comparison,
180 (gcc_jit_context *ctxt, gcc_jit_location *loc, 186 (gcc_jit_context *ctxt, gcc_jit_location *loc,
181 enum gcc_jit_comparison op, gcc_jit_rvalue *a, gcc_jit_rvalue *b)); 187 enum gcc_jit_comparison op, gcc_jit_rvalue *a, gcc_jit_rvalue *b));
@@ -255,9 +261,11 @@ DEF_DLL_FN (void, gcc_jit_context_set_str_option,
255DEF_DLL_FN (void, gcc_jit_struct_set_fields, 261DEF_DLL_FN (void, gcc_jit_struct_set_fields,
256 (gcc_jit_struct *struct_type, gcc_jit_location *loc, int num_fields, 262 (gcc_jit_struct *struct_type, gcc_jit_location *loc, int num_fields,
257 gcc_jit_field **fields)); 263 gcc_jit_field **fields));
264#if defined (LIBGCCJIT_HAVE_gcc_jit_version)
258DEF_DLL_FN (int, gcc_jit_version_major, (void)); 265DEF_DLL_FN (int, gcc_jit_version_major, (void));
259DEF_DLL_FN (int, gcc_jit_version_minor, (void)); 266DEF_DLL_FN (int, gcc_jit_version_minor, (void));
260DEF_DLL_FN (int, gcc_jit_version_patchlevel, (void)); 267DEF_DLL_FN (int, gcc_jit_version_patchlevel, (void));
268#endif
261 269
262static bool 270static bool
263init_gccjit_functions (void) 271init_gccjit_functions (void)
@@ -288,6 +296,7 @@ init_gccjit_functions (void)
288 LOAD_DLL_FN (library, gcc_jit_context_new_binary_op); 296 LOAD_DLL_FN (library, gcc_jit_context_new_binary_op);
289 LOAD_DLL_FN (library, gcc_jit_context_new_call); 297 LOAD_DLL_FN (library, gcc_jit_context_new_call);
290 LOAD_DLL_FN (library, gcc_jit_context_new_call_through_ptr); 298 LOAD_DLL_FN (library, gcc_jit_context_new_call_through_ptr);
299 LOAD_DLL_FN (library, gcc_jit_context_new_cast);
291 LOAD_DLL_FN (library, gcc_jit_context_new_comparison); 300 LOAD_DLL_FN (library, gcc_jit_context_new_comparison);
292 LOAD_DLL_FN (library, gcc_jit_context_new_field); 301 LOAD_DLL_FN (library, gcc_jit_context_new_field);
293 LOAD_DLL_FN (library, gcc_jit_context_new_function); 302 LOAD_DLL_FN (library, gcc_jit_context_new_function);
@@ -327,10 +336,14 @@ init_gccjit_functions (void)
327 LOAD_DLL_FN (library, gcc_jit_type_get_pointer); 336 LOAD_DLL_FN (library, gcc_jit_type_get_pointer);
328 LOAD_DLL_FN_OPT (library, gcc_jit_context_add_command_line_option); 337 LOAD_DLL_FN_OPT (library, gcc_jit_context_add_command_line_option);
329 LOAD_DLL_FN_OPT (library, gcc_jit_context_add_driver_option); 338 LOAD_DLL_FN_OPT (library, gcc_jit_context_add_driver_option);
339#if defined (LIBGCCJIT_HAVE_gcc_jit_global_set_initializer)
330 LOAD_DLL_FN_OPT (library, gcc_jit_global_set_initializer); 340 LOAD_DLL_FN_OPT (library, gcc_jit_global_set_initializer);
341#endif
342#if defined (LIBGCCJIT_HAVE_gcc_jit_version)
331 LOAD_DLL_FN_OPT (library, gcc_jit_version_major); 343 LOAD_DLL_FN_OPT (library, gcc_jit_version_major);
332 LOAD_DLL_FN_OPT (library, gcc_jit_version_minor); 344 LOAD_DLL_FN_OPT (library, gcc_jit_version_minor);
333 LOAD_DLL_FN_OPT (library, gcc_jit_version_patchlevel); 345 LOAD_DLL_FN_OPT (library, gcc_jit_version_patchlevel);
346#endif
334 347
335 return true; 348 return true;
336} 349}
@@ -358,6 +371,7 @@ init_gccjit_functions (void)
358#define gcc_jit_context_new_binary_op fn_gcc_jit_context_new_binary_op 371#define gcc_jit_context_new_binary_op fn_gcc_jit_context_new_binary_op
359#define gcc_jit_context_new_call fn_gcc_jit_context_new_call 372#define gcc_jit_context_new_call fn_gcc_jit_context_new_call
360#define gcc_jit_context_new_call_through_ptr fn_gcc_jit_context_new_call_through_ptr 373#define gcc_jit_context_new_call_through_ptr fn_gcc_jit_context_new_call_through_ptr
374#define gcc_jit_context_new_cast fn_gcc_jit_context_new_cast
361#define gcc_jit_context_new_comparison fn_gcc_jit_context_new_comparison 375#define gcc_jit_context_new_comparison fn_gcc_jit_context_new_comparison
362#define gcc_jit_context_new_field fn_gcc_jit_context_new_field 376#define gcc_jit_context_new_field fn_gcc_jit_context_new_field
363#define gcc_jit_context_new_function fn_gcc_jit_context_new_function 377#define gcc_jit_context_new_function fn_gcc_jit_context_new_function
@@ -382,7 +396,9 @@ init_gccjit_functions (void)
382#define gcc_jit_function_get_param fn_gcc_jit_function_get_param 396#define gcc_jit_function_get_param fn_gcc_jit_function_get_param
383#define gcc_jit_function_new_block fn_gcc_jit_function_new_block 397#define gcc_jit_function_new_block fn_gcc_jit_function_new_block
384#define gcc_jit_function_new_local fn_gcc_jit_function_new_local 398#define gcc_jit_function_new_local fn_gcc_jit_function_new_local
385#define gcc_jit_global_set_initializer fn_gcc_jit_global_set_initializer 399#if defined (LIBGCCJIT_HAVE_gcc_jit_global_set_initializer)
400 #define gcc_jit_global_set_initializer fn_gcc_jit_global_set_initializer
401#endif
386#define gcc_jit_lvalue_access_field fn_gcc_jit_lvalue_access_field 402#define gcc_jit_lvalue_access_field fn_gcc_jit_lvalue_access_field
387#define gcc_jit_lvalue_as_rvalue fn_gcc_jit_lvalue_as_rvalue 403#define gcc_jit_lvalue_as_rvalue fn_gcc_jit_lvalue_as_rvalue
388#define gcc_jit_lvalue_get_address fn_gcc_jit_lvalue_get_address 404#define gcc_jit_lvalue_get_address fn_gcc_jit_lvalue_get_address
@@ -396,9 +412,11 @@ init_gccjit_functions (void)
396#define gcc_jit_struct_set_fields fn_gcc_jit_struct_set_fields 412#define gcc_jit_struct_set_fields fn_gcc_jit_struct_set_fields
397#define gcc_jit_type_get_const fn_gcc_jit_type_get_const 413#define gcc_jit_type_get_const fn_gcc_jit_type_get_const
398#define gcc_jit_type_get_pointer fn_gcc_jit_type_get_pointer 414#define gcc_jit_type_get_pointer fn_gcc_jit_type_get_pointer
399#define gcc_jit_version_major fn_gcc_jit_version_major 415#if defined (LIBGCCJIT_HAVE_gcc_jit_version)
400#define gcc_jit_version_minor fn_gcc_jit_version_minor 416 #define gcc_jit_version_major fn_gcc_jit_version_major
401#define gcc_jit_version_patchlevel fn_gcc_jit_version_patchlevel 417 #define gcc_jit_version_minor fn_gcc_jit_version_minor
418 #define gcc_jit_version_patchlevel fn_gcc_jit_version_patchlevel
419#endif
402 420
403#endif 421#endif
404 422
@@ -499,13 +517,6 @@ static f_reloc_t freloc;
499 517
500#define NUM_CAST_TYPES 15 518#define NUM_CAST_TYPES 15
501 519
502enum cast_kind_of_type
503 {
504 kind_unsigned,
505 kind_signed,
506 kind_pointer
507 };
508
509typedef struct { 520typedef struct {
510 EMACS_INT len; 521 EMACS_INT len;
511 gcc_jit_rvalue *r_val; 522 gcc_jit_rvalue *r_val;
@@ -516,6 +527,7 @@ typedef struct {
516typedef struct { 527typedef struct {
517 EMACS_INT speed; 528 EMACS_INT speed;
518 EMACS_INT debug; 529 EMACS_INT debug;
530 Lisp_Object compiler_options;
519 Lisp_Object driver_options; 531 Lisp_Object driver_options;
520 gcc_jit_context *ctxt; 532 gcc_jit_context *ctxt;
521 gcc_jit_type *void_type; 533 gcc_jit_type *void_type;
@@ -571,14 +583,9 @@ typedef struct {
571 be used for the scope. */ 583 be used for the scope. */
572 gcc_jit_type *cast_union_type; 584 gcc_jit_type *cast_union_type;
573 gcc_jit_function *cast_functions_from_to[NUM_CAST_TYPES][NUM_CAST_TYPES]; 585 gcc_jit_function *cast_functions_from_to[NUM_CAST_TYPES][NUM_CAST_TYPES];
574 /* We add one to make space for the last member which is the "biggest_type" 586 gcc_jit_function *cast_ptr_to_int;
575 member. */ 587 gcc_jit_function *cast_int_to_ptr;
576 gcc_jit_type *cast_types[NUM_CAST_TYPES + 1]; 588 gcc_jit_type *cast_types[NUM_CAST_TYPES];
577 size_t cast_type_sizes[NUM_CAST_TYPES + 1];
578 enum cast_kind_of_type cast_type_kind[NUM_CAST_TYPES + 1];
579 const char *cast_type_names[NUM_CAST_TYPES + 1];
580 gcc_jit_field *cast_union_fields[NUM_CAST_TYPES + 1];
581 size_t cast_union_field_biggest_type;
582 gcc_jit_function *func; /* Current function being compiled. */ 589 gcc_jit_function *func; /* Current function being compiled. */
583 bool func_has_non_local; /* From comp-func has-non-local slot. */ 590 bool func_has_non_local; /* From comp-func has-non-local slot. */
584 EMACS_INT func_speed; /* From comp-func speed slot. */ 591 EMACS_INT func_speed; /* From comp-func speed slot. */
@@ -698,6 +705,12 @@ comp_hash_source_file (Lisp_Object filename)
698 /* Can't use Finsert_file_contents + Fbuffer_hash as this is called 705 /* Can't use Finsert_file_contents + Fbuffer_hash as this is called
699 by Fcomp_el_to_eln_filename too early during bootstrap. */ 706 by Fcomp_el_to_eln_filename too early during bootstrap. */
700 bool is_gz = suffix_p (filename, ".gz"); 707 bool is_gz = suffix_p (filename, ".gz");
708#ifndef HAVE_ZLIB
709 if (is_gz)
710 xsignal2 (Qfile_notify_error,
711 build_string ("Cannot natively compile compressed *.el files without zlib support"),
712 filename);
713#endif
701 Lisp_Object encoded_filename = ENCODE_FILE (filename); 714 Lisp_Object encoded_filename = ENCODE_FILE (filename);
702 FILE *f = emacs_fopen (SSDATA (encoded_filename), is_gz ? "rb" : "r"); 715 FILE *f = emacs_fopen (SSDATA (encoded_filename), is_gz ? "rb" : "r");
703 716
@@ -706,9 +719,13 @@ comp_hash_source_file (Lisp_Object filename)
706 719
707 Lisp_Object digest = make_uninit_string (MD5_DIGEST_SIZE * 2); 720 Lisp_Object digest = make_uninit_string (MD5_DIGEST_SIZE * 2);
708 721
722#ifdef HAVE_ZLIB
709 int res = is_gz 723 int res = is_gz
710 ? md5_gz_stream (f, SSDATA (digest)) 724 ? md5_gz_stream (f, SSDATA (digest))
711 : md5_stream (f, SSDATA (digest)); 725 : md5_stream (f, SSDATA (digest));
726#else
727 int res = md5_stream (f, SSDATA (digest));
728#endif
712 fclose (f); 729 fclose (f);
713 730
714 if (res) 731 if (res)
@@ -1113,13 +1130,6 @@ emit_coerce (gcc_jit_type *new_type, gcc_jit_rvalue *obj)
1113 int old_index = type_to_cast_index (old_type); 1130 int old_index = type_to_cast_index (old_type);
1114 int new_index = type_to_cast_index (new_type); 1131 int new_index = type_to_cast_index (new_type);
1115 1132
1116 if (comp.cast_type_sizes[old_index] < comp.cast_type_sizes[new_index]
1117 && comp.cast_type_kind[new_index] == kind_signed)
1118 xsignal3 (Qnative_ice,
1119 build_string ("FIXME: sign extension not implemented"),
1120 build_string (comp.cast_type_names[old_index]),
1121 build_string (comp.cast_type_names[new_index]));
1122
1123 /* Lookup the appropriate cast function in the cast matrix. */ 1133 /* Lookup the appropriate cast function in the cast matrix. */
1124 return gcc_jit_context_new_call (comp.ctxt, 1134 return gcc_jit_context_new_call (comp.ctxt,
1125 NULL, 1135 NULL,
@@ -2493,8 +2503,7 @@ emit_static_object (const char *name, Lisp_Object obj)
2493 ptrdiff_t len = SBYTES (str); 2503 ptrdiff_t len = SBYTES (str);
2494 const char *p = SSDATA (str); 2504 const char *p = SSDATA (str);
2495 2505
2496#if defined (LIBGCCJIT_HAVE_gcc_jit_global_set_initializer) \ 2506#if defined (LIBGCCJIT_HAVE_gcc_jit_global_set_initializer)
2497 || defined (WINDOWSNT)
2498 if (gcc_jit_global_set_initializer) 2507 if (gcc_jit_global_set_initializer)
2499 { 2508 {
2500 ptrdiff_t str_size = len + 1; 2509 ptrdiff_t str_size = len + 1;
@@ -3111,30 +3120,17 @@ define_thread_state_struct (void)
3111 gcc_jit_type_get_pointer (gcc_jit_struct_as_type (comp.thread_state_s)); 3120 gcc_jit_type_get_pointer (gcc_jit_struct_as_type (comp.thread_state_s));
3112} 3121}
3113 3122
3114struct cast_type
3115{
3116 gcc_jit_type *type;
3117 const char *name;
3118 size_t bytes_size;
3119 enum cast_kind_of_type kind;
3120};
3121
3122static gcc_jit_function * 3123static gcc_jit_function *
3123define_cast_from_to (struct cast_type from, int from_index, struct cast_type to, 3124define_type_punning (const char *name,
3124 int to_index) 3125 gcc_jit_type *from, gcc_jit_field *from_field,
3126 gcc_jit_type *to, gcc_jit_field *to_field)
3125{ 3127{
3126 /* FIXME: sign extension not implemented. */
3127 if (comp.cast_type_sizes[from_index] < comp.cast_type_sizes[to_index]
3128 && comp.cast_type_kind[to_index] == kind_signed)
3129 return NULL;
3130
3131 char *name = format_string ("cast_from_%s_to_%s", from.name, to.name);
3132 gcc_jit_param *param = gcc_jit_context_new_param (comp.ctxt, NULL, 3128 gcc_jit_param *param = gcc_jit_context_new_param (comp.ctxt, NULL,
3133 from.type, "arg"); 3129 from, "arg");
3134 gcc_jit_function *result = gcc_jit_context_new_function (comp.ctxt, 3130 gcc_jit_function *result = gcc_jit_context_new_function (comp.ctxt,
3135 NULL, 3131 NULL,
3136 GCC_JIT_FUNCTION_INTERNAL, 3132 GCC_JIT_FUNCTION_INTERNAL,
3137 to.type, 3133 to,
3138 name, 3134 name,
3139 1, 3135 1,
3140 &param, 3136 &param,
@@ -3148,26 +3144,63 @@ define_cast_from_to (struct cast_type from, int from_index, struct cast_type to,
3148 comp.cast_union_type, 3144 comp.cast_union_type,
3149 "union_cast"); 3145 "union_cast");
3150 3146
3151 /* Zero the union first. */
3152 gcc_jit_block_add_assignment (entry_block, NULL, 3147 gcc_jit_block_add_assignment (entry_block, NULL,
3153 gcc_jit_lvalue_access_field (tmp_union, NULL, 3148 gcc_jit_lvalue_access_field (tmp_union, NULL,
3154 comp.cast_union_fields[NUM_CAST_TYPES]), 3149 from_field),
3155 gcc_jit_context_new_rvalue_from_int (
3156 comp.ctxt,
3157 comp.cast_types[NUM_CAST_TYPES],
3158 0));
3159
3160 gcc_jit_block_add_assignment (entry_block, NULL,
3161 gcc_jit_lvalue_access_field (tmp_union, NULL,
3162 comp.cast_union_fields[from_index]),
3163 gcc_jit_param_as_rvalue (param)); 3150 gcc_jit_param_as_rvalue (param));
3164 3151
3165 gcc_jit_block_end_with_return (entry_block, 3152 gcc_jit_block_end_with_return (entry_block,
3166 NULL, 3153 NULL,
3167 gcc_jit_rvalue_access_field ( 3154 gcc_jit_rvalue_access_field (
3168 gcc_jit_lvalue_as_rvalue (tmp_union), 3155 gcc_jit_lvalue_as_rvalue (tmp_union),
3169 NULL, 3156 NULL, to_field));
3170 comp.cast_union_fields[to_index])); 3157
3158 return result;
3159}
3160
3161struct cast_type
3162{
3163 gcc_jit_type *type;
3164 const char *name;
3165 bool is_ptr;
3166};
3167
3168static gcc_jit_function *
3169define_cast_from_to (struct cast_type from, struct cast_type to)
3170{
3171 char *name = format_string ("cast_from_%s_to_%s", from.name, to.name);
3172 gcc_jit_param *param = gcc_jit_context_new_param (comp.ctxt, NULL,
3173 from.type, "arg");
3174 gcc_jit_function *result
3175 = gcc_jit_context_new_function (comp.ctxt,
3176 NULL,
3177 GCC_JIT_FUNCTION_INTERNAL,
3178 to.type, name,
3179 1, &param, 0);
3180 DECL_BLOCK (entry_block, result);
3181
3182 gcc_jit_rvalue *tmp = gcc_jit_param_as_rvalue (param);
3183 if (from.is_ptr != to.is_ptr)
3184 {
3185 if (from.is_ptr)
3186 {
3187 tmp = gcc_jit_context_new_cast (comp.ctxt, NULL,
3188 tmp, comp.void_ptr_type);
3189 tmp = gcc_jit_context_new_call (comp.ctxt, NULL,
3190 comp.cast_ptr_to_int, 1, &tmp);
3191 }
3192 else
3193 {
3194 tmp = gcc_jit_context_new_cast (comp.ctxt, NULL,
3195 tmp, comp.uintptr_type);
3196 tmp = gcc_jit_context_new_call (comp.ctxt, NULL,
3197 comp.cast_int_to_ptr, 1, &tmp);
3198 }
3199 }
3200
3201 tmp = gcc_jit_context_new_cast (comp.ctxt, NULL, tmp, to.type);
3202
3203 gcc_jit_block_end_with_return (entry_block, NULL, tmp);
3171 3204
3172 return result; 3205 return result;
3173} 3206}
@@ -3176,69 +3209,58 @@ static void
3176define_cast_functions (void) 3209define_cast_functions (void)
3177{ 3210{
3178 struct cast_type cast_types[NUM_CAST_TYPES] 3211 struct cast_type cast_types[NUM_CAST_TYPES]
3179 = { { comp.bool_type, "bool", sizeof (bool), kind_unsigned }, 3212 = { { comp.bool_type, "bool", false },
3180 { comp.char_ptr_type, "char_ptr", sizeof (char *), kind_pointer }, 3213 { comp.char_ptr_type, "char_ptr", true },
3181 { comp.int_type, "int", sizeof (int), kind_signed }, 3214 { comp.int_type, "int", false },
3182 { comp.lisp_cons_ptr_type, "cons_ptr", sizeof (struct Lisp_Cons *), 3215 { comp.lisp_cons_ptr_type, "lisp_cons_ptr", true },
3183 kind_pointer }, 3216 { comp.lisp_obj_ptr_type, "lisp_obj_ptr", true },
3184 { comp.lisp_obj_ptr_type, "lisp_obj_ptr", sizeof (Lisp_Object *), 3217 { comp.lisp_word_tag_type, "lisp_word_tag", false },
3185 kind_pointer }, 3218 { comp.lisp_word_type, "lisp_word", LISP_WORDS_ARE_POINTERS },
3186 { comp.lisp_word_tag_type, "lisp_word_tag", sizeof (Lisp_Word_tag), 3219 { comp.long_long_type, "long_long", false },
3187 kind_unsigned }, 3220 { comp.long_type, "long", false },
3188 { comp.lisp_word_type, "lisp_word", sizeof (Lisp_Word), 3221 { comp.ptrdiff_type, "ptrdiff", false },
3189 LISP_WORDS_ARE_POINTERS ? kind_pointer : kind_signed }, 3222 { comp.uintptr_type, "uintptr", false },
3190 { comp.long_long_type, "long_long", sizeof (long long), kind_signed }, 3223 { comp.unsigned_long_long_type, "unsigned_long_long", false },
3191 { comp.long_type, "long", sizeof (long), kind_signed }, 3224 { comp.unsigned_long_type, "unsigned_long", false },
3192 { comp.ptrdiff_type, "ptrdiff", sizeof (ptrdiff_t), kind_signed }, 3225 { comp.unsigned_type, "unsigned", false },
3193 { comp.uintptr_type, "uintptr", sizeof (uintptr_t), kind_unsigned }, 3226 { comp.void_ptr_type, "void_ptr", true } };
3194 { comp.unsigned_long_long_type, "unsigned_long_long", 3227 gcc_jit_field *cast_union_fields[2];
3195 sizeof (unsigned long long), kind_unsigned }, 3228
3196 { comp.unsigned_long_type, "unsigned_long", sizeof (unsigned long), 3229 /* Define the union used for type punning. */
3197 kind_unsigned }, 3230 cast_union_fields[0] = gcc_jit_context_new_field (comp.ctxt,
3198 { comp.unsigned_type, "unsigned", sizeof (unsigned), kind_unsigned }, 3231 NULL,
3199 { comp.void_ptr_type, "void_ptr", sizeof (void*), kind_pointer } }; 3232 comp.void_ptr_type,
3200 3233 "void_ptr");
3201 /* Find the biggest size. It should be unsigned long long, but to be 3234 cast_union_fields[1] = gcc_jit_context_new_field (comp.ctxt,
3202 sure we find it programmatically. */ 3235 NULL,
3203 size_t biggest_size = 0; 3236 comp.uintptr_type,
3204 for (int i = 0; i < NUM_CAST_TYPES; ++i) 3237 "uintptr");
3205 biggest_size = max (biggest_size, cast_types[i].bytes_size);
3206 3238
3207 /* Define the union used for casting. */ 3239 comp.cast_union_type
3208 for (int i = 0; i < NUM_CAST_TYPES; ++i) 3240 = gcc_jit_context_new_union_type (comp.ctxt,
3209 { 3241 NULL,
3210 comp.cast_types[i] = cast_types[i].type; 3242 "cast_union",
3211 comp.cast_union_fields[i] = gcc_jit_context_new_field (comp.ctxt, 3243 2, cast_union_fields);
3212 NULL, 3244
3213 cast_types[i].type, 3245 comp.cast_ptr_to_int = define_type_punning ("cast_pointer_to_uintptr_t",
3214 cast_types[i].name); 3246 comp.void_ptr_type,
3215 comp.cast_type_names[i] = cast_types[i].name; 3247 cast_union_fields[0],
3216 comp.cast_type_sizes[i] = cast_types[i].bytes_size; 3248 comp.uintptr_type,
3217 comp.cast_type_kind[i] = cast_types[i].kind; 3249 cast_union_fields[1]);
3218 } 3250 comp.cast_int_to_ptr = define_type_punning ("cast_uintptr_t_to_pointer",
3251 comp.uintptr_type,
3252 cast_union_fields[1],
3253 comp.void_ptr_type,
3254 cast_union_fields[0]);
3219 3255
3220 gcc_jit_type *biggest_type = gcc_jit_context_get_int_type (comp.ctxt, 3256 for (int i = 0; i < NUM_CAST_TYPES; ++i)
3221 biggest_size, 3257 comp.cast_types[i] = cast_types[i].type;
3222 false);
3223 comp.cast_types[NUM_CAST_TYPES] = biggest_type;
3224 comp.cast_union_fields[NUM_CAST_TYPES] =
3225 gcc_jit_context_new_field (comp.ctxt, NULL, biggest_type, "biggest_type");
3226 comp.cast_type_names[NUM_CAST_TYPES] = "biggest_type";
3227 comp.cast_type_sizes[NUM_CAST_TYPES] = biggest_size;
3228 comp.cast_type_kind[NUM_CAST_TYPES] = kind_unsigned;
3229
3230 comp.cast_union_type =
3231 gcc_jit_context_new_union_type (comp.ctxt,
3232 NULL,
3233 "cast_union",
3234 NUM_CAST_TYPES + 1,
3235 comp.cast_union_fields);
3236 3258
3237 /* Define the cast functions using a matrix. */ 3259 /* Define the cast functions using a matrix. */
3238 for (int i = 0; i < NUM_CAST_TYPES; ++i) 3260 for (int i = 0; i < NUM_CAST_TYPES; ++i)
3239 for (int j = 0; j < NUM_CAST_TYPES; ++j) 3261 for (int j = 0; j < NUM_CAST_TYPES; ++j)
3240 comp.cast_functions_from_to[i][j] = 3262 comp.cast_functions_from_to[i][j] =
3241 define_cast_from_to (cast_types[i], i, cast_types[j], j); 3263 define_cast_from_to (cast_types[i], cast_types[j]);
3242} 3264}
3243 3265
3244static void 3266static void
@@ -4029,7 +4051,13 @@ make_directory_wrapper_1 (Lisp_Object ignore)
4029 4051
4030DEFUN ("comp-el-to-eln-rel-filename", Fcomp_el_to_eln_rel_filename, 4052DEFUN ("comp-el-to-eln-rel-filename", Fcomp_el_to_eln_rel_filename,
4031 Scomp_el_to_eln_rel_filename, 1, 1, 0, 4053 Scomp_el_to_eln_rel_filename, 1, 1, 0,
4032 doc: /* Return the corresponding .eln relative filename. */) 4054 doc: /* Return the relative name of the .eln file for FILENAME.
4055FILENAME must exist, and if it's a symlink, the target must exist.
4056If FILENAME is compressed, it must have the \".gz\" extension,
4057and Emacs must have been compiled with zlib; the file will be
4058uncompressed on the fly to hash its contents.
4059Value includes the original base name, followed by 2 hash values,
4060one for the file name and another for its contents, followed by .eln. */)
4033 (Lisp_Object filename) 4061 (Lisp_Object filename)
4034{ 4062{
4035 CHECK_STRING (filename); 4063 CHECK_STRING (filename);
@@ -4095,7 +4123,7 @@ DEFUN ("comp-el-to-eln-rel-filename", Fcomp_el_to_eln_rel_filename,
4095 FOR_EACH_TAIL (lds_re_tail) 4123 FOR_EACH_TAIL (lds_re_tail)
4096 { 4124 {
4097 Lisp_Object match_idx = 4125 Lisp_Object match_idx =
4098 Fstring_match (XCAR (lds_re_tail), filename, Qnil); 4126 Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil);
4099 if (EQ (match_idx, make_fixnum (0))) 4127 if (EQ (match_idx, make_fixnum (0)))
4100 { 4128 {
4101 filename = 4129 filename =
@@ -4114,10 +4142,22 @@ DEFUN ("comp-el-to-eln-rel-filename", Fcomp_el_to_eln_rel_filename,
4114 4142
4115DEFUN ("comp-el-to-eln-filename", Fcomp_el_to_eln_filename, 4143DEFUN ("comp-el-to-eln-filename", Fcomp_el_to_eln_filename,
4116 Scomp_el_to_eln_filename, 1, 2, 0, 4144 Scomp_el_to_eln_filename, 1, 2, 0,
4117 doc: /* Return the .eln filename for source FILENAME to used 4145 doc: /* Return the absolute .eln file name for source FILENAME.
4118for new compilations. 4146The resulting .eln file name is intended to be used for natively
4119If BASE-DIR is non-nil use it as a base directory, look for a suitable 4147compiling FILENAME. FILENAME must exist and be readable, but other
4120directory in `comp-eln-load-path' otherwise. */) 4148than that, its leading directories are ignored when constructing
4149the name of the .eln file.
4150If BASE-DIR is non-nil, use it as the directory for the .eln file;
4151non-absolute BASE-DIR is interpreted as relative to `invocation-directory'.
4152If BASE-DIR is omitted or nil, look for the first writable directory
4153in `native-comp-eln-load-path', and use as BASE-DIR its subdirectory
4154whose name is given by `comp-native-version-dir'.
4155If FILENAME specifies a preloaded file, the directory for the .eln
4156file is the \"preloaded/\" subdirectory of the directory determined
4157as described above. FILENAME is considered to be a preloaded file if
4158the value of `comp-file-preloaded-p' is non-nil, or if FILENAME
4159appears in the value of the environment variable LISP_PRELOADED;
4160the latter is supposed to be used by the Emacs build procedure. */)
4121 (Lisp_Object filename, Lisp_Object base_dir) 4161 (Lisp_Object filename, Lisp_Object base_dir)
4122{ 4162{
4123 Lisp_Object source_filename = filename; 4163 Lisp_Object source_filename = filename;
@@ -4374,8 +4414,7 @@ DEFUN ("comp-native-driver-options-effective-p",
4374 doc: /* Return t if `comp-native-driver-options' is effective. */) 4414 doc: /* Return t if `comp-native-driver-options' is effective. */)
4375 (void) 4415 (void)
4376{ 4416{
4377#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option) \ 4417#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option)
4378 || defined (WINDOWSNT)
4379 if (gcc_jit_context_add_driver_option) 4418 if (gcc_jit_context_add_driver_option)
4380 return Qt; 4419 return Qt;
4381#endif 4420#endif
@@ -4383,13 +4422,28 @@ DEFUN ("comp-native-driver-options-effective-p",
4383} 4422}
4384#pragma GCC diagnostic pop 4423#pragma GCC diagnostic pop
4385 4424
4425#pragma GCC diagnostic ignored "-Waddress"
4426DEFUN ("comp-native-compiler-options-effective-p",
4427 Fcomp_native_compiler_options_effective_p,
4428 Scomp_native_compiler_options_effective_p,
4429 0, 0, 0,
4430 doc: /* Return t if `comp-native-compiler-options' is effective. */)
4431 (void)
4432{
4433#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option)
4434 if (gcc_jit_context_add_command_line_option)
4435 return Qt;
4436#endif
4437 return Qnil;
4438}
4439#pragma GCC diagnostic pop
4440
4386static void 4441static void
4387add_driver_options (void) 4442add_driver_options (void)
4388{ 4443{
4389 Lisp_Object options = Fsymbol_value (Qnative_comp_driver_options); 4444 Lisp_Object options = Fsymbol_value (Qnative_comp_driver_options);
4390 4445
4391#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option) \ 4446#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option)
4392 || defined (WINDOWSNT)
4393 load_gccjit_if_necessary (true); 4447 load_gccjit_if_necessary (true);
4394 if (!NILP (Fcomp_native_driver_options_effective_p ())) 4448 if (!NILP (Fcomp_native_driver_options_effective_p ()))
4395 FOR_EACH_TAIL (options) 4449 FOR_EACH_TAIL (options)
@@ -4408,8 +4462,7 @@ add_driver_options (void)
4408 " and above.")); 4462 " and above."));
4409 4463
4410 /* Captured `comp-native-driver-options' because file-local. */ 4464 /* Captured `comp-native-driver-options' because file-local. */
4411#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option) \ 4465#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option)
4412 || defined (WINDOWSNT)
4413 options = comp.driver_options; 4466 options = comp.driver_options;
4414 if (!NILP (Fcomp_native_driver_options_effective_p ())) 4467 if (!NILP (Fcomp_native_driver_options_effective_p ()))
4415 FOR_EACH_TAIL (options) 4468 FOR_EACH_TAIL (options)
@@ -4422,6 +4475,43 @@ add_driver_options (void)
4422#endif 4475#endif
4423} 4476}
4424 4477
4478static void
4479add_compiler_options (void)
4480{
4481 Lisp_Object options = Fsymbol_value (Qnative_comp_compiler_options);
4482
4483#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option)
4484 load_gccjit_if_necessary (true);
4485 if (!NILP (Fcomp_native_compiler_options_effective_p ()))
4486 FOR_EACH_TAIL (options)
4487 gcc_jit_context_add_command_line_option (comp.ctxt,
4488 /* FIXME: Need to encode
4489 this, but how? either
4490 ENCODE_FILE or
4491 ENCODE_SYSTEM. */
4492 SSDATA (XCAR (options)));
4493#endif
4494 if (CONSP (options))
4495 xsignal1 (Qnative_compiler_error,
4496 build_string ("Customizing native compiler options"
4497 " via `comp-native-compiler-options' is"
4498 " only available on libgccjit version 9"
4499 " and above."));
4500
4501 /* Captured `comp-native-compiler-options' because file-local. */
4502#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option)
4503 options = comp.compiler_options;
4504 if (!NILP (Fcomp_native_compiler_options_effective_p ()))
4505 FOR_EACH_TAIL (options)
4506 gcc_jit_context_add_command_line_option (comp.ctxt,
4507 /* FIXME: Need to encode
4508 this, but how? either
4509 ENCODE_FILE or
4510 ENCODE_SYSTEM. */
4511 SSDATA (XCAR (options)));
4512#endif
4513}
4514
4425DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, 4515DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4426 Scomp__compile_ctxt_to_file, 4516 Scomp__compile_ctxt_to_file,
4427 1, 1, 0, 4517 1, 1, 0,
@@ -4467,6 +4557,7 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4467 comp.debug = XFIXNUM (CALL1I (comp-ctxt-debug, Vcomp_ctxt)); 4557 comp.debug = XFIXNUM (CALL1I (comp-ctxt-debug, Vcomp_ctxt));
4468 eassert (comp.debug < INT_MAX); 4558 eassert (comp.debug < INT_MAX);
4469 comp.driver_options = CALL1I (comp-ctxt-driver-options, Vcomp_ctxt); 4559 comp.driver_options = CALL1I (comp-ctxt-driver-options, Vcomp_ctxt);
4560 comp.compiler_options = CALL1I (comp-ctxt-compiler-options, Vcomp_ctxt);
4470 4561
4471 if (comp.debug) 4562 if (comp.debug)
4472 gcc_jit_context_set_bool_option (comp.ctxt, 4563 gcc_jit_context_set_bool_option (comp.ctxt,
@@ -4490,6 +4581,15 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4490 GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 4581 GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
4491 comp.speed < 0 ? 0 4582 comp.speed < 0 ? 0
4492 : (comp.speed > 3 ? 3 : comp.speed)); 4583 : (comp.speed > 3 ? 3 : comp.speed));
4584
4585 /* On MacOS set a unique dylib ID. */
4586#if defined (LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option) \
4587 && defined (DARWIN_OS)
4588 gcc_jit_context_add_driver_option (comp.ctxt, "-install_name");
4589 gcc_jit_context_add_driver_option (
4590 comp.ctxt, SSDATA (Ffile_name_nondirectory (filename)));
4591#endif
4592
4493 comp.d_default_idx = 4593 comp.d_default_idx =
4494 CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-default, Vcomp_ctxt)); 4594 CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-default, Vcomp_ctxt));
4495 comp.d_impure_idx = 4595 comp.d_impure_idx =
@@ -4523,8 +4623,7 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4523 4623
4524 /* Work around bug#46495 (GCC PR99126). */ 4624 /* Work around bug#46495 (GCC PR99126). */
4525#if defined (WIDE_EMACS_INT) \ 4625#if defined (WIDE_EMACS_INT) \
4526 && (defined (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option) \ 4626 && defined (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option)
4527 || defined (WINDOWSNT))
4528 Lisp_Object version = Fcomp_libgccjit_version (); 4627 Lisp_Object version = Fcomp_libgccjit_version ();
4529 if (NILP (version) 4628 if (NILP (version)
4530 || XFIXNUM (XCAR (version)) < 11) 4629 || XFIXNUM (XCAR (version)) < 11)
@@ -4532,6 +4631,7 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
4532 "-fdisable-tree-isolate-paths"); 4631 "-fdisable-tree-isolate-paths");
4533#endif 4632#endif
4534 4633
4634 add_compiler_options ();
4535 add_driver_options (); 4635 add_driver_options ();
4536 4636
4537 if (comp.debug > 1) 4637 if (comp.debug > 1)
@@ -4575,7 +4675,7 @@ The return value has the form (MAJOR MINOR PATCHLEVEL) or nil if
4575unknown (before GCC version 10). */) 4675unknown (before GCC version 10). */)
4576 (void) 4676 (void)
4577{ 4677{
4578#if defined (LIBGCCJIT_HAVE_gcc_jit_version) || defined (WINDOWSNT) 4678#if defined (LIBGCCJIT_HAVE_gcc_jit_version)
4579 load_gccjit_if_necessary (true); 4679 load_gccjit_if_necessary (true);
4580 4680
4581 return gcc_jit_version_major 4681 return gcc_jit_version_major
@@ -4635,7 +4735,7 @@ helper_PSEUDOVECTOR_TYPEP_XUNTAG (Lisp_Object a, enum pvec_type code)
4635} 4735}
4636 4736
4637 4737
4638/* `comp-eln-load-path' clean-up support code. */ 4738/* `native-comp-eln-load-path' clean-up support code. */
4639 4739
4640static Lisp_Object all_loaded_comp_units_h; 4740static Lisp_Object all_loaded_comp_units_h;
4641 4741
@@ -4650,7 +4750,7 @@ return_nil (Lisp_Object arg)
4650/* Windows does not let us delete a .eln file that is currently loaded 4750/* Windows does not let us delete a .eln file that is currently loaded
4651 by a process. The strategy is to rename .eln files into .old.eln 4751 by a process. The strategy is to rename .eln files into .old.eln
4652 instead of removing them when this is not possible and clean-up 4752 instead of removing them when this is not possible and clean-up
4653 `comp-eln-load-path' when exiting. 4753 `native-comp-eln-load-path' when exiting.
4654 4754
4655 Any error is ignored because it may be due to the file being loaded 4755 Any error is ignored because it may be due to the file being loaded
4656 in another Emacs instance. */ 4756 in another Emacs instance. */
@@ -4778,7 +4878,7 @@ maybe_defer_native_compilation (Lisp_Object function_name,
4778/**************************************/ 4878/**************************************/
4779 4879
4780/* Fixup the system eln-cache directory, which is the last entry in 4880/* Fixup the system eln-cache directory, which is the last entry in
4781 `comp-eln-load-path'. Argument is a .eln file in that directory. */ 4881 `native-comp-eln-load-path'. Argument is a .eln file in that directory. */
4782void 4882void
4783fixup_eln_load_path (Lisp_Object eln_filename) 4883fixup_eln_load_path (Lisp_Object eln_filename)
4784{ 4884{
@@ -5160,7 +5260,8 @@ file_in_eln_sys_dir (Lisp_Object filename)
5160 eln_sys_dir = XCAR (tmp); 5260 eln_sys_dir = XCAR (tmp);
5161 return !NILP (Fstring_match (Fregexp_quote (Fexpand_file_name (eln_sys_dir, 5261 return !NILP (Fstring_match (Fregexp_quote (Fexpand_file_name (eln_sys_dir,
5162 Qnil)), 5262 Qnil)),
5163 Fexpand_file_name (filename, Qnil), Qnil)); 5263 Fexpand_file_name (filename, Qnil),
5264 Qnil, Qnil));
5164} 5265}
5165 5266
5166/* Load related routines. */ 5267/* Load related routines. */
@@ -5239,6 +5340,7 @@ compiled one. */);
5239 DEFSYM (Qnative_comp_speed, "native-comp-speed"); 5340 DEFSYM (Qnative_comp_speed, "native-comp-speed");
5240 DEFSYM (Qnative_comp_debug, "native-comp-debug"); 5341 DEFSYM (Qnative_comp_debug, "native-comp-debug");
5241 DEFSYM (Qnative_comp_driver_options, "native-comp-driver-options"); 5342 DEFSYM (Qnative_comp_driver_options, "native-comp-driver-options");
5343 DEFSYM (Qnative_comp_compiler_options, "native-comp-compiler-options");
5242 DEFSYM (Qcomp_libgccjit_reproducer, "comp-libgccjit-reproducer"); 5344 DEFSYM (Qcomp_libgccjit_reproducer, "comp-libgccjit-reproducer");
5243 5345
5244 /* Limple instruction set. */ 5346 /* Limple instruction set. */
@@ -5348,6 +5450,7 @@ compiled one. */);
5348 defsubr (&Scomp_el_to_eln_rel_filename); 5450 defsubr (&Scomp_el_to_eln_rel_filename);
5349 defsubr (&Scomp_el_to_eln_filename); 5451 defsubr (&Scomp_el_to_eln_filename);
5350 defsubr (&Scomp_native_driver_options_effective_p); 5452 defsubr (&Scomp_native_driver_options_effective_p);
5453 defsubr (&Scomp_native_compiler_options_effective_p);
5351 defsubr (&Scomp__install_trampoline); 5454 defsubr (&Scomp__install_trampoline);
5352 defsubr (&Scomp__init_ctxt); 5455 defsubr (&Scomp__init_ctxt);
5353 defsubr (&Scomp__release_ctxt); 5456 defsubr (&Scomp__release_ctxt);
diff --git a/src/composite.c b/src/composite.c
index 129e9d6bb25..c170805d9dd 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -882,14 +882,15 @@ fill_gstring_body (Lisp_Object gstring)
882/* Try to compose the characters at CHARPOS according to composition 882/* Try to compose the characters at CHARPOS according to composition
883 rule RULE ([PATTERN PREV-CHARS FUNC]). LIMIT limits the characters 883 rule RULE ([PATTERN PREV-CHARS FUNC]). LIMIT limits the characters
884 to compose. STRING, if not nil, is a target string. WIN is a 884 to compose. STRING, if not nil, is a target string. WIN is a
885 window where the characters are being displayed. If characters are 885 window where the characters are being displayed. CH is the
886 character that triggered the composition check. If characters are
886 successfully composed, return the composition as a glyph-string 887 successfully composed, return the composition as a glyph-string
887 object. Otherwise return nil. */ 888 object. Otherwise return nil. */
888 889
889static Lisp_Object 890static Lisp_Object
890autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos, 891autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
891 ptrdiff_t limit, struct window *win, struct face *face, 892 ptrdiff_t limit, struct window *win, struct face *face,
892 Lisp_Object string, Lisp_Object direction) 893 Lisp_Object string, Lisp_Object direction, int ch)
893{ 894{
894 ptrdiff_t count = SPECPDL_INDEX (); 895 ptrdiff_t count = SPECPDL_INDEX ();
895 Lisp_Object pos = make_fixnum (charpos); 896 Lisp_Object pos = make_fixnum (charpos);
@@ -920,7 +921,7 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
920 struct frame *f = XFRAME (font_object); 921 struct frame *f = XFRAME (font_object);
921 if (FRAME_WINDOW_P (f)) 922 if (FRAME_WINDOW_P (f))
922 { 923 {
923 font_object = font_range (charpos, bytepos, &to, win, face, string); 924 font_object = font_range (charpos, bytepos, &to, win, face, string, ch);
924 if (! FONT_OBJECT_P (font_object) 925 if (! FONT_OBJECT_P (font_object)
925 || (! NILP (re) 926 || (! NILP (re)
926 && to < limit 927 && to < limit
@@ -953,6 +954,9 @@ char_composable_p (int c)
953 Lisp_Object val; 954 Lisp_Object val;
954 return (c >= ' ' 955 return (c >= ' '
955 && (c == ZERO_WIDTH_NON_JOINER || c == ZERO_WIDTH_JOINER 956 && (c == ZERO_WIDTH_NON_JOINER || c == ZERO_WIDTH_JOINER
957 /* Per Unicode TR51, these tag characters can be part of
958 Emoji sequences. */
959 || (TAG_SPACE <= c && c <= CANCEL_TAG)
956 /* unicode-category-table may not be available during 960 /* unicode-category-table may not be available during
957 dumping. */ 961 dumping. */
958 || (CHAR_TABLE_P (Vunicode_category_table) 962 || (CHAR_TABLE_P (Vunicode_category_table)
@@ -961,6 +965,23 @@ char_composable_p (int c)
961 && (XFIXNUM (val) <= UNICODE_CATEGORY_Zs)))))); 965 && (XFIXNUM (val) <= UNICODE_CATEGORY_Zs))))));
962} 966}
963 967
968static inline bool
969inhibit_auto_composition (void)
970{
971 if (NILP (Vauto_composition_mode))
972 return true;
973
974 if (STRINGP (Vauto_composition_mode))
975 {
976 char *name = tty_type_name (Qnil);
977
978 if (name && ! strcmp (SSDATA (Vauto_composition_mode), name))
979 return true;
980 }
981
982 return false;
983}
984
964/* Update cmp_it->stop_pos to the next position after CHARPOS (and 985/* Update cmp_it->stop_pos to the next position after CHARPOS (and
965 BYTEPOS) where character composition may happen. If BYTEPOS is 986 BYTEPOS) where character composition may happen. If BYTEPOS is
966 negative, compute it. ENDPOS is a limit of searching. If it is 987 negative, compute it. ENDPOS is a limit of searching. If it is
@@ -1015,7 +1036,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
1015 cmp_it->ch = -1; 1036 cmp_it->ch = -1;
1016 } 1037 }
1017 if (NILP (BVAR (current_buffer, enable_multibyte_characters)) 1038 if (NILP (BVAR (current_buffer, enable_multibyte_characters))
1018 || NILP (Vauto_composition_mode)) 1039 || inhibit_auto_composition ())
1019 return; 1040 return;
1020 if (bytepos < 0) 1041 if (bytepos < 0)
1021 { 1042 {
@@ -1252,7 +1273,7 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
1252 if (XFIXNAT (AREF (elt, 1)) != cmp_it->lookback) 1273 if (XFIXNAT (AREF (elt, 1)) != cmp_it->lookback)
1253 goto no_composition; 1274 goto no_composition;
1254 lgstring = autocmp_chars (elt, charpos, bytepos, endpos, 1275 lgstring = autocmp_chars (elt, charpos, bytepos, endpos,
1255 w, face, string, direction); 1276 w, face, string, direction, cmp_it->ch);
1256 if (composition_gstring_p (lgstring)) 1277 if (composition_gstring_p (lgstring))
1257 break; 1278 break;
1258 lgstring = Qnil; 1279 lgstring = Qnil;
@@ -1290,7 +1311,7 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
1290 else 1311 else
1291 direction = QR2L; 1312 direction = QR2L;
1292 lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face, 1313 lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
1293 string, direction); 1314 string, direction, cmp_it->ch);
1294 if (! composition_gstring_p (lgstring) 1315 if (! composition_gstring_p (lgstring)
1295 || cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos) 1316 || cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos)
1296 /* Composition failed or didn't cover the current 1317 /* Composition failed or didn't cover the current
@@ -1659,7 +1680,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
1659 for (check = cur; check_pos < check.pos; ) 1680 for (check = cur; check_pos < check.pos; )
1660 BACKWARD_CHAR (check, stop); 1681 BACKWARD_CHAR (check, stop);
1661 *gstring = autocmp_chars (elt, check.pos, check.pos_byte, 1682 *gstring = autocmp_chars (elt, check.pos, check.pos_byte,
1662 tail, w, NULL, string, Qnil); 1683 tail, w, NULL, string, Qnil, c);
1663 need_adjustment = 1; 1684 need_adjustment = 1;
1664 if (NILP (*gstring)) 1685 if (NILP (*gstring))
1665 { 1686 {
@@ -1741,7 +1762,7 @@ composition_adjust_point (ptrdiff_t last_pt, ptrdiff_t new_pt)
1741 } 1762 }
1742 1763
1743 if (NILP (BVAR (current_buffer, enable_multibyte_characters)) 1764 if (NILP (BVAR (current_buffer, enable_multibyte_characters))
1744 || NILP (Vauto_composition_mode)) 1765 || inhibit_auto_composition ())
1745 return new_pt; 1766 return new_pt;
1746 1767
1747 /* Next check the automatic composition. */ 1768 /* Next check the automatic composition. */
@@ -1941,7 +1962,7 @@ See `find-composition' for more details. */)
1941 if (!find_composition (from, to, &start, &end, &prop, string)) 1962 if (!find_composition (from, to, &start, &end, &prop, string))
1942 { 1963 {
1943 if (!NILP (BVAR (current_buffer, enable_multibyte_characters)) 1964 if (!NILP (BVAR (current_buffer, enable_multibyte_characters))
1944 && ! NILP (Vauto_composition_mode) 1965 && ! inhibit_auto_composition ()
1945 && find_automatic_composition (from, to, (ptrdiff_t) -1, 1966 && find_automatic_composition (from, to, (ptrdiff_t) -1,
1946 &start, &end, &gstring, string)) 1967 &start, &end, &gstring, string))
1947 return list3 (make_fixnum (start), make_fixnum (end), gstring); 1968 return list3 (make_fixnum (start), make_fixnum (end), gstring);
@@ -2040,7 +2061,10 @@ The default value is the function `compose-chars-after'. */);
2040 2061
2041 DEFVAR_LISP ("auto-composition-mode", Vauto_composition_mode, 2062 DEFVAR_LISP ("auto-composition-mode", Vauto_composition_mode,
2042 doc: /* Non-nil if Auto-Composition mode is enabled. 2063 doc: /* Non-nil if Auto-Composition mode is enabled.
2043Use the command `auto-composition-mode' to change this variable. */); 2064Use the command `auto-composition-mode' to change this variable.
2065
2066If this variable is a string, `auto-composition-mode' will be disabled in
2067buffers displayed on a terminal whose type compares equal to this string. */);
2044 Vauto_composition_mode = Qt; 2068 Vauto_composition_mode = Qt;
2045 2069
2046 DEFVAR_LISP ("auto-composition-function", Vauto_composition_function, 2070 DEFVAR_LISP ("auto-composition-function", Vauto_composition_function,
@@ -2100,6 +2124,17 @@ GSTRING, or modify GSTRING itself and return it.
2100See also the documentation of `auto-composition-mode'. */); 2124See also the documentation of `auto-composition-mode'. */);
2101 Vcomposition_function_table = Fmake_char_table (Qnil, Qnil); 2125 Vcomposition_function_table = Fmake_char_table (Qnil, Qnil);
2102 2126
2127 DEFVAR_LISP ("auto-composition-emoji-eligible-codepoints", Vauto_composition_emoji_eligible_codepoints,
2128 doc: /* List of codepoints for which auto-composition will check for an emoji font.
2129
2130These are codepoints which have Emoji_Presentation = No, and thus by
2131default are not displayed as emoji. In certain circumstances, such as
2132when followed by U+FE0F (VS-16) the emoji font should be used for
2133them anyway.
2134
2135This list is auto-generated, you should not need to modify it. */);
2136 Vauto_composition_emoji_eligible_codepoints = Qnil;
2137
2103 defsubr (&Scompose_region_internal); 2138 defsubr (&Scompose_region_internal);
2104 defsubr (&Scompose_string_internal); 2139 defsubr (&Scompose_string_internal);
2105 defsubr (&Sfind_composition_internal); 2140 defsubr (&Sfind_composition_internal);
diff --git a/src/composite.h b/src/composite.h
index 67e87201bf2..945f2612915 100644
--- a/src/composite.h
+++ b/src/composite.h
@@ -254,6 +254,10 @@ composition_valid_p (ptrdiff_t start, ptrdiff_t end, Lisp_Object prop)
254#define LGSTRING_HEADER(lgs) AREF (lgs, 0) 254#define LGSTRING_HEADER(lgs) AREF (lgs, 0)
255#define LGSTRING_SET_HEADER(lgs, header) ASET (lgs, 0, header) 255#define LGSTRING_SET_HEADER(lgs, header) ASET (lgs, 0, header)
256 256
257/* LGSTRING_FONT retrieves the font used for LGSTRING, if we are going
258 to display it on a GUI frame. On text-mode frames, that slot
259 stores the coding-system that should be used to write output to the
260 frame's terminal. */
257#define LGSTRING_FONT(lgs) AREF (LGSTRING_HEADER (lgs), 0) 261#define LGSTRING_FONT(lgs) AREF (LGSTRING_HEADER (lgs), 0)
258#define LGSTRING_CHAR(lgs, i) AREF (LGSTRING_HEADER (lgs), (i) + 1) 262#define LGSTRING_CHAR(lgs, i) AREF (LGSTRING_HEADER (lgs), (i) + 1)
259#define LGSTRING_CHAR_LEN(lgs) (ASIZE (LGSTRING_HEADER (lgs)) - 1) 263#define LGSTRING_CHAR_LEN(lgs) (ASIZE (LGSTRING_HEADER (lgs)) - 1)
diff --git a/src/conf_post.h b/src/conf_post.h
index 8558dc466cc..2c6fbb0dba5 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -293,7 +293,6 @@ extern int emacs_setenv_TZ (char const *);
293 ATTRIBUTE_FORMAT ((PRINTF_ARCHETYPE, string_index, first_to_check)) 293 ATTRIBUTE_FORMAT ((PRINTF_ARCHETYPE, string_index, first_to_check))
294 294
295#define ARG_NONNULL ATTRIBUTE_NONNULL 295#define ARG_NONNULL ATTRIBUTE_NONNULL
296#define ATTRIBUTE_UNUSED MAYBE_UNUSED
297 296
298/* Declare NAME to be a pointer to an object of type TYPE, initialized 297/* Declare NAME to be a pointer to an object of type TYPE, initialized
299 to the address ADDR, which may be of a different type. Accesses 298 to the address ADDR, which may be of a different type. Accesses
diff --git a/src/data.c b/src/data.c
index ffca7e75355..0d3376f0903 100644
--- a/src/data.c
+++ b/src/data.c
@@ -681,7 +681,7 @@ global value outside of any lexical scope. */)
681/* It has been previously suggested to make this function an alias for 681/* It has been previously suggested to make this function an alias for
682 symbol-function, but upon discussion at Bug#23957, there is a risk 682 symbol-function, but upon discussion at Bug#23957, there is a risk
683 breaking backward compatibility, as some users of fboundp may 683 breaking backward compatibility, as some users of fboundp may
684 expect `t' in particular, rather than any true value. */ 684 expect t in particular, rather than any true value. */
685DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, 685DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0,
686 doc: /* Return t if SYMBOL's function definition is not void. */) 686 doc: /* Return t if SYMBOL's function definition is not void. */)
687 (Lisp_Object symbol) 687 (Lisp_Object symbol)
@@ -1045,6 +1045,8 @@ The value, if non-nil, is a list of mode name symbols. */)
1045 1045
1046 if (COMPILEDP (fun)) 1046 if (COMPILEDP (fun))
1047 { 1047 {
1048 if (PVSIZE (fun) <= COMPILED_INTERACTIVE)
1049 return Qnil;
1048 Lisp_Object form = AREF (fun, COMPILED_INTERACTIVE); 1050 Lisp_Object form = AREF (fun, COMPILED_INTERACTIVE);
1049 if (VECTORP (form)) 1051 if (VECTORP (form))
1050 /* New form -- the second element is the command modes. */ 1052 /* New form -- the second element is the command modes. */
diff --git a/src/dispextern.h b/src/dispextern.h
index c8cefec37f4..ef4d7d915f6 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -544,8 +544,8 @@ struct glyph
544 int img_id; 544 int img_id;
545 545
546#ifdef HAVE_XWIDGETS 546#ifdef HAVE_XWIDGETS
547 /* Xwidget reference (type == XWIDGET_GLYPH). */ 547 /* Xwidget ID. */
548 struct xwidget *xwidget; 548 uint32_t xwidget;
549#endif 549#endif
550 550
551 /* Sub-structure for type == STRETCH_GLYPH. */ 551 /* Sub-structure for type == STRETCH_GLYPH. */
@@ -1334,7 +1334,9 @@ struct glyph_string
1334 /* The area within row. */ 1334 /* The area within row. */
1335 enum glyph_row_area area; 1335 enum glyph_row_area area;
1336 1336
1337 /* Characters to be drawn, and number of characters. */ 1337 /* Characters to be drawn, and number of characters. Note that
1338 NCHARS can be zero if this is a composition glyph string, as
1339 evidenced by FIRST_GLYPH->type. */
1338 unsigned *char2b; 1340 unsigned *char2b;
1339 int nchars; 1341 int nchars;
1340 1342
@@ -3171,7 +3173,7 @@ struct image_cache
3171 3173
3172/* Size of bucket vector of image caches. Should be prime. */ 3174/* Size of bucket vector of image caches. Should be prime. */
3173 3175
3174#define IMAGE_CACHE_BUCKETS_SIZE 1001 3176#define IMAGE_CACHE_BUCKETS_SIZE 1009
3175 3177
3176#endif /* HAVE_WINDOW_SYSTEM */ 3178#endif /* HAVE_WINDOW_SYSTEM */
3177 3179
@@ -3213,7 +3215,7 @@ enum tab_bar_item_idx
3213 3215
3214/* Default values of the above variables. */ 3216/* Default values of the above variables. */
3215 3217
3216#define DEFAULT_TAB_BAR_BUTTON_MARGIN 4 3218#define DEFAULT_TAB_BAR_BUTTON_MARGIN 1
3217#define DEFAULT_TAB_BAR_BUTTON_RELIEF 1 3219#define DEFAULT_TAB_BAR_BUTTON_RELIEF 1
3218 3220
3219/* The height in pixels of the default tab-bar images. */ 3221/* The height in pixels of the default tab-bar images. */
@@ -3426,8 +3428,8 @@ extern void get_glyph_string_clip_rect (struct glyph_string *,
3426 NativeRectangle *nr); 3428 NativeRectangle *nr);
3427extern Lisp_Object find_hot_spot (Lisp_Object, int, int); 3429extern Lisp_Object find_hot_spot (Lisp_Object, int, int);
3428 3430
3429extern void handle_tab_bar_click (struct frame *, 3431extern Lisp_Object handle_tab_bar_click (struct frame *,
3430 int, int, bool, int); 3432 int, int, bool, int);
3431extern void handle_tool_bar_click (struct frame *, 3433extern void handle_tool_bar_click (struct frame *,
3432 int, int, bool, int); 3434 int, int, bool, int);
3433 3435
@@ -3731,10 +3733,8 @@ extern Lisp_Object gui_default_parameter (struct frame *, Lisp_Object,
3731 const char *, const char *, 3733 const char *, const char *,
3732 enum resource_types); 3734 enum resource_types);
3733 3735
3734#ifndef HAVE_NS /* These both used on W32 and X only. */
3735extern bool gui_mouse_grabbed (Display_Info *); 3736extern bool gui_mouse_grabbed (Display_Info *);
3736extern void gui_redo_mouse_highlight (Display_Info *); 3737extern void gui_redo_mouse_highlight (Display_Info *);
3737#endif /* HAVE_NS */
3738 3738
3739#endif /* HAVE_WINDOW_SYSTEM */ 3739#endif /* HAVE_WINDOW_SYSTEM */
3740 3740
diff --git a/src/dispnew.c b/src/dispnew.c
index b79d0c41707..92d9eb1f700 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -475,7 +475,8 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
475 = row->glyphs[TEXT_AREA] + dim.width - left - right; 475 = row->glyphs[TEXT_AREA] + dim.width - left - right;
476 /* Leave room for a border glyph. */ 476 /* Leave room for a border glyph. */
477 if (!FRAME_WINDOW_P (XFRAME (w->frame)) 477 if (!FRAME_WINDOW_P (XFRAME (w->frame))
478 && !WINDOW_RIGHTMOST_P (w)) 478 && !WINDOW_RIGHTMOST_P (w)
479 && right > 0)
479 row->glyphs[RIGHT_MARGIN_AREA] -= 1; 480 row->glyphs[RIGHT_MARGIN_AREA] -= 1;
480 row->glyphs[LAST_AREA] 481 row->glyphs[LAST_AREA]
481 = row->glyphs[LEFT_MARGIN_AREA] + dim.width; 482 = row->glyphs[LEFT_MARGIN_AREA] + dim.width;
@@ -1148,7 +1149,8 @@ prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p)
1148 row->glyphs[RIGHT_MARGIN_AREA] = row->glyphs[LAST_AREA] - right; 1149 row->glyphs[RIGHT_MARGIN_AREA] = row->glyphs[LAST_AREA] - right;
1149 /* Leave room for a border glyph. */ 1150 /* Leave room for a border glyph. */
1150 if (!FRAME_WINDOW_P (XFRAME (w->frame)) 1151 if (!FRAME_WINDOW_P (XFRAME (w->frame))
1151 && !WINDOW_RIGHTMOST_P (w)) 1152 && !WINDOW_RIGHTMOST_P (w)
1153 && right > 0)
1152 row->glyphs[RIGHT_MARGIN_AREA] -= 1; 1154 row->glyphs[RIGHT_MARGIN_AREA] -= 1;
1153 } 1155 }
1154 } 1156 }
@@ -3848,6 +3850,9 @@ gui_update_window_end (struct window *w, bool cursor_on_p,
3848 w->output_cursor.hpos, w->output_cursor.vpos, 3850 w->output_cursor.hpos, w->output_cursor.vpos,
3849 w->output_cursor.x, w->output_cursor.y); 3851 w->output_cursor.x, w->output_cursor.y);
3850 3852
3853 if (cursor_in_mouse_face_p (w) && cursor_on_p)
3854 mouse_face_overwritten_p = 1;
3855
3851 if (draw_window_fringes (w, true)) 3856 if (draw_window_fringes (w, true))
3852 { 3857 {
3853 if (WINDOW_RIGHT_DIVIDER_WIDTH (w)) 3858 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
@@ -4444,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p)
4444 break; 4449 break;
4445 } 4450 }
4446 4451
4447#ifdef HAVE_XWIDGETS
4448 /* Currently this seems needed to detect xwidget movement reliably.
4449 This is most probably because an xwidget glyph is represented in
4450 struct glyph's 'union u' by a pointer to a struct, which takes 8
4451 bytes in 64-bit builds, and thus the comparison of u.val values
4452 done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the
4453 size of the union is 4 bytes. FIXME. */
4454 return 0;
4455#endif
4456
4457 /* Can't scroll the display of w32 GUI frames when position of point 4452 /* Can't scroll the display of w32 GUI frames when position of point
4458 is indicated by the system caret, because scrolling the display 4453 is indicated by the system caret, because scrolling the display
4459 will then "copy" the pixels used by the caret. */ 4454 will then "copy" the pixels used by the caret. */
@@ -6717,7 +6712,7 @@ See `buffer-display-table' for more information. */);
6717 6712
6718 DEFVAR_LISP ("tab-bar-position", Vtab_bar_position, 6713 DEFVAR_LISP ("tab-bar-position", Vtab_bar_position,
6719 doc: /* Specify on which side from the tool bar the tab bar shall be. 6714 doc: /* Specify on which side from the tool bar the tab bar shall be.
6720Possible values are `t' (below the tool bar), `nil' (above the tool bar). 6715Possible values are t (below the tool bar), nil (above the tool bar).
6721This option affects only builds where the tool bar is not external. */); 6716This option affects only builds where the tool bar is not external. */);
6722 6717
6723 pdumper_do_now_and_after_load (syms_of_display_for_pdumper); 6718 pdumper_do_now_and_after_load (syms_of_display_for_pdumper);
diff --git a/src/editfns.c b/src/editfns.c
index 8ab17ebc9f9..c8219decb06 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2371,7 +2371,7 @@ Both characters must have the same length of multi-byte form. */)
2371 /* replace_range is less efficient, because it moves the gap, 2371 /* replace_range is less efficient, because it moves the gap,
2372 but it handles combining correctly. */ 2372 but it handles combining correctly. */
2373 replace_range (pos, pos + 1, string, 2373 replace_range (pos, pos + 1, string,
2374 false, false, true, false); 2374 false, false, true, false, false);
2375 pos_byte_next = CHAR_TO_BYTE (pos); 2375 pos_byte_next = CHAR_TO_BYTE (pos);
2376 if (pos_byte_next > pos_byte) 2376 if (pos_byte_next > pos_byte)
2377 /* Before combining happened. We should not increment 2377 /* Before combining happened. We should not increment
@@ -2578,7 +2578,7 @@ It returns the number of characters changed. */)
2578 but it should handle multibyte characters correctly. */ 2578 but it should handle multibyte characters correctly. */
2579 string = make_multibyte_string ((char *) str, 1, str_len); 2579 string = make_multibyte_string ((char *) str, 1, str_len);
2580 replace_range (pos, pos + 1, string, 2580 replace_range (pos, pos + 1, string,
2581 true, false, true, false); 2581 true, false, true, false, false);
2582 len = str_len; 2582 len = str_len;
2583 } 2583 }
2584 else 2584 else
@@ -2613,7 +2613,8 @@ It returns the number of characters changed. */)
2613 = (VECTORP (val) 2613 = (VECTORP (val)
2614 ? Fconcat (1, &val) 2614 ? Fconcat (1, &val)
2615 : Fmake_string (make_fixnum (1), val, Qnil)); 2615 : Fmake_string (make_fixnum (1), val, Qnil));
2616 replace_range (pos, pos + len, string, true, false, true, false); 2616 replace_range (pos, pos + len, string, true, false, true, false,
2617 false);
2617 pos_byte += SBYTES (string); 2618 pos_byte += SBYTES (string);
2618 pos += SCHARS (string); 2619 pos += SCHARS (string);
2619 characters_changed += SCHARS (string); 2620 characters_changed += SCHARS (string);
diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in
index fe52587c1a5..a56e4dd12ae 100644
--- a/src/emacs-module.h.in
+++ b/src/emacs-module.h.in
@@ -169,6 +169,19 @@ struct emacs_env_28
169@module_env_snippet_28@ 169@module_env_snippet_28@
170}; 170};
171 171
172struct emacs_env_29
173{
174@module_env_snippet_25@
175
176@module_env_snippet_26@
177
178@module_env_snippet_27@
179
180@module_env_snippet_28@
181
182@module_env_snippet_29@
183};
184
172/* Every module should define a function as follows. */ 185/* Every module should define a function as follows. */
173extern int emacs_module_init (struct emacs_runtime *runtime) 186extern int emacs_module_init (struct emacs_runtime *runtime)
174 EMACS_NOEXCEPT 187 EMACS_NOEXCEPT
diff --git a/src/emacs.c b/src/emacs.c
index 7fd004973d9..925f167d5fa 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -133,6 +133,7 @@ extern char etext;
133#endif 133#endif
134 134
135#include "pdumper.h" 135#include "pdumper.h"
136#include "fingerprint.h"
136#include "epaths.h" 137#include "epaths.h"
137 138
138static const char emacs_version[] = PACKAGE_VERSION; 139static const char emacs_version[] = PACKAGE_VERSION;
@@ -255,6 +256,7 @@ Initialization options:\n\
255#ifdef HAVE_PDUMPER 256#ifdef HAVE_PDUMPER
256 "\ 257 "\
257--dump-file FILE read dumped state from FILE\n\ 258--dump-file FILE read dumped state from FILE\n\
259--fingerprint output fingerprint and exit\n\
258", 260",
259#endif 261#endif
260#if SECCOMP_USABLE 262#if SECCOMP_USABLE
@@ -830,6 +832,8 @@ load_pdump (int argc, char **argv)
830 const char *const suffix = ".pdmp"; 832 const char *const suffix = ".pdmp";
831 int result; 833 int result;
832 char *emacs_executable = argv[0]; 834 char *emacs_executable = argv[0];
835 ptrdiff_t hexbuf_size;
836 char *hexbuf;
833 const char *strip_suffix = 837 const char *strip_suffix =
834#if defined DOS_NT || defined CYGWIN 838#if defined DOS_NT || defined CYGWIN
835 ".exe" 839 ".exe"
@@ -924,12 +928,18 @@ load_pdump (int argc, char **argv)
924 path_exec = ns_relocate (path_exec); 928 path_exec = ns_relocate (path_exec);
925#endif 929#endif
926 930
927 /* Look for "emacs.pdmp" in PATH_EXEC. We hardcode "emacs" in 931 /* Look for "emacs-FINGERPRINT.pdmp" in PATH_EXEC. We hardcode
928 "emacs.pdmp" so that the Emacs binary still works if the user 932 "emacs" in "emacs-FINGERPRINT.pdmp" so that the Emacs binary
929 copies and renames it. */ 933 still works if the user copies and renames it. */
934 hexbuf_size = 2 * sizeof fingerprint;
935 hexbuf = xmalloc (hexbuf_size + 1);
936 hexbuf_digest (hexbuf, (char *) fingerprint, sizeof fingerprint);
937 hexbuf[hexbuf_size] = '\0';
930 needed = (strlen (path_exec) 938 needed = (strlen (path_exec)
931 + 1 939 + 1
932 + strlen (argv0_base) 940 + strlen (argv0_base)
941 + 1
942 + strlen (hexbuf)
933 + strlen (suffix) 943 + strlen (suffix)
934 + 1); 944 + 1);
935 if (bufsize < needed) 945 if (bufsize < needed)
@@ -937,8 +947,8 @@ load_pdump (int argc, char **argv)
937 xfree (dump_file); 947 xfree (dump_file);
938 dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1); 948 dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1);
939 } 949 }
940 sprintf (dump_file, "%s%c%s%s", 950 sprintf (dump_file, "%s%c%s-%s%s",
941 path_exec, DIRECTORY_SEP, argv0_base, suffix); 951 path_exec, DIRECTORY_SEP, argv0_base, hexbuf, suffix);
942#if !defined (NS_SELF_CONTAINED) 952#if !defined (NS_SELF_CONTAINED)
943 /* Assume the Emacs binary lives in a sibling directory as set up by 953 /* Assume the Emacs binary lives in a sibling directory as set up by
944 the default installation configuration. */ 954 the default installation configuration. */
@@ -1387,6 +1397,24 @@ main (int argc, char **argv)
1387 exit (0); 1397 exit (0);
1388 } 1398 }
1389 1399
1400#ifdef HAVE_PDUMPER
1401 if (argmatch (argv, argc, "-fingerprint", "--fingerprint", 4,
1402 NULL, &skip_args))
1403 {
1404 if (initialized)
1405 {
1406 dump_fingerprint (stdout, "",
1407 (unsigned char *) fingerprint);
1408 exit (0);
1409 }
1410 else
1411 {
1412 fputs ("Not initialized\n", stderr);
1413 exit (1);
1414 }
1415 }
1416#endif
1417
1390 emacs_wd = emacs_get_current_dir_name (); 1418 emacs_wd = emacs_get_current_dir_name ();
1391#ifdef HAVE_PDUMPER 1419#ifdef HAVE_PDUMPER
1392 if (dumped_with_pdumper_p ()) 1420 if (dumped_with_pdumper_p ())
@@ -1847,7 +1875,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1847#ifdef HAVE_PGTK 1875#ifdef HAVE_PGTK
1848 init_pgtkterm (); /* before init_atimer(). */ 1876 init_pgtkterm (); /* before init_atimer(). */
1849#endif 1877#endif
1850 init_atimer ();
1851 running_asynch_code = 0; 1878 running_asynch_code = 0;
1852 init_random (); 1879 init_random ();
1853 1880
@@ -2009,6 +2036,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2009 if (!will_dump_p ()) 2036 if (!will_dump_p ())
2010 set_initial_environment (); 2037 set_initial_environment ();
2011 2038
2039 /* Has to run after the environment is set up. */
2040 init_atimer ();
2041
2012#ifdef WINDOWSNT 2042#ifdef WINDOWSNT
2013 globals_of_w32 (); 2043 globals_of_w32 ();
2014#ifdef HAVE_W32NOTIFY 2044#ifdef HAVE_W32NOTIFY
@@ -2320,6 +2350,11 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2320 if (dump_mode) 2350 if (dump_mode)
2321 Vdump_mode = build_string (dump_mode); 2351 Vdump_mode = build_string (dump_mode);
2322 2352
2353#ifdef HAVE_PDUMPER
2354 /* Allow code to be run (mostly useful after redumping). */
2355 safe_run_hooks (Qafter_pdump_load_hook);
2356#endif
2357
2323 /* Enter editor command loop. This never returns. */ 2358 /* Enter editor command loop. This never returns. */
2324 set_initial_minibuffer_mode (); 2359 set_initial_minibuffer_mode ();
2325 Frecursive_edit (); 2360 Frecursive_edit ();
@@ -2342,6 +2377,9 @@ struct standard_args
2342static const struct standard_args standard_args[] = 2377static const struct standard_args standard_args[] =
2343{ 2378{
2344 { "-version", "--version", 150, 0 }, 2379 { "-version", "--version", 150, 0 },
2380#ifdef HAVE_PDUMPER
2381 { "-fingerprint", "--fingerprint", 140, 0 },
2382#endif
2345 { "-chdir", "--chdir", 130, 1 }, 2383 { "-chdir", "--chdir", 130, 1 },
2346 { "-t", "--terminal", 120, 1 }, 2384 { "-t", "--terminal", 120, 1 },
2347 { "-nw", "--no-window-system", 110, 0 }, 2385 { "-nw", "--no-window-system", 110, 0 },
diff --git a/src/eval.c b/src/eval.c
index 48104bd0f45..94ad0607732 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#include "dispextern.h" 29#include "dispextern.h"
30#include "buffer.h" 30#include "buffer.h"
31#include "pdumper.h" 31#include "pdumper.h"
32#include "atimer.h"
32 33
33/* CACHEABLE is ordinarily nothing, except it is 'volatile' if 34/* CACHEABLE is ordinarily nothing, except it is 'volatile' if
34 necessary to cajole GCC into not warning incorrectly that a 35 necessary to cajole GCC into not warning incorrectly that a
@@ -364,9 +365,6 @@ do_debug_on_call (Lisp_Object code, ptrdiff_t count)
364 call_debugger (list1 (code)); 365 call_debugger (list1 (code));
365} 366}
366 367
367/* NOTE!!! Every function that can call EVAL must protect its args
368 and temporaries from garbage collection while it needs them.
369 The definition of `For' shows what you have to do. */
370 368
371DEFUN ("or", For, Sor, 0, UNEVALLED, 0, 369DEFUN ("or", For, Sor, 0, UNEVALLED, 0,
372 doc: /* Eval args until one of them yields non-nil, then return that value. 370 doc: /* Eval args until one of them yields non-nil, then return that value.
@@ -1081,6 +1079,47 @@ usage: (while TEST BODY...) */)
1081 return Qnil; 1079 return Qnil;
1082} 1080}
1083 1081
1082static void
1083with_delayed_message_display (struct atimer *timer)
1084{
1085 message3 (build_string (timer->client_data));
1086}
1087
1088static void
1089with_delayed_message_cancel (void *timer)
1090{
1091 xfree (((struct atimer *) timer)->client_data);
1092 cancel_atimer (timer);
1093}
1094
1095DEFUN ("funcall-with-delayed-message",
1096 Ffuncall_with_delayed_message, Sfuncall_with_delayed_message,
1097 3, 3, 0,
1098 doc: /* Like `funcall', but display MESSAGE if FUNCTION takes longer than TIMEOUT.
1099TIMEOUT is a number of seconds, and can be an integer or a floating
1100point number.
1101
1102If FUNCTION takes less time to execute than TIMEOUT seconds, MESSAGE
1103is not displayed. */)
1104 (Lisp_Object timeout, Lisp_Object message, Lisp_Object function)
1105{
1106 ptrdiff_t count = SPECPDL_INDEX ();
1107
1108 CHECK_NUMBER (timeout);
1109 CHECK_STRING (message);
1110
1111 /* Set up the atimer. */
1112 struct timespec interval = dtotimespec (XFLOATINT (timeout));
1113 struct atimer *timer = start_atimer (ATIMER_RELATIVE, interval,
1114 with_delayed_message_display,
1115 xstrdup (SSDATA (message)));
1116 record_unwind_protect_ptr (with_delayed_message_cancel, timer);
1117
1118 Lisp_Object result = CALLN (Ffuncall, function);
1119
1120 return unbind_to (count, result);
1121}
1122
1084DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0, 1123DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0,
1085 doc: /* Return result of expanding macros at top level of FORM. 1124 doc: /* Return result of expanding macros at top level of FORM.
1086If FORM is not a macro call, it is returned unchanged. 1125If FORM is not a macro call, it is returned unchanged.
@@ -1174,14 +1213,6 @@ usage: (catch TAG BODY...) */)
1174 FUNC should return a Lisp_Object. 1213 FUNC should return a Lisp_Object.
1175 This is how catches are done from within C code. */ 1214 This is how catches are done from within C code. */
1176 1215
1177/* MINIBUFFER_QUIT_LEVEL is to handle quitting from nested minibuffers by
1178 throwing t to tag `exit'.
1179 0 means there is no (throw 'exit t) in progress, or it wasn't from
1180 a minibuffer which isn't the most nested;
1181 N > 0 means the `throw' was done from the minibuffer at level N which
1182 wasn't the most nested. */
1183EMACS_INT minibuffer_quit_level = 0;
1184
1185Lisp_Object 1216Lisp_Object
1186internal_catch (Lisp_Object tag, 1217internal_catch (Lisp_Object tag,
1187 Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) 1218 Lisp_Object (*func) (Lisp_Object), Lisp_Object arg)
@@ -1189,9 +1220,6 @@ internal_catch (Lisp_Object tag,
1189 /* This structure is made part of the chain `catchlist'. */ 1220 /* This structure is made part of the chain `catchlist'. */
1190 struct handler *c = push_handler (tag, CATCHER); 1221 struct handler *c = push_handler (tag, CATCHER);
1191 1222
1192 if (EQ (tag, Qexit))
1193 minibuffer_quit_level = 0;
1194
1195 /* Call FUNC. */ 1223 /* Call FUNC. */
1196 if (! sys_setjmp (c->jmp)) 1224 if (! sys_setjmp (c->jmp))
1197 { 1225 {
@@ -1205,17 +1233,6 @@ internal_catch (Lisp_Object tag,
1205 Lisp_Object val = handlerlist->val; 1233 Lisp_Object val = handlerlist->val;
1206 clobbered_eassert (handlerlist == c); 1234 clobbered_eassert (handlerlist == c);
1207 handlerlist = handlerlist->next; 1235 handlerlist = handlerlist->next;
1208 if (EQ (tag, Qexit) && EQ (val, Qt) && minibuffer_quit_level > 0)
1209 /* If we've thrown t to tag `exit' from within a minibuffer, we
1210 exit all minibuffers more deeply nested than the current
1211 one. */
1212 {
1213 if (minibuf_level > minibuffer_quit_level
1214 && !NILP (Fminibuffer_innermost_command_loop_p (Qnil)))
1215 Fthrow (Qexit, Qt);
1216 else
1217 minibuffer_quit_level = 0;
1218 }
1219 return val; 1236 return val;
1220 } 1237 }
1221} 1238}
@@ -3270,6 +3287,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3270 emacs_abort (); 3287 emacs_abort ();
3271 3288
3272 i = optional = rest = 0; 3289 i = optional = rest = 0;
3290 bool previous_rest = false;
3273 for (; CONSP (syms_left); syms_left = XCDR (syms_left)) 3291 for (; CONSP (syms_left); syms_left = XCDR (syms_left))
3274 { 3292 {
3275 maybe_quit (); 3293 maybe_quit ();
@@ -3280,13 +3298,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3280 3298
3281 if (EQ (next, Qand_rest)) 3299 if (EQ (next, Qand_rest))
3282 { 3300 {
3283 if (rest) 3301 if (rest || previous_rest)
3284 xsignal1 (Qinvalid_function, fun); 3302 xsignal1 (Qinvalid_function, fun);
3285 rest = 1; 3303 rest = 1;
3304 previous_rest = true;
3286 } 3305 }
3287 else if (EQ (next, Qand_optional)) 3306 else if (EQ (next, Qand_optional))
3288 { 3307 {
3289 if (optional || rest) 3308 if (optional || rest || previous_rest)
3290 xsignal1 (Qinvalid_function, fun); 3309 xsignal1 (Qinvalid_function, fun);
3291 optional = 1; 3310 optional = 1;
3292 } 3311 }
@@ -3312,10 +3331,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
3312 else 3331 else
3313 /* Dynamically bind NEXT. */ 3332 /* Dynamically bind NEXT. */
3314 specbind (next, arg); 3333 specbind (next, arg);
3334 previous_rest = false;
3315 } 3335 }
3316 } 3336 }
3317 3337
3318 if (!NILP (syms_left)) 3338 if (!NILP (syms_left) || previous_rest)
3319 xsignal1 (Qinvalid_function, fun); 3339 xsignal1 (Qinvalid_function, fun);
3320 else if (i < nargs) 3340 else if (i < nargs)
3321 xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs)); 3341 xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs));
@@ -4333,13 +4353,19 @@ syms_of_eval (void)
4333{ 4353{
4334 DEFVAR_INT ("max-specpdl-size", max_specpdl_size, 4354 DEFVAR_INT ("max-specpdl-size", max_specpdl_size,
4335 doc: /* Limit on number of Lisp variable bindings and `unwind-protect's. 4355 doc: /* Limit on number of Lisp variable bindings and `unwind-protect's.
4336If Lisp code tries to increase the total number past this amount, 4356
4337an error is signaled. 4357If Lisp code tries to use more bindings than this amount, an error is
4338You can safely use a value considerably larger than the default value, 4358signaled.
4339if that proves inconveniently small. However, if you increase it too far, 4359
4340Emacs could run out of memory trying to make the stack bigger. 4360You can safely increase this variable substantially if the default
4341Note that this limit may be silently increased by the debugger 4361value proves inconveniently small. However, if you increase it too
4342if `debug-on-error' or `debug-on-quit' is set. */); 4362much, Emacs could run out of memory trying to make the stack bigger.
4363Note that this limit may be silently increased by the debugger if
4364`debug-on-error' or `debug-on-quit' is set.
4365
4366\"spec\" is short for \"special variables\", i.e., dynamically bound
4367variables. \"PDL\" is short for \"push-down list\", which is an old
4368term for \"stack\". */);
4343 4369
4344 DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth, 4370 DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth,
4345 doc: /* Limit on depth in `eval', `apply' and `funcall' before error. 4371 doc: /* Limit on depth in `eval', `apply' and `funcall' before error.
@@ -4527,6 +4553,7 @@ alist of active lexical bindings. */);
4527 defsubr (&Slet); 4553 defsubr (&Slet);
4528 defsubr (&SletX); 4554 defsubr (&SletX);
4529 defsubr (&Swhile); 4555 defsubr (&Swhile);
4556 defsubr (&Sfuncall_with_delayed_message);
4530 defsubr (&Smacroexpand); 4557 defsubr (&Smacroexpand);
4531 defsubr (&Scatch); 4558 defsubr (&Scatch);
4532 defsubr (&Sthrow); 4559 defsubr (&Sthrow);
diff --git a/src/fileio.c b/src/fileio.c
index 13c99bee109..3c13d3fe416 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -945,6 +945,7 @@ the root directory. */)
945 USE_SAFE_ALLOCA; 945 USE_SAFE_ALLOCA;
946 946
947 CHECK_STRING (name); 947 CHECK_STRING (name);
948 CHECK_STRING_NULL_BYTES (name);
948 949
949 /* If the file name has special constructs in it, 950 /* If the file name has special constructs in it,
950 call the corresponding file name handler. */ 951 call the corresponding file name handler. */
@@ -993,7 +994,10 @@ the root directory. */)
993 if (STRINGP (dir)) 994 if (STRINGP (dir))
994 { 995 {
995 if (file_name_absolute_no_tilde_p (dir)) 996 if (file_name_absolute_no_tilde_p (dir))
996 default_directory = dir; 997 {
998 CHECK_STRING_NULL_BYTES (dir);
999 default_directory = dir;
1000 }
997 else 1001 else
998 { 1002 {
999 Lisp_Object absdir 1003 Lisp_Object absdir
@@ -1307,6 +1311,8 @@ the root directory. */)
1307 newdir = SSDATA (hdir); 1311 newdir = SSDATA (hdir);
1308 newdirlim = newdir + SBYTES (hdir); 1312 newdirlim = newdir + SBYTES (hdir);
1309 } 1313 }
1314 else if (!multibyte && STRING_MULTIBYTE (tem))
1315 multibyte = 1;
1310#ifdef DOS_NT 1316#ifdef DOS_NT
1311 collapse_newdir = false; 1317 collapse_newdir = false;
1312#endif 1318#endif
diff --git a/src/fns.c b/src/fns.c
index 932800a3a49..76c76c92ba9 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -322,7 +322,7 @@ Letter-case is significant, but text properties are ignored. */)
322 322
323 USE_SAFE_ALLOCA; 323 USE_SAFE_ALLOCA;
324 ptrdiff_t *column = SAFE_ALLOCA ((len1 + 1) * sizeof (ptrdiff_t)); 324 ptrdiff_t *column = SAFE_ALLOCA ((len1 + 1) * sizeof (ptrdiff_t));
325 for (y = 1; y <= len1; y++) 325 for (y = 0; y <= len1; y++)
326 column[y] = y; 326 column[y] = y;
327 327
328 if (use_byte_compare) 328 if (use_byte_compare)
@@ -672,6 +672,9 @@ DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
672 doc: /* Concatenate all the arguments and make the result a string. 672 doc: /* Concatenate all the arguments and make the result a string.
673The result is a string whose elements are the elements of all the arguments. 673The result is a string whose elements are the elements of all the arguments.
674Each argument may be a string or a list or vector of characters (integers). 674Each argument may be a string or a list or vector of characters (integers).
675
676Values of the `composition' property of the result are not guaranteed
677to be `eq'.
675usage: (concat &rest SEQUENCES) */) 678usage: (concat &rest SEQUENCES) */)
676 (ptrdiff_t nargs, Lisp_Object *args) 679 (ptrdiff_t nargs, Lisp_Object *args)
677{ 680{
@@ -1174,7 +1177,7 @@ string_make_multibyte (Lisp_Object string)
1174 1177
1175 1178
1176/* Convert STRING (if unibyte) to a multibyte string without changing 1179/* Convert STRING (if unibyte) to a multibyte string without changing
1177 the number of characters. Characters 0200 trough 0237 are 1180 the number of characters. Characters 0200 through 0237 are
1178 converted to eight-bit characters. */ 1181 converted to eight-bit characters. */
1179 1182
1180Lisp_Object 1183Lisp_Object
@@ -1755,7 +1758,8 @@ DEFUN ("assoc", Fassoc, Sassoc, 2, 3, 0,
1755 doc: /* Return non-nil if KEY is equal to the car of an element of ALIST. 1758 doc: /* Return non-nil if KEY is equal to the car of an element of ALIST.
1756The value is actually the first element of ALIST whose car equals KEY. 1759The value is actually the first element of ALIST whose car equals KEY.
1757 1760
1758Equality is defined by TESTFN if non-nil or by `equal' if nil. */) 1761Equality is defined by the function TESTFN, defaulting to `equal'.
1762TESTFN is called with 2 arguments: a car of an alist element and KEY. */)
1759 (Lisp_Object key, Lisp_Object alist, Lisp_Object testfn) 1763 (Lisp_Object key, Lisp_Object alist, Lisp_Object testfn)
1760{ 1764{
1761 if (eq_comparable_value (key) && NILP (testfn)) 1765 if (eq_comparable_value (key) && NILP (testfn))
@@ -2851,12 +2855,16 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
2851 return leni; 2855 return leni;
2852} 2856}
2853 2857
2854DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0, 2858DEFUN ("mapconcat", Fmapconcat, Smapconcat, 2, 3, 0,
2855 doc: /* Apply FUNCTION to each element of SEQUENCE, and concat the results as strings. 2859 doc: /* Apply FUNCTION to each element of SEQUENCE, and concat the results as strings.
2856In between each pair of results, stick in SEPARATOR. Thus, " " as 2860In between each pair of results, stick in SEPARATOR. Thus, " " as
2857 SEPARATOR results in spaces between the values returned by FUNCTION. 2861 SEPARATOR results in spaces between the values returned by FUNCTION.
2862
2858SEQUENCE may be a list, a vector, a bool-vector, or a string. 2863SEQUENCE may be a list, a vector, a bool-vector, or a string.
2859SEPARATOR must be a string, a vector, or a list of characters. 2864
2865Optional argument SEPARATOR must be a string, a vector, or a list of
2866characters; nil stands for the empty string.
2867
2860FUNCTION must be a function of one argument, and must return a value 2868FUNCTION must be a function of one argument, and must return a value
2861 that is a sequence of characters: either a string, or a vector or 2869 that is a sequence of characters: either a string, or a vector or
2862 list of numbers that are valid character codepoints. */) 2870 list of numbers that are valid character codepoints. */)
@@ -2949,8 +2957,10 @@ do_yes_or_no_p (Lisp_Object prompt)
2949DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0, 2957DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0,
2950 doc: /* Ask user a yes-or-no question. 2958 doc: /* Ask user a yes-or-no question.
2951Return t if answer is yes, and nil if the answer is no. 2959Return t if answer is yes, and nil if the answer is no.
2952PROMPT is the string to display to ask the question. It should end in 2960
2953a space; `yes-or-no-p' adds \"(yes or no) \" to it. 2961PROMPT is the string to display to ask the question; `yes-or-no-p'
2962adds \"(yes or no) \" to it. It does not need to end in space, but if
2963it does up to one space will be removed.
2954 2964
2955The user must confirm the answer with RET, and can edit it until it 2965The user must confirm the answer with RET, and can edit it until it
2956has been confirmed. 2966has been confirmed.
diff --git a/src/font.c b/src/font.c
index cdf35b03702..205e9d214c0 100644
--- a/src/font.c
+++ b/src/font.c
@@ -57,24 +57,26 @@ struct table_entry
57 int numeric; 57 int numeric;
58 /* The first one is a valid name as a face attribute. 58 /* The first one is a valid name as a face attribute.
59 The second one (if any) is a typical name in XLFD field. */ 59 The second one (if any) is a typical name in XLFD field. */
60 const char *names[5]; 60 const char *names[6];
61}; 61};
62 62
63/* Table of weight numeric values and their names. This table must be 63/* Table of weight numeric values and their names. This table must be
64 sorted by numeric values in ascending order. */ 64 sorted by numeric values in ascending order and the numeric values
65 must approximately match the weights in the font files. */
65 66
66static const struct table_entry weight_table[] = 67static const struct table_entry weight_table[] =
67{ 68{
68 { 0, { "thin" }}, 69 { 0, { "thin" }},
69 { 20, { "ultra-light", "ultralight" }}, 70 { 40, { "ultra-light", "ultralight", "extra-light", "extralight" }},
70 { 40, { "extra-light", "extralight" }},
71 { 50, { "light" }}, 71 { 50, { "light" }},
72 { 75, { "semi-light", "semilight", "demilight", "book" }}, 72 { 55, { "semi-light", "semilight", "demilight" }},
73 { 100, { "normal", "medium", "regular", "unspecified" }}, 73 { 80, { "regular", "normal", "unspecified", "book" }},
74 { 180, { "semi-bold", "semibold", "demibold", "demi" }}, 74 { 100, { "medium" }},
75 { 180, { "semi-bold", "semibold", "demibold", "demi-bold", "demi" }},
75 { 200, { "bold" }}, 76 { 200, { "bold" }},
76 { 205, { "extra-bold", "extrabold" }}, 77 { 205, { "extra-bold", "extrabold", "ultra-bold", "ultrabold" }},
77 { 210, { "ultra-bold", "ultrabold", "black" }} 78 { 210, { "black", "heavy" }},
79 { 250, { "ultra-heavy", "ultraheavy" }}
78}; 80};
79 81
80/* Table of slant numeric values and their names. This table must be 82/* Table of slant numeric values and their names. This table must be
@@ -1029,8 +1031,8 @@ font_expand_wildcards (Lisp_Object *field, int n)
1029 X font backend driver, it is a font-entity. In that case, NAME is 1031 X font backend driver, it is a font-entity. In that case, NAME is
1030 a fully specified XLFD. */ 1032 a fully specified XLFD. */
1031 1033
1032int 1034static int
1033font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font) 1035font_parse_xlfd_1 (char *name, ptrdiff_t len, Lisp_Object font, int segments)
1034{ 1036{
1035 int i, j, n; 1037 int i, j, n;
1036 char *f[XLFD_LAST_INDEX + 1]; 1038 char *f[XLFD_LAST_INDEX + 1];
@@ -1040,17 +1042,27 @@ font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
1040 if (len > 255 || !len) 1042 if (len > 255 || !len)
1041 /* Maximum XLFD name length is 255. */ 1043 /* Maximum XLFD name length is 255. */
1042 return -1; 1044 return -1;
1045
1043 /* Accept "*-.." as a fully specified XLFD. */ 1046 /* Accept "*-.." as a fully specified XLFD. */
1044 if (name[0] == '*' && (len == 1 || name[1] == '-')) 1047 if (name[0] == '*' && (len == 1 || name[1] == '-'))
1045 i = 1, f[XLFD_FOUNDRY_INDEX] = name; 1048 i = 1, f[XLFD_FOUNDRY_INDEX] = name;
1046 else 1049 else
1047 i = 0; 1050 i = 0;
1051
1052 /* Split into segments. */
1048 for (p = name + i; *p; p++) 1053 for (p = name + i; *p; p++)
1049 if (*p == '-') 1054 if (*p == '-')
1050 { 1055 {
1051 f[i++] = p + 1; 1056 /* If we have too many segments, then gather them up into the
1052 if (i == XLFD_LAST_INDEX) 1057 FAMILY part of the name. This allows using fonts with
1053 break; 1058 dashes in the FAMILY bit. */
1059 if (segments > XLFD_LAST_INDEX && i == XLFD_WEIGHT_INDEX)
1060 segments--;
1061 else {
1062 f[i++] = p + 1;
1063 if (i == XLFD_LAST_INDEX)
1064 break;
1065 }
1054 } 1066 }
1055 f[i] = name + len; 1067 f[i] = name + len;
1056 1068
@@ -1215,6 +1227,28 @@ font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
1215 return 0; 1227 return 0;
1216} 1228}
1217 1229
1230int
1231font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
1232{
1233 int found = font_parse_xlfd_1 (name, len, font, -1);
1234 if (found > -1)
1235 return found;
1236
1237 int segments = 0;
1238 /* Count how many segments we have. */
1239 for (char *p = name; *p; p++)
1240 if (*p == '-')
1241 segments++;
1242
1243 /* If we have a surplus of segments, then we try to parse again, in
1244 case there's a font with dashes in the family name. */
1245 if (segments > XLFD_LAST_INDEX)
1246 return font_parse_xlfd_1 (name, len, font, segments);
1247 else
1248 return -1;
1249}
1250
1251
1218/* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES 1252/* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES
1219 length), and return the name length. If FONT_SIZE_INDEX of FONT is 1253 length), and return the name length. If FONT_SIZE_INDEX of FONT is
1220 0, use PIXEL_SIZE instead. */ 1254 0, use PIXEL_SIZE instead. */
@@ -1452,11 +1486,20 @@ font_parse_fcname (char *name, ptrdiff_t len, Lisp_Object font)
1452#define PROP_MATCH(STR) (word_len == strlen (STR) \ 1486#define PROP_MATCH(STR) (word_len == strlen (STR) \
1453 && memcmp (p, STR, strlen (STR)) == 0) 1487 && memcmp (p, STR, strlen (STR)) == 0)
1454 1488
1455 if (PROP_MATCH ("light") 1489 if (PROP_MATCH ("thin")
1490 || PROP_MATCH ("ultra-light")
1491 || PROP_MATCH ("light")
1492 || PROP_MATCH ("semi-light")
1493 || PROP_MATCH ("book")
1456 || PROP_MATCH ("medium") 1494 || PROP_MATCH ("medium")
1495 || PROP_MATCH ("normal")
1496 || PROP_MATCH ("semibold")
1457 || PROP_MATCH ("demibold") 1497 || PROP_MATCH ("demibold")
1458 || PROP_MATCH ("bold") 1498 || PROP_MATCH ("bold")
1459 || PROP_MATCH ("black")) 1499 || PROP_MATCH ("ultra-bold")
1500 || PROP_MATCH ("black")
1501 || PROP_MATCH ("heavy")
1502 || PROP_MATCH ("ultra-heavy"))
1460 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val); 1503 FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
1461 else if (PROP_MATCH ("roman") 1504 else if (PROP_MATCH ("roman")
1462 || PROP_MATCH ("italic") 1505 || PROP_MATCH ("italic")
@@ -3828,12 +3871,32 @@ font_at (int c, ptrdiff_t pos, struct face *face, struct window *w,
3828 3871
3829#ifdef HAVE_WINDOW_SYSTEM 3872#ifdef HAVE_WINDOW_SYSTEM
3830 3873
3874/* Check if CH is a codepoint for which we should attempt to use the
3875 emoji font, even if the codepoint itself has Emoji_Presentation =
3876 No. Vauto_composition_emoji_eligible_codepoints is filled in for
3877 us by admin/unidata/emoji-zwj.awk. */
3878static bool
3879codepoint_is_emoji_eligible (int ch)
3880{
3881 if (EQ (CHAR_TABLE_REF (Vchar_script_table, ch), Qemoji))
3882 return true;
3883
3884 if (! NILP (Fmemq (make_fixnum (ch),
3885 Vauto_composition_emoji_eligible_codepoints)))
3886 return true;
3887
3888 return false;
3889}
3890
3831/* Check how many characters after character/byte position POS/POS_BYTE 3891/* Check how many characters after character/byte position POS/POS_BYTE
3832 (at most to *LIMIT) can be displayed by the same font in the window W. 3892 (at most to *LIMIT) can be displayed by the same font in the window W.
3833 FACE, if non-NULL, is the face selected for the character at POS. 3893 FACE, if non-NULL, is the face selected for the character at POS.
3834 If STRING is not nil, it is the string to check instead of the current 3894 If STRING is not nil, it is the string to check instead of the current
3835 buffer. In that case, FACE must be not NULL. 3895 buffer. In that case, FACE must be not NULL.
3836 3896
3897 CH is the character that actually caused the composition
3898 process to start, it may be different from the character at POS.
3899
3837 The return value is the font-object for the character at POS. 3900 The return value is the font-object for the character at POS.
3838 *LIMIT is set to the position where that font can't be used. 3901 *LIMIT is set to the position where that font can't be used.
3839 3902
@@ -3841,15 +3904,16 @@ font_at (int c, ptrdiff_t pos, struct face *face, struct window *w,
3841 3904
3842Lisp_Object 3905Lisp_Object
3843font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, 3906font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit,
3844 struct window *w, struct face *face, Lisp_Object string) 3907 struct window *w, struct face *face, Lisp_Object string,
3908 int ch)
3845{ 3909{
3846 ptrdiff_t ignore; 3910 ptrdiff_t ignore;
3847 int c; 3911 int c;
3848 Lisp_Object font_object = Qnil; 3912 Lisp_Object font_object = Qnil;
3913 struct frame *f = XFRAME (w->frame);
3849 3914
3850 if (!face) 3915 if (!face)
3851 { 3916 {
3852 struct frame *f = XFRAME (w->frame);
3853 int face_id; 3917 int face_id;
3854 3918
3855 if (NILP (string)) 3919 if (NILP (string))
@@ -3868,6 +3932,23 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit,
3868 face = FACE_FROM_ID (f, face_id); 3932 face = FACE_FROM_ID (f, face_id);
3869 } 3933 }
3870 3934
3935 /* If the composition was triggered by an emoji, use a character
3936 from 'script-representative-chars', rather than the first
3937 character in the string, to determine the font to use. */
3938 if (codepoint_is_emoji_eligible (ch))
3939 {
3940 Lisp_Object val = assq_no_quit (Qemoji, Vscript_representative_chars);
3941 if (CONSP (val))
3942 {
3943 val = XCDR (val);
3944 if (CONSP (val))
3945 val = XCAR (val);
3946 else if (VECTORP (val))
3947 val = AREF (val, 0);
3948 font_object = font_for_char (face, XFIXNAT (val), pos, string);
3949 }
3950 }
3951
3871 while (pos < *limit) 3952 while (pos < *limit)
3872 { 3953 {
3873 c = (NILP (string) 3954 c = (NILP (string)
@@ -4896,6 +4977,33 @@ If the font is not OpenType font, CAPABILITY is nil. */)
4896 : Qnil)); 4977 : Qnil));
4897} 4978}
4898 4979
4980DEFUN ("font-has-char-p", Ffont_has_char_p, Sfont_has_char_p, 2, 3, 0,
4981 doc:
4982 /* Return non-nil if FONT on FRAME has a glyph for character CH.
4983FONT can be either a font-entity or a font-object. If it is
4984a font-entity and the result is nil, it means the font needs to be
4985opened (with `open-font') to check.
4986FRAME defaults to the selected frame if it is nil or omitted. */)
4987 (Lisp_Object font, Lisp_Object ch, Lisp_Object frame)
4988{
4989 struct frame *f;
4990 CHECK_FONT (font);
4991 CHECK_CHARACTER (ch);
4992
4993 if (NILP (frame))
4994 f = XFRAME (selected_frame);
4995 else
4996 {
4997 CHECK_FRAME (frame);
4998 f = XFRAME (frame);
4999 }
5000
5001 if (font_has_char (f, font, XFIXNAT (ch)) <= 0)
5002 return Qnil;
5003 else
5004 return Qt;
5005}
5006
4899DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0, 5007DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
4900 doc: 5008 doc:
4901 /* Return a vector of FONT-OBJECT's glyphs for the specified characters. 5009 /* Return a vector of FONT-OBJECT's glyphs for the specified characters.
@@ -4914,8 +5022,13 @@ where
4914 CODE is the glyph-code of C in FONT-OBJECT. 5022 CODE is the glyph-code of C in FONT-OBJECT.
4915 WIDTH thru DESCENT are the metrics (in pixels) of the glyph. 5023 WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
4916 ADJUSTMENT is always nil. 5024 ADJUSTMENT is always nil.
4917If FONT-OBJECT doesn't have a glyph for a character, 5025
4918the corresponding element is nil. */) 5026If FONT-OBJECT doesn't have a glyph for a character, the corresponding
5027element is nil.
5028
5029Also see `font-has-char-p', which is more efficient than this function
5030if you just want to check whether FONT-OBJECT has a glyph for a
5031character. */)
4919 (Lisp_Object font_object, Lisp_Object from, Lisp_Object to, 5032 (Lisp_Object font_object, Lisp_Object from, Lisp_Object to,
4920 Lisp_Object object) 5033 Lisp_Object object)
4921{ 5034{
@@ -5391,6 +5504,7 @@ syms_of_font (void)
5391 DEFSYM (Qiso8859_1, "iso8859-1"); 5504 DEFSYM (Qiso8859_1, "iso8859-1");
5392 DEFSYM (Qiso10646_1, "iso10646-1"); 5505 DEFSYM (Qiso10646_1, "iso10646-1");
5393 DEFSYM (Qunicode_bmp, "unicode-bmp"); 5506 DEFSYM (Qunicode_bmp, "unicode-bmp");
5507 DEFSYM (Qemoji, "emoji");
5394 5508
5395 /* Symbols representing keys of font extra info. */ 5509 /* Symbols representing keys of font extra info. */
5396 DEFSYM (QCotf, ":otf"); 5510 DEFSYM (QCotf, ":otf");
@@ -5466,6 +5580,7 @@ syms_of_font (void)
5466 defsubr (&Sclose_font); 5580 defsubr (&Sclose_font);
5467 defsubr (&Squery_font); 5581 defsubr (&Squery_font);
5468 defsubr (&Sfont_get_glyphs); 5582 defsubr (&Sfont_get_glyphs);
5583 defsubr (&Sfont_has_char_p);
5469 defsubr (&Sfont_match_p); 5584 defsubr (&Sfont_match_p);
5470 defsubr (&Sfont_at); 5585 defsubr (&Sfont_at);
5471#if 0 5586#if 0
diff --git a/src/font.h b/src/font.h
index 750754433c8..6ee7bcafffa 100644
--- a/src/font.h
+++ b/src/font.h
@@ -885,7 +885,7 @@ valid_font_driver (struct font_driver const *d)
885extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list); 885extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list);
886extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *, 886extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *,
887 struct window *, struct face *, 887 struct window *, struct face *,
888 Lisp_Object); 888 Lisp_Object, int);
889extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned int); 889extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned int);
890 890
891extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop, 891extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop,
diff --git a/src/fontset.c b/src/fontset.c
index 332be6c39d1..7d4bd65f70c 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -1361,7 +1361,11 @@ check_fontset_name (Lisp_Object name, Lisp_Object *frame)
1361 if (EQ (name, Qt)) 1361 if (EQ (name, Qt))
1362 return Vdefault_fontset; 1362 return Vdefault_fontset;
1363 if (NILP (name)) 1363 if (NILP (name))
1364 id = FRAME_FONTSET (f); 1364 {
1365 if (!FRAME_WINDOW_P (f))
1366 error ("Can't use fontsets in non-GUI frames");
1367 id = FRAME_FONTSET (f);
1368 }
1365 else 1369 else
1366 { 1370 {
1367 CHECK_STRING (name); 1371 CHECK_STRING (name);
diff --git a/src/frame.c b/src/frame.c
index 94e0073e22a..bb5d46f4eeb 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -732,7 +732,7 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
732 && (f->new_width >= 0 || f->new_height >= 0)) 732 && (f->new_width >= 0 || f->new_height >= 0))
733 /* For implied resizes with inhibit 2 (external menu and tool 733 /* For implied resizes with inhibit 2 (external menu and tool
734 bar) pick up any new sizes the display engine has not 734 bar) pick up any new sizes the display engine has not
735 processed yet. Otherwsie, we would request the old sizes 735 processed yet. Otherwise, we would request the old sizes
736 which will make this request appear as a request to set new 736 which will make this request appear as a request to set new
737 sizes and have the WM react accordingly which is not TRT. 737 sizes and have the WM react accordingly which is not TRT.
738 738
@@ -1409,11 +1409,6 @@ affects all frames on the same terminal device. */)
1409 (t->display_info.tty->name 1409 (t->display_info.tty->name
1410 ? build_string (t->display_info.tty->name) 1410 ? build_string (t->display_info.tty->name)
1411 : Qnil)); 1411 : Qnil));
1412 /* On terminal frames the `minibuffer' frame parameter is always
1413 virtually t. Avoid that a different value in parms causes
1414 complaints, see Bug#24758. */
1415 store_in_alist (&parms, Qminibuffer, Qt);
1416 Fmodify_frame_parameters (frame, parms);
1417 1412
1418 /* Make the frame face hash be frame-specific, so that each 1413 /* Make the frame face hash be frame-specific, so that each
1419 frame could change its face definitions independently. */ 1414 frame could change its face definitions independently. */
@@ -1426,6 +1421,12 @@ affects all frames on the same terminal device. */)
1426 for (idx = 0; idx < table->count; ++idx) 1421 for (idx = 0; idx < table->count; ++idx)
1427 set_hash_value_slot (table, idx, Fcopy_sequence (HASH_VALUE (table, idx))); 1422 set_hash_value_slot (table, idx, Fcopy_sequence (HASH_VALUE (table, idx)));
1428 1423
1424 /* On terminal frames the `minibuffer' frame parameter is always
1425 virtually t. Avoid that a different value in parms causes
1426 complaints, see Bug#24758. */
1427 store_in_alist (&parms, Qminibuffer, Qt);
1428 Fmodify_frame_parameters (frame, parms);
1429
1429 f->can_set_window_size = true; 1430 f->can_set_window_size = true;
1430 f->after_make_frame = true; 1431 f->after_make_frame = true;
1431 1432
@@ -1840,15 +1841,20 @@ prev_frame (Lisp_Object frame, Lisp_Object minibuf)
1840 1841
1841DEFUN ("next-frame", Fnext_frame, Snext_frame, 0, 2, 0, 1842DEFUN ("next-frame", Fnext_frame, Snext_frame, 0, 2, 0,
1842 doc: /* Return the next frame in the frame list after FRAME. 1843 doc: /* Return the next frame in the frame list after FRAME.
1843It considers only frames on the same terminal as FRAME. 1844Only frames on the same terminal as FRAME are included in the list
1844By default, skip minibuffer-only frames. 1845of candidate frames. If omitted, FRAME defaults to the selected frame.
1845If omitted, FRAME defaults to the selected frame. 1846
1846If optional argument MINIFRAME is nil, exclude minibuffer-only frames. 1847If MINIFRAME is nil (the default), include all frames except
1847If MINIFRAME is a window, include only its own frame 1848minibuffer-only frames.
1848and any frame now using that window as the minibuffer. 1849
1849If MINIFRAME is `visible', include all visible frames. 1850If MINIFRAME is a window, include only its own frame and any frame now
1850If MINIFRAME is 0, include all visible and iconified frames. 1851using that window as the minibuffer.
1851Otherwise, include all frames. */) 1852
1853If MINIFRAME is `visible', include only visible frames.
1854
1855If MINIFRAME is 0, include only visible and iconified frames.
1856
1857If MINIFRAME is any other value, include all frames. */)
1852 (Lisp_Object frame, Lisp_Object miniframe) 1858 (Lisp_Object frame, Lisp_Object miniframe)
1853{ 1859{
1854 if (NILP (frame)) 1860 if (NILP (frame))
@@ -5033,8 +5039,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o
5033} 5039}
5034 5040
5035 5041
5036#ifndef HAVE_NS
5037
5038/* Non-zero if mouse is grabbed on DPYINFO 5042/* Non-zero if mouse is grabbed on DPYINFO
5039 and we know the frame where it is. */ 5043 and we know the frame where it is. */
5040 5044
@@ -5059,8 +5063,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo)
5059 dpyinfo->last_mouse_motion_y); 5063 dpyinfo->last_mouse_motion_y);
5060} 5064}
5061 5065
5062#endif /* HAVE_NS */
5063
5064/* Subroutines of creating an X frame. */ 5066/* Subroutines of creating an X frame. */
5065 5067
5066/* Make sure that Vx_resource_name is set to a reasonable value. 5068/* Make sure that Vx_resource_name is set to a reasonable value.
@@ -6251,7 +6253,10 @@ when the mouse is over clickable text. */);
6251 6253
6252 DEFVAR_LISP ("make-pointer-invisible", Vmake_pointer_invisible, 6254 DEFVAR_LISP ("make-pointer-invisible", Vmake_pointer_invisible,
6253 doc: /* If non-nil, make mouse pointer invisible while typing. 6255 doc: /* If non-nil, make mouse pointer invisible while typing.
6254The pointer becomes visible again when the mouse is moved. */); 6256The pointer becomes visible again when the mouse is moved.
6257
6258When using this, you might also want to disable highlighting of
6259clickable text. See `mouse-highlight'. */);
6255 Vmake_pointer_invisible = Qt; 6260 Vmake_pointer_invisible = Qt;
6256 6261
6257 DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions, 6262 DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions,
diff --git a/src/frame.h b/src/frame.h
index 9856890c315..39607766049 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -449,8 +449,8 @@ struct frame
449 /* Non-zero if this frame's faces need to be recomputed. */ 449 /* Non-zero if this frame's faces need to be recomputed. */
450 bool_bf face_change : 1; 450 bool_bf face_change : 1;
451 451
452 /* Non-zero if this frame's image cache cannot be freed because the 452 /* Non-zero if this frame's image cache and face cache cannot be
453 frame is in the process of being redisplayed. */ 453 freed because the frame is in the process of being redisplayed. */
454 bool_bf inhibit_clear_image_cache : 1; 454 bool_bf inhibit_clear_image_cache : 1;
455 455
456 /* True when new_width or new_height were set by change_frame_size, 456 /* True when new_width or new_height were set by change_frame_size,
diff --git a/src/fringe.c b/src/fringe.c
index e67ea9d88fd..f22d0956982 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -971,6 +971,14 @@ update_window_fringes (struct window *w, bool keep_current_p)
971 if (w->pseudo_window_p) 971 if (w->pseudo_window_p)
972 return 0; 972 return 0;
973 973
974 ptrdiff_t count = SPECPDL_INDEX ();
975
976 /* This function could be called for redisplaying non-selected
977 windows, in which case point has been temporarily moved to that
978 window's window-point. So we cannot afford quitting out of here,
979 as point is restored after this function returns. */
980 specbind (Qinhibit_quit, Qt);
981
974 if (!MINI_WINDOW_P (w) 982 if (!MINI_WINDOW_P (w)
975 && (ind = BVAR (XBUFFER (w->contents), indicate_buffer_boundaries), !NILP (ind))) 983 && (ind = BVAR (XBUFFER (w->contents), indicate_buffer_boundaries), !NILP (ind)))
976 { 984 {
@@ -1333,6 +1341,8 @@ update_window_fringes (struct window *w, bool keep_current_p)
1333 row->fringe_bitmap_periodic_p = periodic_p; 1341 row->fringe_bitmap_periodic_p = periodic_p;
1334 } 1342 }
1335 1343
1344 unbind_to (count, Qnil);
1345
1336 return redraw_p && !keep_current_p; 1346 return redraw_p && !keep_current_p;
1337} 1347}
1338 1348
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 40d1d17a60a..7f8a33c01d7 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -2617,20 +2617,34 @@ xg_get_file_name (struct frame *f,
2617 2617
2618#ifdef HAVE_GTK3 2618#ifdef HAVE_GTK3
2619 2619
2620#define XG_WEIGHT_TO_SYMBOL(w) \ 2620static
2621 (w <= PANGO_WEIGHT_THIN ? Qextra_light \ 2621Lisp_Object xg_weight_to_symbol (PangoWeight w)
2622 : w <= PANGO_WEIGHT_ULTRALIGHT ? Qlight \ 2622{
2623 : w <= PANGO_WEIGHT_LIGHT ? Qsemi_light \ 2623 return
2624 : w < PANGO_WEIGHT_MEDIUM ? Qnormal \ 2624 (w <= PANGO_WEIGHT_THIN ? Qthin /* 100 */
2625 : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold \ 2625 : w <= PANGO_WEIGHT_ULTRALIGHT ? Qultra_light /* 200 */
2626 : w <= PANGO_WEIGHT_BOLD ? Qbold \ 2626 : w <= PANGO_WEIGHT_LIGHT ? Qlight /* 300 */
2627 : w <= PANGO_WEIGHT_HEAVY ? Qextra_bold \ 2627#if PANGO_VERSION_CHECK(1, 36, 7)
2628 : Qultra_bold) 2628 : w <= PANGO_WEIGHT_SEMILIGHT ? Qsemi_light /* 350 */
2629 2629#endif
2630#define XG_STYLE_TO_SYMBOL(s) \ 2630 : w <= PANGO_WEIGHT_BOOK ? Qbook /* 380 */
2631 (s == PANGO_STYLE_OBLIQUE ? Qoblique \ 2631 : w <= PANGO_WEIGHT_NORMAL ? Qnormal /* 400 */
2632 : s == PANGO_STYLE_ITALIC ? Qitalic \ 2632 : w <= PANGO_WEIGHT_MEDIUM ? Qmedium /* 500 */
2633 : Qnormal) 2633 : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold /* 600 */
2634 : w <= PANGO_WEIGHT_BOLD ? Qbold /* 700 */
2635 : w <= PANGO_WEIGHT_ULTRABOLD ? Qultra_bold /* 800 */
2636 : w <= PANGO_WEIGHT_HEAVY ? Qblack /* 900 */
2637 : Qultra_heavy); /* 1000 */
2638}
2639
2640static
2641Lisp_Object xg_style_to_symbol (PangoStyle s)
2642{
2643 return
2644 (s == PANGO_STYLE_OBLIQUE ? Qoblique
2645 : s == PANGO_STYLE_ITALIC ? Qitalic
2646 : Qnormal);
2647}
2634 2648
2635#endif /* HAVE_GTK3 */ 2649#endif /* HAVE_GTK3 */
2636 2650
@@ -2726,8 +2740,8 @@ xg_get_font (struct frame *f, const char *default_name)
2726 font = CALLN (Ffont_spec, 2740 font = CALLN (Ffont_spec,
2727 QCfamily, build_string (family), 2741 QCfamily, build_string (family),
2728 QCsize, make_float (pango_units_to_double (size)), 2742 QCsize, make_float (pango_units_to_double (size)),
2729 QCweight, XG_WEIGHT_TO_SYMBOL (weight), 2743 QCweight, xg_weight_to_symbol (weight),
2730 QCslant, XG_STYLE_TO_SYMBOL (style)); 2744 QCslant, xg_style_to_symbol (style));
2731 2745
2732 char *font_desc_str = pango_font_description_to_string (desc); 2746 char *font_desc_str = pango_font_description_to_string (desc);
2733 dupstring (&x_last_font_name, font_desc_str); 2747 dupstring (&x_last_font_name, font_desc_str);
@@ -3328,8 +3342,9 @@ xg_item_label_same_p (GtkMenuItem *witem, const char *label)
3328 char *utf8_label = get_utf8_string (label); 3342 char *utf8_label = get_utf8_string (label);
3329 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0; 3343 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
3330 3344
3331 bool is_same = (!old_label == !utf8_label 3345 bool is_same = (old_label
3332 && (!old_label || strcmp (utf8_label, old_label) == 0)); 3346 ? utf8_label && strcmp (utf8_label, old_label) == 0
3347 : !utf8_label);
3333 3348
3334 if (utf8_label) g_free (utf8_label); 3349 if (utf8_label) g_free (utf8_label);
3335 3350
diff --git a/src/image.c b/src/image.c
index 7a6f406e76f..f911da51eaa 100644
--- a/src/image.c
+++ b/src/image.c
@@ -3670,10 +3670,8 @@ convert_mono_to_color_image (struct frame *f, struct image *img,
3670 release_frame_dc (f, hdc); 3670 release_frame_dc (f, hdc);
3671 old_prev = SelectObject (old_img_dc, img->pixmap); 3671 old_prev = SelectObject (old_img_dc, img->pixmap);
3672 new_prev = SelectObject (new_img_dc, new_pixmap); 3672 new_prev = SelectObject (new_img_dc, new_pixmap);
3673 /* Windows convention for mono bitmaps is black = background, 3673 SetTextColor (new_img_dc, foreground);
3674 white = foreground. */ 3674 SetBkColor (new_img_dc, background);
3675 SetTextColor (new_img_dc, background);
3676 SetBkColor (new_img_dc, foreground);
3677 3675
3678 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc, 3676 BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
3679 0, 0, SRCCOPY); 3677 0, 0, SRCCOPY);
@@ -4246,9 +4244,9 @@ struct xpm_cached_color
4246}; 4244};
4247 4245
4248/* The hash table used for the color cache, and its bucket vector 4246/* The hash table used for the color cache, and its bucket vector
4249 size. */ 4247 size (which should be prime). */
4250 4248
4251#define XPM_COLOR_CACHE_BUCKETS 1001 4249#define XPM_COLOR_CACHE_BUCKETS 1009
4252static struct xpm_cached_color **xpm_color_cache; 4250static struct xpm_cached_color **xpm_color_cache;
4253 4251
4254/* Initialize the color cache. */ 4252/* Initialize the color cache. */
@@ -6551,9 +6549,8 @@ image_can_use_native_api (Lisp_Object type)
6551} 6549}
6552 6550
6553/* 6551/*
6554 * These functions are actually defined in the OS-native implementation 6552 * These functions are actually defined in the OS-native implementation file.
6555 * file. Currently, for Windows GDI+ interface, w32image.c, but other 6553 * Currently, for Windows GDI+ interface, w32image.c, and nsimage.m for macOS.
6556 * operating systems can follow suit.
6557 */ 6554 */
6558 6555
6559/* Indices of image specification fields in native format, below. */ 6556/* Indices of image specification fields in native format, below. */
@@ -8363,24 +8360,30 @@ gif_image_p (Lisp_Object object)
8363# undef DrawText 8360# undef DrawText
8364# endif 8361# endif
8365 8362
8366/* Giflib before 5.0 didn't define these macros (used only if HAVE_NTGUI). */
8367# ifndef GIFLIB_MINOR
8368# define GIFLIB_MINOR 0
8369# endif
8370# ifndef GIFLIB_RELEASE
8371# define GIFLIB_RELEASE 0
8372# endif
8373
8374# else /* HAVE_NTGUI */ 8363# else /* HAVE_NTGUI */
8375 8364
8376# include <gif_lib.h> 8365# include <gif_lib.h>
8377 8366
8378# endif /* HAVE_NTGUI */ 8367# endif /* HAVE_NTGUI */
8379 8368
8380/* Giflib before 5.0 didn't define these macros. */ 8369/* Giflib before 4.1.6 didn't define these macros. */
8381# ifndef GIFLIB_MAJOR 8370# ifndef GIFLIB_MAJOR
8382# define GIFLIB_MAJOR 4 8371# define GIFLIB_MAJOR 4
8383# endif 8372# endif
8373# ifndef GIFLIB_MINOR
8374# define GIFLIB_MINOR 0
8375# endif
8376# ifndef GIFLIB_RELEASE
8377# define GIFLIB_RELEASE 0
8378# endif
8379/* Giflib before 5.0 didn't define these macros. */
8380# if GIFLIB_MAJOR < 5
8381# define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
8382# define DISPOSE_DO_NOT 1 /* Leave image in place. */
8383# define DISPOSE_BACKGROUND 2 /* Set area too background color. */
8384# define DISPOSE_PREVIOUS 3 /* Restore to previous content. */
8385# define NO_TRANSPARENT_COLOR -1
8386# endif
8384 8387
8385/* GifErrorString is declared to return char const * when GIFLIB_MAJOR 8388/* GifErrorString is declared to return char const * when GIFLIB_MAJOR
8386 and GIFLIB_MINOR indicate 5.1 or later. Do not bother using it in 8389 and GIFLIB_MINOR indicate 5.1 or later. Do not bother using it in
@@ -8403,6 +8406,8 @@ DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *));
8403# else 8406# else
8404DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *)); 8407DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *));
8405DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *)); 8408DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *));
8409DEF_DLL_FN (int, DGifSavedExtensionToGCB,
8410 (GifFileType *, int, GraphicsControlBlock *));
8406# endif 8411# endif
8407# if HAVE_GIFERRORSTRING 8412# if HAVE_GIFERRORSTRING
8408DEF_DLL_FN (char const *, GifErrorString, (int)); 8413DEF_DLL_FN (char const *, GifErrorString, (int));
@@ -8420,6 +8425,9 @@ init_gif_functions (void)
8420 LOAD_DLL_FN (library, DGifSlurp); 8425 LOAD_DLL_FN (library, DGifSlurp);
8421 LOAD_DLL_FN (library, DGifOpen); 8426 LOAD_DLL_FN (library, DGifOpen);
8422 LOAD_DLL_FN (library, DGifOpenFileName); 8427 LOAD_DLL_FN (library, DGifOpenFileName);
8428# if GIFLIB_MAJOR >= 5
8429 LOAD_DLL_FN (library, DGifSavedExtensionToGCB);
8430# endif
8423# if HAVE_GIFERRORSTRING 8431# if HAVE_GIFERRORSTRING
8424 LOAD_DLL_FN (library, GifErrorString); 8432 LOAD_DLL_FN (library, GifErrorString);
8425# endif 8433# endif
@@ -8430,12 +8438,18 @@ init_gif_functions (void)
8430# undef DGifOpen 8438# undef DGifOpen
8431# undef DGifOpenFileName 8439# undef DGifOpenFileName
8432# undef DGifSlurp 8440# undef DGifSlurp
8441# if GIFLIB_MAJOR >= 5
8442# undef DGifSavedExtensionToGCB
8443# endif
8433# undef GifErrorString 8444# undef GifErrorString
8434 8445
8435# define DGifCloseFile fn_DGifCloseFile 8446# define DGifCloseFile fn_DGifCloseFile
8436# define DGifOpen fn_DGifOpen 8447# define DGifOpen fn_DGifOpen
8437# define DGifOpenFileName fn_DGifOpenFileName 8448# define DGifOpenFileName fn_DGifOpenFileName
8438# define DGifSlurp fn_DGifSlurp 8449# define DGifSlurp fn_DGifSlurp
8450# if GIFLIB_MAJOR >= 5
8451# define DGifSavedExtensionToGCB fn_DGifSavedExtensionToGCB
8452# endif
8439# define GifErrorString fn_GifErrorString 8453# define GifErrorString fn_GifErrorString
8440 8454
8441# endif /* WINDOWSNT */ 8455# endif /* WINDOWSNT */
@@ -8513,7 +8527,7 @@ gif_load (struct frame *f, struct image *img)
8513 if (!STRINGP (file)) 8527 if (!STRINGP (file))
8514 { 8528 {
8515 image_error ("Cannot find image file `%s'", specified_file); 8529 image_error ("Cannot find image file `%s'", specified_file);
8516 return 0; 8530 return false;
8517 } 8531 }
8518 8532
8519 Lisp_Object encoded_file = ENCODE_FILE (file); 8533 Lisp_Object encoded_file = ENCODE_FILE (file);
@@ -8536,8 +8550,7 @@ gif_load (struct frame *f, struct image *img)
8536 else 8550 else
8537#endif 8551#endif
8538 image_error ("Cannot open `%s'", file); 8552 image_error ("Cannot open `%s'", file);
8539 8553 return false;
8540 return 0;
8541 } 8554 }
8542 } 8555 }
8543 else 8556 else
@@ -8545,7 +8558,7 @@ gif_load (struct frame *f, struct image *img)
8545 if (!STRINGP (specified_data)) 8558 if (!STRINGP (specified_data))
8546 { 8559 {
8547 image_error ("Invalid image data `%s'", specified_data); 8560 image_error ("Invalid image data `%s'", specified_data);
8548 return 0; 8561 return false;
8549 } 8562 }
8550 8563
8551 /* Read from memory! */ 8564 /* Read from memory! */
@@ -8569,7 +8582,7 @@ gif_load (struct frame *f, struct image *img)
8569 else 8582 else
8570#endif 8583#endif
8571 image_error ("Cannot open memory source `%s'", img->spec); 8584 image_error ("Cannot open memory source `%s'", img->spec);
8572 return 0; 8585 return false;
8573 } 8586 }
8574 } 8587 }
8575 8588
@@ -8577,8 +8590,7 @@ gif_load (struct frame *f, struct image *img)
8577 if (!check_image_size (f, gif->SWidth, gif->SHeight)) 8590 if (!check_image_size (f, gif->SWidth, gif->SHeight))
8578 { 8591 {
8579 image_size_error (); 8592 image_size_error ();
8580 gif_close (gif, NULL); 8593 goto gif_error;
8581 return 0;
8582 } 8594 }
8583 8595
8584 /* Read entire contents. */ 8596 /* Read entire contents. */
@@ -8589,8 +8601,7 @@ gif_load (struct frame *f, struct image *img)
8589 image_error ("Error reading `%s'", img->spec); 8601 image_error ("Error reading `%s'", img->spec);
8590 else 8602 else
8591 image_error ("Error reading GIF data"); 8603 image_error ("Error reading GIF data");
8592 gif_close (gif, NULL); 8604 goto gif_error;
8593 return 0;
8594 } 8605 }
8595 8606
8596 /* Which sub-image are we to display? */ 8607 /* Which sub-image are we to display? */
@@ -8601,8 +8612,7 @@ gif_load (struct frame *f, struct image *img)
8601 { 8612 {
8602 image_error ("Invalid image number `%s' in image `%s'", 8613 image_error ("Invalid image number `%s' in image `%s'",
8603 image_number, img->spec); 8614 image_number, img->spec);
8604 gif_close (gif, NULL); 8615 goto gif_error;
8605 return 0;
8606 } 8616 }
8607 } 8617 }
8608 8618
@@ -8619,8 +8629,7 @@ gif_load (struct frame *f, struct image *img)
8619 if (!check_image_size (f, width, height)) 8629 if (!check_image_size (f, width, height))
8620 { 8630 {
8621 image_size_error (); 8631 image_size_error ();
8622 gif_close (gif, NULL); 8632 goto gif_error;
8623 return 0;
8624 } 8633 }
8625 8634
8626 /* Check that the selected subimages fit. It's not clear whether 8635 /* Check that the selected subimages fit. It's not clear whether
@@ -8637,18 +8646,14 @@ gif_load (struct frame *f, struct image *img)
8637 && 0 <= subimg_left && subimg_left <= width - subimg_width)) 8646 && 0 <= subimg_left && subimg_left <= width - subimg_width))
8638 { 8647 {
8639 image_error ("Subimage does not fit in image"); 8648 image_error ("Subimage does not fit in image");
8640 gif_close (gif, NULL); 8649 goto gif_error;
8641 return 0;
8642 } 8650 }
8643 } 8651 }
8644 8652
8645 /* Create the X image and pixmap. */ 8653 /* Create the X image and pixmap. */
8646 Emacs_Pix_Container ximg; 8654 Emacs_Pix_Container ximg;
8647 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0)) 8655 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
8648 { 8656 goto gif_error;
8649 gif_close (gif, NULL);
8650 return 0;
8651 }
8652 8657
8653 /* Clear the part of the screen image not covered by the image. 8658 /* Clear the part of the screen image not covered by the image.
8654 Full animated GIF support requires more here (see the gif89 spec, 8659 Full animated GIF support requires more here (see the gif89 spec,
@@ -8707,13 +8712,17 @@ gif_load (struct frame *f, struct image *img)
8707 char *, which invites problems with bytes >= 0x80. */ 8712 char *, which invites problems with bytes >= 0x80. */
8708 struct SavedImage *subimage = gif->SavedImages + j; 8713 struct SavedImage *subimage = gif->SavedImages + j;
8709 unsigned char *raster = (unsigned char *) subimage->RasterBits; 8714 unsigned char *raster = (unsigned char *) subimage->RasterBits;
8710 int transparency_color_index = -1;
8711 int disposal = 0;
8712 int subimg_width = subimage->ImageDesc.Width; 8715 int subimg_width = subimage->ImageDesc.Width;
8713 int subimg_height = subimage->ImageDesc.Height; 8716 int subimg_height = subimage->ImageDesc.Height;
8714 int subimg_top = subimage->ImageDesc.Top; 8717 int subimg_top = subimage->ImageDesc.Top;
8715 int subimg_left = subimage->ImageDesc.Left; 8718 int subimg_left = subimage->ImageDesc.Left;
8716 8719
8720 /* From gif89a spec: 1 = "keep in place", 2 = "restore
8721 to background". Treat any other value like 2. */
8722 int disposal = DISPOSAL_UNSPECIFIED;
8723 int transparency_color_index = NO_TRANSPARENT_COLOR;
8724
8725#if GIFLIB_MAJOR < 5
8717 /* Find the Graphic Control Extension block for this sub-image. 8726 /* Find the Graphic Control Extension block for this sub-image.
8718 Extract the disposal method and transparency color. */ 8727 Extract the disposal method and transparency color. */
8719 for (i = 0; i < subimage->ExtensionBlockCount; i++) 8728 for (i = 0; i < subimage->ExtensionBlockCount; i++)
@@ -8724,24 +8733,29 @@ gif_load (struct frame *f, struct image *img)
8724 && extblock->ByteCount == 4 8733 && extblock->ByteCount == 4
8725 && extblock->Bytes[0] & 1) 8734 && extblock->Bytes[0] & 1)
8726 { 8735 {
8727 /* From gif89a spec: 1 = "keep in place", 2 = "restore
8728 to background". Treat any other value like 2. */
8729 disposal = (extblock->Bytes[0] >> 2) & 7; 8736 disposal = (extblock->Bytes[0] >> 2) & 7;
8730 transparency_color_index = (unsigned char) extblock->Bytes[3]; 8737 transparency_color_index = (unsigned char) extblock->Bytes[3];
8731 break; 8738 break;
8732 } 8739 }
8733 } 8740 }
8741#else
8742 GraphicsControlBlock gcb;
8743 DGifSavedExtensionToGCB (gif, j, &gcb);
8744 disposal = gcb.DisposalMode;
8745 transparency_color_index = gcb.TransparentColor;
8746#endif
8734 8747
8735 /* We can't "keep in place" the first subimage. */ 8748 /* We can't "keep in place" the first subimage. */
8736 if (j == 0) 8749 if (j == 0)
8737 disposal = 2; 8750 disposal = DISPOSE_BACKGROUND;
8738 8751
8739 /* For disposal == 0, the spec says "No disposal specified. The 8752 /* For disposal == 0 (DISPOSAL_UNSPECIFIED), the spec says
8740 decoder is not required to take any action." In practice, it 8753 "No disposal specified. The decoder is not required to take
8741 seems we need to treat this like "keep in place", see e.g. 8754 any action." In practice, it seems we need to treat this
8755 like "keep in place" (DISPOSE_DO_NOT), see e.g.
8742 https://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */ 8756 https://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */
8743 if (disposal == 0) 8757 if (disposal == DISPOSAL_UNSPECIFIED)
8744 disposal = 1; 8758 disposal = DISPOSE_DO_NOT;
8745 8759
8746 gif_color_map = subimage->ImageDesc.ColorMap; 8760 gif_color_map = subimage->ImageDesc.ColorMap;
8747 if (!gif_color_map) 8761 if (!gif_color_map)
@@ -8780,7 +8794,7 @@ gif_load (struct frame *f, struct image *img)
8780 for (x = 0; x < subimg_width; x++) 8794 for (x = 0; x < subimg_width; x++)
8781 { 8795 {
8782 int c = raster[y * subimg_width + x]; 8796 int c = raster[y * subimg_width + x];
8783 if (transparency_color_index != c || disposal != 1) 8797 if (transparency_color_index != c || disposal != DISPOSE_DO_NOT)
8784 { 8798 {
8785 PUT_PIXEL (ximg, x + subimg_left, row + subimg_top, 8799 PUT_PIXEL (ximg, x + subimg_left, row + subimg_top,
8786 pixel_colors[c]); 8800 pixel_colors[c]);
@@ -8794,7 +8808,7 @@ gif_load (struct frame *f, struct image *img)
8794 for (x = 0; x < subimg_width; ++x) 8808 for (x = 0; x < subimg_width; ++x)
8795 { 8809 {
8796 int c = raster[y * subimg_width + x]; 8810 int c = raster[y * subimg_width + x];
8797 if (transparency_color_index != c || disposal != 1) 8811 if (transparency_color_index != c || disposal != DISPOSE_DO_NOT)
8798 { 8812 {
8799 PUT_PIXEL (ximg, x + subimg_left, y + subimg_top, 8813 PUT_PIXEL (ximg, x + subimg_left, y + subimg_top,
8800 pixel_colors[c]); 8814 pixel_colors[c]);
@@ -8864,14 +8878,296 @@ gif_load (struct frame *f, struct image *img)
8864 /* Put ximg into the image. */ 8878 /* Put ximg into the image. */
8865 image_put_x_image (f, img, ximg, 0); 8879 image_put_x_image (f, img, ximg, 0);
8866 8880
8867 return 1; 8881 return true;
8882
8883 gif_error:
8884 gif_close (gif, NULL);
8885 return false;
8868} 8886}
8869 8887
8870#endif /* HAVE_GIF */ 8888#endif /* HAVE_GIF */
8871 8889
8872 8890
8891#ifdef HAVE_WEBP
8892
8893
8894/***********************************************************************
8895 WebP
8896 ***********************************************************************/
8897
8898#include "webp/decode.h"
8899
8900/* Indices of image specification fields in webp_format, below. */
8901
8902enum webp_keyword_index
8903{
8904 WEBP_TYPE,
8905 WEBP_DATA,
8906 WEBP_FILE,
8907 WEBP_ASCENT,
8908 WEBP_MARGIN,
8909 WEBP_RELIEF,
8910 WEBP_ALGORITHM,
8911 WEBP_HEURISTIC_MASK,
8912 WEBP_MASK,
8913 WEBP_BACKGROUND,
8914 WEBP_LAST
8915};
8916
8917/* Vector of image_keyword structures describing the format
8918 of valid user-defined image specifications. */
8919
8920static const struct image_keyword webp_format[WEBP_LAST] =
8921{
8922 {":type", IMAGE_SYMBOL_VALUE, 1},
8923 {":data", IMAGE_STRING_VALUE, 0},
8924 {":file", IMAGE_STRING_VALUE, 0},
8925 {":ascent", IMAGE_ASCENT_VALUE, 0},
8926 {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
8927 {":relief", IMAGE_INTEGER_VALUE, 0},
8928 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8929 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8930 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8931 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
8932};
8933
8934/* Return true if OBJECT is a valid WebP image specification. */
8935
8936static bool
8937webp_image_p (Lisp_Object object)
8938{
8939 struct image_keyword fmt[WEBP_LAST];
8940 memcpy (fmt, webp_format, sizeof fmt);
8941
8942 if (!parse_image_spec (object, fmt, WEBP_LAST, Qwebp))
8943 return false;
8944
8945 /* Must specify either the :data or :file keyword. */
8946 return fmt[WEBP_FILE].count + fmt[WEBP_DATA].count == 1;
8947}
8948
8949#ifdef WINDOWSNT
8950
8951/* WebP library details. */
8952
8953DEF_DLL_FN (int, WebPGetInfo, (const uint8_t *, size_t, int *, int *));
8954/* WebPGetFeatures is a static inline function defined in WebP's
8955 decode.h. Since we cannot use that with dynamically-loaded libwebp
8956 DLL, we instead load the internal function it calls and redirect to
8957 that through a macro. */
8958DEF_DLL_FN (VP8StatusCode, WebPGetFeaturesInternal,
8959 (const uint8_t *, size_t, WebPBitstreamFeatures *, int));
8960DEF_DLL_FN (uint8_t *, WebPDecodeRGBA, (const uint8_t *, size_t, int *, int *));
8961DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *));
8962DEF_DLL_FN (void, WebPFree, (void *));
8963
8964static bool
8965init_webp_functions (void)
8966{
8967 HMODULE library;
8968
8969 if (!(library = w32_delayed_load (Qwebp)))
8970 return false;
8971
8972 LOAD_DLL_FN (library, WebPGetInfo);
8973 LOAD_DLL_FN (library, WebPGetFeaturesInternal);
8974 LOAD_DLL_FN (library, WebPDecodeRGBA);
8975 LOAD_DLL_FN (library, WebPDecodeRGB);
8976 LOAD_DLL_FN (library, WebPFree);
8977 return true;
8978}
8979
8980#undef WebPGetInfo
8981#undef WebPGetFeatures
8982#undef WebPDecodeRGBA
8983#undef WebPDecodeRGB
8984#undef WebPFree
8985
8986#define WebPGetInfo fn_WebPGetInfo
8987#define WebPGetFeatures(d,s,f) \
8988 fn_WebPGetFeaturesInternal(d,s,f,WEBP_DECODER_ABI_VERSION)
8989#define WebPDecodeRGBA fn_WebPDecodeRGBA
8990#define WebPDecodeRGB fn_WebPDecodeRGB
8991#define WebPFree fn_WebPFree
8992
8993#endif /* WINDOWSNT */
8994
8995/* Load WebP image IMG for use on frame F. Value is true if
8996 successful. */
8997
8998static bool
8999webp_load (struct frame *f, struct image *img)
9000{
9001 ptrdiff_t size = 0;
9002 uint8_t *contents;
9003 Lisp_Object file;
9004
9005 /* Open the WebP file. */
9006 Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
9007 Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
9008
9009 if (NILP (specified_data))
9010 {
9011 int fd;
9012 file = image_find_image_fd (specified_file, &fd);
9013 if (!STRINGP (file))
9014 {
9015 image_error ("Cannot find image file `%s'", specified_file);
9016 return false;
9017 }
9018
9019 contents = (uint8_t *) slurp_file (fd, &size);
9020 if (contents == NULL)
9021 {
9022 image_error ("Error loading WebP image `%s'", file);
9023 return false;
9024 }
9025 }
9026 else
9027 {
9028 if (!STRINGP (specified_data))
9029 {
9030 image_error ("Invalid image data `%s'", specified_data);
9031 return false;
9032 }
9033 contents = SDATA (specified_data);
9034 size = SBYTES (specified_data);
9035 }
9036
9037 /* Validate the WebP image header. */
9038 if (!WebPGetInfo (contents, size, NULL, NULL))
9039 {
9040 if (NILP (specified_data))
9041 image_error ("Not a WebP file: `%s'", file);
9042 else
9043 image_error ("Invalid header in WebP image data");
9044 goto webp_error1;
9045 }
9046
9047 /* Get WebP features. */
9048 WebPBitstreamFeatures features;
9049 VP8StatusCode result = WebPGetFeatures (contents, size, &features);
9050 switch (result)
9051 {
9052 case VP8_STATUS_OK:
9053 break;
9054 case VP8_STATUS_NOT_ENOUGH_DATA:
9055 case VP8_STATUS_OUT_OF_MEMORY:
9056 case VP8_STATUS_INVALID_PARAM:
9057 case VP8_STATUS_BITSTREAM_ERROR:
9058 case VP8_STATUS_UNSUPPORTED_FEATURE:
9059 case VP8_STATUS_SUSPENDED:
9060 case VP8_STATUS_USER_ABORT:
9061 default:
9062 /* Error out in all other cases. */
9063 if (NILP (specified_data))
9064 image_error ("Error when interpreting WebP image data: `%s'", file);
9065 else
9066 image_error ("Error when interpreting WebP image data");
9067 goto webp_error1;
9068 }
9069
9070 /* Decode WebP data. */
9071 uint8_t *decoded;
9072 int width, height;
9073 if (features.has_alpha)
9074 /* Linear [r0, g0, b0, a0, r1, g1, b1, a1, ...] order. */
9075 decoded = WebPDecodeRGBA (contents, size, &width, &height);
9076 else
9077 /* Linear [r0, g0, b0, r1, g1, b1, ...] order. */
9078 decoded = WebPDecodeRGB (contents, size, &width, &height);
9079
9080 if (!(width <= INT_MAX && height <= INT_MAX
9081 && check_image_size (f, width, height)))
9082 {
9083 image_size_error ();
9084 goto webp_error2;
9085 }
9086
9087 /* Create the x image and pixmap. */
9088 Emacs_Pix_Container ximg, mask_img;
9089 if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false))
9090 goto webp_error2;
9091
9092 /* Create an image and pixmap serving as mask if the WebP image
9093 contains an alpha channel. */
9094 if (features.has_alpha
9095 && !image_create_x_image_and_pixmap (f, img, width, height, 1, &mask_img, true))
9096 {
9097 image_destroy_x_image (ximg);
9098 image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
9099 goto webp_error2;
9100 }
9101
9102 /* Fill the X image and mask from WebP data. */
9103 init_color_table ();
9104
9105 uint8_t *p = decoded;
9106 for (int y = 0; y < height; ++y)
9107 {
9108 for (int x = 0; x < width; ++x)
9109 {
9110 int r = *p++ << 8;
9111 int g = *p++ << 8;
9112 int b = *p++ << 8;
9113 PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
9114
9115 /* An alpha channel associates variable transparency with an
9116 image. WebP allows up to 256 levels of partial transparency.
9117 We handle this like with PNG (which see), using the frame's
9118 background color to combine the image with. */
9119 if (features.has_alpha)
9120 {
9121 if (mask_img)
9122 PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
9123 ++p;
9124 }
9125 }
9126 }
9127
9128#ifdef COLOR_TABLE_SUPPORT
9129 /* Remember colors allocated for this image. */
9130 img->colors = colors_in_color_table (&img->ncolors);
9131 free_color_table ();
9132#endif /* COLOR_TABLE_SUPPORT */
9133
9134 /* Put ximg into the image. */
9135 image_put_x_image (f, img, ximg, 0);
9136
9137 /* Same for the mask. */
9138 if (mask_img)
9139 {
9140 /* Fill in the background_transparent field while we have the
9141 mask handy. Casting avoids a GCC warning. */
9142 image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
9143
9144 image_put_x_image (f, img, mask_img, 1);
9145 }
9146
9147 img->width = width;
9148 img->height = height;
9149
9150 /* Clean up. */
9151 WebPFree (decoded);
9152 if (NILP (specified_data))
9153 xfree (contents);
9154 return true;
9155
9156 webp_error2:
9157 WebPFree (decoded);
9158
9159 webp_error1:
9160 if (NILP (specified_data))
9161 xfree (contents);
9162 return false;
9163}
9164
9165#endif /* HAVE_WEBP */
9166
9167
8873#ifdef HAVE_IMAGEMAGICK 9168#ifdef HAVE_IMAGEMAGICK
8874 9169
9170
8875/*********************************************************************** 9171/***********************************************************************
8876 ImageMagick 9172 ImageMagick
8877***********************************************************************/ 9173***********************************************************************/
@@ -9816,14 +10112,15 @@ DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions,
9816DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer, 10112DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer,
9817 (RsvgHandle *, const char *, const RsvgRectangle *, 10113 (RsvgHandle *, const char *, const RsvgRectangle *,
9818 RsvgRectangle *, RsvgRectangle *, GError **)); 10114 RsvgRectangle *, RsvgRectangle *, GError **));
10115# else
10116DEF_DLL_FN (void, rsvg_handle_get_dimensions,
10117 (RsvgHandle *, RsvgDimensionData *));
9819# endif 10118# endif
9820 10119
9821# if LIBRSVG_CHECK_VERSION (2, 48, 0) 10120# if LIBRSVG_CHECK_VERSION (2, 48, 0)
9822DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet, 10121DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet,
9823 (RsvgHandle *, const guint8 *, gsize, GError **)); 10122 (RsvgHandle *, const guint8 *, gsize, GError **));
9824# endif 10123# endif
9825DEF_DLL_FN (void, rsvg_handle_get_dimensions,
9826 (RsvgHandle *, RsvgDimensionData *));
9827DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *)); 10124DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *));
9828DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *)); 10125DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *));
9829DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *)); 10126DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *));
@@ -9874,11 +10171,12 @@ init_svg_functions (void)
9874#if LIBRSVG_CHECK_VERSION (2, 46, 0) 10171#if LIBRSVG_CHECK_VERSION (2, 46, 0)
9875 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions); 10172 LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions);
9876 LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer); 10173 LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer);
10174#else
10175 LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
9877#endif 10176#endif
9878#if LIBRSVG_CHECK_VERSION (2, 48, 0) 10177#if LIBRSVG_CHECK_VERSION (2, 48, 0)
9879 LOAD_DLL_FN (library, rsvg_handle_set_stylesheet); 10178 LOAD_DLL_FN (library, rsvg_handle_set_stylesheet);
9880#endif 10179#endif
9881 LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
9882 LOAD_DLL_FN (library, rsvg_handle_get_pixbuf); 10180 LOAD_DLL_FN (library, rsvg_handle_get_pixbuf);
9883 10181
9884 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width); 10182 LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width);
@@ -9916,8 +10214,9 @@ init_svg_functions (void)
9916# if LIBRSVG_CHECK_VERSION (2, 46, 0) 10214# if LIBRSVG_CHECK_VERSION (2, 46, 0)
9917# undef rsvg_handle_get_intrinsic_dimensions 10215# undef rsvg_handle_get_intrinsic_dimensions
9918# undef rsvg_handle_get_geometry_for_layer 10216# undef rsvg_handle_get_geometry_for_layer
10217# else
10218# undef rsvg_handle_get_dimensions
9919# endif 10219# endif
9920# undef rsvg_handle_get_dimensions
9921# if LIBRSVG_CHECK_VERSION (2, 48, 0) 10220# if LIBRSVG_CHECK_VERSION (2, 48, 0)
9922# undef rsvg_handle_set_stylesheet 10221# undef rsvg_handle_set_stylesheet
9923# endif 10222# endif
@@ -9952,8 +10251,9 @@ init_svg_functions (void)
9952 fn_rsvg_handle_get_intrinsic_dimensions 10251 fn_rsvg_handle_get_intrinsic_dimensions
9953# define rsvg_handle_get_geometry_for_layer \ 10252# define rsvg_handle_get_geometry_for_layer \
9954 fn_rsvg_handle_get_geometry_for_layer 10253 fn_rsvg_handle_get_geometry_for_layer
10254# else
10255# define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
9955# endif 10256# endif
9956# define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
9957# if LIBRSVG_CHECK_VERSION (2, 48, 0) 10257# if LIBRSVG_CHECK_VERSION (2, 48, 0)
9958# define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet 10258# define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet
9959# endif 10259# endif
@@ -10136,10 +10436,16 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10136 if (!STRINGP (lcss)) 10436 if (!STRINGP (lcss))
10137 { 10437 {
10138 /* Generate the CSS for the SVG image. */ 10438 /* Generate the CSS for the SVG image. */
10139 const char *css_spec = "svg{font-family:\"%s\";font-size:%4dpx}"; 10439 /* FIXME: The below calculations leave enough space for a font
10140 int css_len = strlen (css_spec) + strlen (img->face_font_family); 10440 size up to 9999, if it overflows we just throw an error but
10441 should probably increase the buffer size. */
10442 const char *css_spec = "svg{font-family:\"%s\";font-size:%dpx}";
10443 int css_len = strlen (css_spec) + strlen (img->face_font_family) + 1;
10141 css = xmalloc (css_len); 10444 css = xmalloc (css_len);
10142 snprintf (css, css_len, css_spec, img->face_font_family, img->face_font_size); 10445 if (css_len <= snprintf (css, css_len, css_spec,
10446 img->face_font_family, img->face_font_size))
10447 goto rsvg_error;
10448
10143 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL); 10449 rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), NULL);
10144 } 10450 }
10145 else 10451 else
@@ -10179,7 +10485,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10179#if LIBRSVG_CHECK_VERSION (2, 46, 0) 10485#if LIBRSVG_CHECK_VERSION (2, 46, 0)
10180 RsvgRectangle zero_rect, viewbox, out_logical_rect; 10486 RsvgRectangle zero_rect, viewbox, out_logical_rect;
10181 10487
10182 /* Try the instrinsic dimensions first. */ 10488 /* Try the intrinsic dimensions first. */
10183 gboolean has_width, has_height, has_viewbox; 10489 gboolean has_width, has_height, has_viewbox;
10184 RsvgLength iwidth, iheight; 10490 RsvgLength iwidth, iheight;
10185 double dpi = FRAME_DISPLAY_INFO (f)->resx; 10491 double dpi = FRAME_DISPLAY_INFO (f)->resx;
@@ -10214,7 +10520,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10214 } 10520 }
10215 else 10521 else
10216 { 10522 {
10217 /* We haven't found a useable set of sizes, so try working out 10523 /* We haven't found a usable set of sizes, so try working out
10218 the visible area. */ 10524 the visible area. */
10219 rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL, 10525 rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL,
10220 &zero_rect, &viewbox, 10526 &zero_rect, &viewbox,
@@ -10222,21 +10528,13 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10222 viewbox_width = viewbox.x + viewbox.width; 10528 viewbox_width = viewbox.x + viewbox.width;
10223 viewbox_height = viewbox.y + viewbox.height; 10529 viewbox_height = viewbox.y + viewbox.height;
10224 } 10530 }
10225 10531#else
10226 if (viewbox_width == 0 || viewbox_height == 0) 10532 /* In librsvg before 2.46.0, guess the viewbox from the image dimensions. */
10533 RsvgDimensionData dimension_data;
10534 rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
10535 viewbox_width = dimension_data.width;
10536 viewbox_height = dimension_data.height;
10227#endif 10537#endif
10228 {
10229 /* The functions used above to get the geometry of the visible
10230 area of the SVG are only available in librsvg 2.46 and above,
10231 so in certain circumstances this code path can result in some
10232 parts of the SVG being cropped. */
10233 RsvgDimensionData dimension_data;
10234
10235 rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
10236
10237 viewbox_width = dimension_data.width;
10238 viewbox_height = dimension_data.height;
10239 }
10240 10538
10241 compute_image_size (viewbox_width, viewbox_height, img, 10539 compute_image_size (viewbox_width, viewbox_height, img,
10242 &width, &height); 10540 &width, &height);
@@ -10297,12 +10595,11 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
10297 10595
10298 wrapped_contents = xmalloc (buffer_size); 10596 wrapped_contents = xmalloc (buffer_size);
10299 10597
10300 if (!wrapped_contents 10598 if (buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
10301 || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper, 10599 foreground & 0xFFFFFF, width, height,
10302 foreground & 0xFFFFFF, width, height, 10600 viewbox_width, viewbox_height,
10303 viewbox_width, viewbox_height, 10601 background & 0xFFFFFF,
10304 background & 0xFFFFFF, 10602 SSDATA (encoded_contents)))
10305 SSDATA (encoded_contents)))
10306 goto rsvg_error; 10603 goto rsvg_error;
10307 10604
10308 wrapped_size = strlen (wrapped_contents); 10605 wrapped_size = strlen (wrapped_contents);
@@ -10862,6 +11159,10 @@ static struct image_type const image_types[] =
10862 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image, 11159 { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
10863 IMAGE_TYPE_INIT (init_xpm_functions) }, 11160 IMAGE_TYPE_INIT (init_xpm_functions) },
10864#endif 11161#endif
11162#if defined HAVE_WEBP
11163 { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image,
11164 IMAGE_TYPE_INIT (init_webp_functions) },
11165#endif
10865 { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image }, 11166 { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image },
10866 { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image }, 11167 { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
10867}; 11168};
@@ -11027,6 +11328,11 @@ non-numeric, there is no explicit limit on the size of images. */);
11027 add_image_type (Qpng); 11328 add_image_type (Qpng);
11028#endif 11329#endif
11029 11330
11331#if defined (HAVE_WEBP)
11332 DEFSYM (Qwebp, "webp");
11333 add_image_type (Qwebp);
11334#endif
11335
11030#if defined (HAVE_IMAGEMAGICK) 11336#if defined (HAVE_IMAGEMAGICK)
11031 DEFSYM (Qimagemagick, "imagemagick"); 11337 DEFSYM (Qimagemagick, "imagemagick");
11032 add_image_type (Qimagemagick); 11338 add_image_type (Qimagemagick);
diff --git a/src/insdel.c b/src/insdel.c
index e66120eb08a..40674e15e45 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1392,7 +1392,7 @@ adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte,
1392void 1392void
1393replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, 1393replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1394 bool prepare, bool inherit, bool markers, 1394 bool prepare, bool inherit, bool markers,
1395 bool adjust_match_data) 1395 bool adjust_match_data, bool inhibit_mod_hooks)
1396{ 1396{
1397 ptrdiff_t inschars = SCHARS (new); 1397 ptrdiff_t inschars = SCHARS (new);
1398 ptrdiff_t insbytes = SBYTES (new); 1398 ptrdiff_t insbytes = SBYTES (new);
@@ -1552,8 +1552,11 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
1552 if (adjust_match_data) 1552 if (adjust_match_data)
1553 update_search_regs (from, to, from + SCHARS (new)); 1553 update_search_regs (from, to, from + SCHARS (new));
1554 1554
1555 signal_after_change (from, nchars_del, GPT - from); 1555 if (!inhibit_mod_hooks)
1556 update_compositions (from, GPT, CHECK_BORDER); 1556 {
1557 signal_after_change (from, nchars_del, GPT - from);
1558 update_compositions (from, GPT, CHECK_BORDER);
1559 }
1557} 1560}
1558 1561
1559/* Replace the text from character positions FROM to TO with 1562/* Replace the text from character positions FROM to TO with
diff --git a/src/intervals.c b/src/intervals.c
index f88a41f2549..11d5b6bbb6f 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -166,10 +166,11 @@ merge_properties (register INTERVAL source, register INTERVAL target)
166 } 166 }
167} 167}
168 168
169/* Return true if the two intervals have the same properties. */ 169/* Return true if the two intervals have the same properties.
170 If use_equal is true, use Fequal for comparisons instead of EQ. */
170 171
171bool 172static bool
172intervals_equal (INTERVAL i0, INTERVAL i1) 173intervals_equal_1 (INTERVAL i0, INTERVAL i1, bool use_equal)
173{ 174{
174 Lisp_Object i0_cdr, i0_sym; 175 Lisp_Object i0_cdr, i0_sym;
175 Lisp_Object i1_cdr, i1_val; 176 Lisp_Object i1_cdr, i1_val;
@@ -204,7 +205,8 @@ intervals_equal (INTERVAL i0, INTERVAL i1)
204 /* i0 and i1 both have sym, but it has different values in each. */ 205 /* i0 and i1 both have sym, but it has different values in each. */
205 if (!CONSP (i1_val) 206 if (!CONSP (i1_val)
206 || (i1_val = XCDR (i1_val), !CONSP (i1_val)) 207 || (i1_val = XCDR (i1_val), !CONSP (i1_val))
207 || !EQ (XCAR (i1_val), XCAR (i0_cdr))) 208 || use_equal ? NILP (Fequal (XCAR (i1_val), XCAR (i0_cdr)))
209 : !EQ (XCAR (i1_val), XCAR (i0_cdr)))
208 return false; 210 return false;
209 211
210 i0_cdr = XCDR (i0_cdr); 212 i0_cdr = XCDR (i0_cdr);
@@ -218,6 +220,14 @@ intervals_equal (INTERVAL i0, INTERVAL i1)
218 /* Lengths of the two plists were equal. */ 220 /* Lengths of the two plists were equal. */
219 return (NILP (i0_cdr) && NILP (i1_cdr)); 221 return (NILP (i0_cdr) && NILP (i1_cdr));
220} 222}
223
224/* Return true if the two intervals have the same properties. */
225
226bool
227intervals_equal (INTERVAL i0, INTERVAL i1)
228{
229 return intervals_equal_1 (i0, i1, false);
230}
221 231
222 232
223/* Traverse an interval tree TREE, performing FUNCTION on each node. 233/* Traverse an interval tree TREE, performing FUNCTION on each node.
@@ -2291,7 +2301,7 @@ compare_string_intervals (Lisp_Object s1, Lisp_Object s2)
2291 2301
2292 /* If we ever find a mismatch between the strings, 2302 /* If we ever find a mismatch between the strings,
2293 they differ. */ 2303 they differ. */
2294 if (! intervals_equal (i1, i2)) 2304 if (! intervals_equal_1 (i1, i2, true))
2295 return 0; 2305 return 0;
2296 2306
2297 /* Advance POS till the end of the shorter interval, 2307 /* Advance POS till the end of the shorter interval,
diff --git a/src/keyboard.c b/src/keyboard.c
index 5b828ca60ff..79c353702c7 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -375,6 +375,7 @@ static void timer_resume_idle (void);
375static void deliver_user_signal (int); 375static void deliver_user_signal (int);
376static char *find_user_signal_name (int); 376static char *find_user_signal_name (int);
377static void store_user_signal_events (void); 377static void store_user_signal_events (void);
378static bool is_ignored_event (union buffered_input_event *);
378 379
379/* Advance or retreat a buffered input event pointer. */ 380/* Advance or retreat a buffered input event pointer. */
380 381
@@ -753,10 +754,21 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
753 doc: /* Invoke the editor command loop recursively. 754 doc: /* Invoke the editor command loop recursively.
754To get out of the recursive edit, a command can throw to `exit' -- for 755To get out of the recursive edit, a command can throw to `exit' -- for
755instance (throw \\='exit nil). 756instance (throw \\='exit nil).
756If you throw a value other than t, `recursive-edit' returns normally 757
757to the function that called it. Throwing a t value causes 758The following values (last argument to `throw') can be used when
758`recursive-edit' to quit, so that control returns to the command loop 759throwing to \\='exit:
759one level up. 760
761- t causes `recursive-edit' to quit, so that control returns to the
762 command loop one level up.
763
764- A string causes `recursive-edit' to signal an error, printing that
765 string as the error message.
766
767- A function causes `recursive-edit' to call that function with no
768 arguments, and then return normally.
769
770- Any other value causes `recursive-edit' to return normally to the
771 function that called it.
760 772
761This function is called by the editor initialization to begin editing. */) 773This function is called by the editor initialization to begin editing. */)
762 (void) 774 (void)
@@ -924,6 +936,7 @@ static Lisp_Object
924cmd_error (Lisp_Object data) 936cmd_error (Lisp_Object data)
925{ 937{
926 Lisp_Object old_level, old_length; 938 Lisp_Object old_level, old_length;
939 ptrdiff_t count = SPECPDL_INDEX ();
927 Lisp_Object conditions; 940 Lisp_Object conditions;
928 char macroerror[sizeof "After..kbd macro iterations: " 941 char macroerror[sizeof "After..kbd macro iterations: "
929 + INT_STRLEN_BOUND (EMACS_INT)]; 942 + INT_STRLEN_BOUND (EMACS_INT)];
@@ -950,9 +963,13 @@ cmd_error (Lisp_Object data)
950 Vexecuting_kbd_macro = Qnil; 963 Vexecuting_kbd_macro = Qnil;
951 executing_kbd_macro = Qnil; 964 executing_kbd_macro = Qnil;
952 } 965 }
966 else if (!NILP (KVAR (current_kboard, defining_kbd_macro)))
967 /* An `M-x' command that signals a `minibuffer-quit' condition
968 that's part of a kbd macro. */
969 finalize_kbd_macro_chars ();
953 970
954 Vstandard_output = Qt; 971 specbind (Qstandard_output, Qt);
955 Vstandard_input = Qt; 972 specbind (Qstandard_input, Qt);
956 kset_prefix_arg (current_kboard, Qnil); 973 kset_prefix_arg (current_kboard, Qnil);
957 kset_last_prefix_arg (current_kboard, Qnil); 974 kset_last_prefix_arg (current_kboard, Qnil);
958 cancel_echoing (); 975 cancel_echoing ();
@@ -969,6 +986,7 @@ cmd_error (Lisp_Object data)
969 Vquit_flag = Qnil; 986 Vquit_flag = Qnil;
970 Vinhibit_quit = Qnil; 987 Vinhibit_quit = Qnil;
971 988
989 unbind_to (count, Qnil);
972 return make_fixnum (0); 990 return make_fixnum (0);
973} 991}
974 992
@@ -1007,25 +1025,28 @@ Default value of `command-error-function'. */)
1007 (Lisp_Object data, Lisp_Object context, Lisp_Object signal) 1025 (Lisp_Object data, Lisp_Object context, Lisp_Object signal)
1008{ 1026{
1009 struct frame *sf = SELECTED_FRAME (); 1027 struct frame *sf = SELECTED_FRAME ();
1010 Lisp_Object conditions; 1028 Lisp_Object conditions = Fget (XCAR (data), Qerror_conditions);
1029 int is_minibuffer_quit = !NILP (Fmemq (Qminibuffer_quit, conditions));
1011 1030
1012 CHECK_STRING (context); 1031 CHECK_STRING (context);
1013 1032
1014 /* If the window system or terminal frame hasn't been initialized 1033 /* If the window system or terminal frame hasn't been initialized
1015 yet, or we're not interactive, write the message to stderr and exit. */ 1034 yet, or we're not interactive, write the message to stderr and exit.
1016 if (!sf->glyphs_initialized_p 1035 Don't do this for the minibuffer-quit condition. */
1017 /* The initial frame is a special non-displaying frame. It 1036 if (!is_minibuffer_quit
1018 will be current in daemon mode when there are no frames 1037 && (!sf->glyphs_initialized_p
1019 to display, and in non-daemon mode before the real frame 1038 /* The initial frame is a special non-displaying frame. It
1020 has finished initializing. If an error is thrown in the 1039 will be current in daemon mode when there are no frames
1021 latter case while creating the frame, then the frame 1040 to display, and in non-daemon mode before the real frame
1022 will never be displayed, so the safest thing to do is 1041 has finished initializing. If an error is thrown in the
1023 write to stderr and quit. In daemon mode, there are 1042 latter case while creating the frame, then the frame
1024 many other potential errors that do not prevent frames 1043 will never be displayed, so the safest thing to do is
1025 from being created, so continuing as normal is better in 1044 write to stderr and quit. In daemon mode, there are
1026 that case. */ 1045 many other potential errors that do not prevent frames
1027 || (!IS_DAEMON && FRAME_INITIAL_P (sf)) 1046 from being created, so continuing as normal is better in
1028 || noninteractive) 1047 that case. */
1048 || (!IS_DAEMON && FRAME_INITIAL_P (sf))
1049 || noninteractive))
1029 { 1050 {
1030 print_error_message (data, Qexternal_debugging_output, 1051 print_error_message (data, Qexternal_debugging_output,
1031 SSDATA (context), signal); 1052 SSDATA (context), signal);
@@ -1034,12 +1055,10 @@ Default value of `command-error-function'. */)
1034 } 1055 }
1035 else 1056 else
1036 { 1057 {
1037 conditions = Fget (XCAR (data), Qerror_conditions);
1038
1039 clear_message (1, 0); 1058 clear_message (1, 0);
1040 message_log_maybe_newline (); 1059 message_log_maybe_newline ();
1041 1060
1042 if (!NILP (Fmemq (Qminibuffer_quit, conditions))) 1061 if (is_minibuffer_quit)
1043 { 1062 {
1044 Fding (Qt); 1063 Fding (Qt);
1045 } 1064 }
@@ -2925,20 +2944,8 @@ read_char (int commandflag, Lisp_Object map,
2925 last_input_event = c; 2944 last_input_event = c;
2926 call4 (Qcommand_execute, tem, Qnil, Fvector (1, &last_input_event), Qt); 2945 call4 (Qcommand_execute, tem, Qnil, Fvector (1, &last_input_event), Qt);
2927 2946
2928 if (CONSP (c) 2947 if (CONSP (c) && !NILP (Fmemq (XCAR (c), Vwhile_no_input_ignore_events))
2929 && (EQ (XCAR (c), Qselect_window) 2948 && !end_time)
2930 || EQ (XCAR (c), Qfocus_out)
2931#ifdef HAVE_DBUS
2932 || EQ (XCAR (c), Qdbus_event)
2933#endif
2934#ifdef USE_FILE_NOTIFY
2935 || EQ (XCAR (c), Qfile_notify)
2936#endif
2937#ifdef THREADS_ENABLED
2938 || EQ (XCAR (c), Qthread_event)
2939#endif
2940 || EQ (XCAR (c), Qconfig_changed_event))
2941 && !end_time)
2942 /* We stopped being idle for this event; undo that. This 2949 /* We stopped being idle for this event; undo that. This
2943 prevents automatic window selection (under 2950 prevents automatic window selection (under
2944 mouse-autoselect-window) from acting as a real input event, for 2951 mouse-autoselect-window) from acting as a real input event, for
@@ -3440,10 +3447,17 @@ readable_events (int flags)
3440 if (flags & READABLE_EVENTS_DO_TIMERS_NOW) 3447 if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
3441 timer_check (); 3448 timer_check ();
3442 3449
3443 /* If the buffer contains only FOCUS_IN/OUT_EVENT events, and 3450 /* READABLE_EVENTS_FILTER_EVENTS is meant to be used only by
3444 READABLE_EVENTS_FILTER_EVENTS is set, report it as empty. */ 3451 input-pending-p and similar callers, which aren't interested in
3452 some input events. If this flag is set, and
3453 input-pending-p-filter-events is non-nil, ignore events in
3454 while-no-input-ignore-events. If the flag is set and
3455 input-pending-p-filter-events is nil, ignore only
3456 FOCUS_IN/OUT_EVENT events. */
3445 if (kbd_fetch_ptr != kbd_store_ptr) 3457 if (kbd_fetch_ptr != kbd_store_ptr)
3446 { 3458 {
3459 /* See https://lists.gnu.org/r/emacs-devel/2005-05/msg00297.html
3460 for why we treat toolkit scroll-bar events specially here. */
3447 if (flags & (READABLE_EVENTS_FILTER_EVENTS 3461 if (flags & (READABLE_EVENTS_FILTER_EVENTS
3448#ifdef USE_TOOLKIT_SCROLL_BARS 3462#ifdef USE_TOOLKIT_SCROLL_BARS
3449 | READABLE_EVENTS_IGNORE_SQUEEZABLES 3463 | READABLE_EVENTS_IGNORE_SQUEEZABLES
@@ -3458,8 +3472,11 @@ readable_events (int flags)
3458#ifdef USE_TOOLKIT_SCROLL_BARS 3472#ifdef USE_TOOLKIT_SCROLL_BARS
3459 (flags & READABLE_EVENTS_FILTER_EVENTS) && 3473 (flags & READABLE_EVENTS_FILTER_EVENTS) &&
3460#endif 3474#endif
3461 (event->kind == FOCUS_IN_EVENT 3475 ((!input_pending_p_filter_events
3462 || event->kind == FOCUS_OUT_EVENT)) 3476 && (event->kind == FOCUS_IN_EVENT
3477 || event->kind == FOCUS_OUT_EVENT))
3478 || (input_pending_p_filter_events
3479 && is_ignored_event (event))))
3463#ifdef USE_TOOLKIT_SCROLL_BARS 3480#ifdef USE_TOOLKIT_SCROLL_BARS
3464 && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) 3481 && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
3465 && (event->kind == SCROLL_BAR_CLICK_EVENT 3482 && (event->kind == SCROLL_BAR_CLICK_EVENT
@@ -3641,29 +3658,10 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event,
3641#endif /* subprocesses */ 3658#endif /* subprocesses */
3642 } 3659 }
3643 3660
3644 Lisp_Object ignore_event;
3645
3646 switch (event->kind)
3647 {
3648 case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break;
3649 case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break;
3650 case HELP_EVENT: ignore_event = Qhelp_echo; break;
3651 case ICONIFY_EVENT: ignore_event = Qiconify_frame; break;
3652 case DEICONIFY_EVENT: ignore_event = Qmake_frame_visible; break;
3653 case SELECTION_REQUEST_EVENT: ignore_event = Qselection_request; break;
3654#ifdef USE_FILE_NOTIFY
3655 case FILE_NOTIFY_EVENT: ignore_event = Qfile_notify; break;
3656#endif
3657#ifdef HAVE_DBUS
3658 case DBUS_EVENT: ignore_event = Qdbus_event; break;
3659#endif
3660 default: ignore_event = Qnil; break;
3661 }
3662
3663 /* If we're inside while-no-input, and this event qualifies 3661 /* If we're inside while-no-input, and this event qualifies
3664 as input, set quit-flag to cause an interrupt. */ 3662 as input, set quit-flag to cause an interrupt. */
3665 if (!NILP (Vthrow_on_input) 3663 if (!NILP (Vthrow_on_input)
3666 && NILP (Fmemq (ignore_event, Vwhile_no_input_ignore_events))) 3664 && !is_ignored_event (event))
3667 Vquit_flag = Vthrow_on_input; 3665 Vquit_flag = Vthrow_on_input;
3668} 3666}
3669 3667
@@ -3998,6 +3996,7 @@ kbd_buffer_get_event (KBOARD **kbp,
3998#endif 3996#endif
3999#ifdef HAVE_XWIDGETS 3997#ifdef HAVE_XWIDGETS
4000 case XWIDGET_EVENT: 3998 case XWIDGET_EVENT:
3999 case XWIDGET_DISPLAY_EVENT:
4001#endif 4000#endif
4002 case SAVE_SESSION_EVENT: 4001 case SAVE_SESSION_EVENT:
4003 case NO_EVENT: 4002 case NO_EVENT:
@@ -4235,7 +4234,7 @@ decode_timer (Lisp_Object timer, struct timespec *result)
4235{ 4234{
4236 Lisp_Object *vec; 4235 Lisp_Object *vec;
4237 4236
4238 if (! (VECTORP (timer) && ASIZE (timer) == 9)) 4237 if (! (VECTORP (timer) && ASIZE (timer) == 10))
4239 return false; 4238 return false;
4240 vec = XVECTOR (timer)->contents; 4239 vec = XVECTOR (timer)->contents;
4241 if (! NILP (vec[0])) 4240 if (! NILP (vec[0]))
@@ -4902,7 +4901,7 @@ static const char *const lispy_kana_keys[] =
4902 4901
4903/* You'll notice that this table is arranged to be conveniently 4902/* You'll notice that this table is arranged to be conveniently
4904 indexed by X Windows keysym values. */ 4903 indexed by X Windows keysym values. */
4905static const char *const lispy_function_keys[] = 4904const char *const lispy_function_keys[] =
4906 { 4905 {
4907 /* X Keysym value */ 4906 /* X Keysym value */
4908 4907
@@ -5088,13 +5087,56 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5088 enum window_part part; 5087 enum window_part part;
5089 Lisp_Object posn = Qnil; 5088 Lisp_Object posn = Qnil;
5090 Lisp_Object extra_info = Qnil; 5089 Lisp_Object extra_info = Qnil;
5090 int mx = XFIXNUM (x), my = XFIXNUM (y);
5091 /* Coordinate pixel positions to return. */ 5091 /* Coordinate pixel positions to return. */
5092 int xret = 0, yret = 0; 5092 int xret = 0, yret = 0;
5093 /* The window or frame under frame pixel coordinates (x,y) */ 5093 /* The window or frame under frame pixel coordinates (x,y) */
5094 Lisp_Object window_or_frame = f 5094 Lisp_Object window_or_frame = f
5095 ? window_from_coordinates (f, XFIXNUM (x), XFIXNUM (y), &part, 0, 0) 5095 ? window_from_coordinates (f, mx, my, &part, true, true)
5096 : Qnil; 5096 : Qnil;
5097 5097
5098 /* Report mouse events on the tab bar and (on GUI frames) on the
5099 tool bar. */
5100#ifdef HAVE_WINDOW_SYSTEM
5101 if ((WINDOWP (f->tab_bar_window)
5102 && EQ (window_or_frame, f->tab_bar_window))
5103#ifndef HAVE_EXT_TOOL_BAR
5104 || (WINDOWP (f->tool_bar_window)
5105 && EQ (window_or_frame, f->tool_bar_window))
5106#endif
5107 )
5108 {
5109 /* FIXME: While track_mouse is non-nil, we do not report this
5110 event as something that happened on the tool or tab bar since
5111 that would break mouse dragging operations that originate from
5112 an ordinary window beneath and expect the window to auto-scroll
5113 as soon as the mouse cursor appears above or beneath it
5114 (Bug#50993). Since this "fix" might break track_mouse based
5115 operations originating from the tool or tab bar itself, such
5116 operations should set track_mouse to some special value that
5117 would be recognized by the following check.
5118
5119 This issue should be properly handled by 'mouse-drag-track' and
5120 friends, so the below is only a temporary workaround. */
5121 if (NILP (track_mouse))
5122 posn = EQ (window_or_frame, f->tab_bar_window) ? Qtab_bar : Qtool_bar;
5123 /* Kludge alert: for mouse events on the tab bar and tool bar,
5124 keyboard.c wants the frame, not the special-purpose window
5125 we use to display those, and it wants frame-relative
5126 coordinates. FIXME! */
5127 window_or_frame = Qnil;
5128 }
5129#endif
5130 if (f
5131 && !FRAME_WINDOW_P (f)
5132 && FRAME_TAB_BAR_LINES (f) > 0
5133 && my >= FRAME_MENU_BAR_LINES (f)
5134 && my < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))
5135 {
5136 posn = Qtab_bar;
5137 window_or_frame = Qnil; /* see above */
5138 }
5139
5098 if (WINDOWP (window_or_frame)) 5140 if (WINDOWP (window_or_frame))
5099 { 5141 {
5100 /* It's a click in window WINDOW at frame coordinates (X,Y) */ 5142 /* It's a click in window WINDOW at frame coordinates (X,Y) */
@@ -5107,15 +5149,15 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5107 Lisp_Object object = Qnil; 5149 Lisp_Object object = Qnil;
5108 5150
5109 /* Pixel coordinates relative to the window corner. */ 5151 /* Pixel coordinates relative to the window corner. */
5110 int wx = XFIXNUM (x) - WINDOW_LEFT_EDGE_X (w); 5152 int wx = mx - WINDOW_LEFT_EDGE_X (w);
5111 int wy = XFIXNUM (y) - WINDOW_TOP_EDGE_Y (w); 5153 int wy = my - WINDOW_TOP_EDGE_Y (w);
5112 5154
5113 /* For text area clicks, return X, Y relative to the corner of 5155 /* For text area clicks, return X, Y relative to the corner of
5114 this text area. Note that dX, dY etc are set below, by 5156 this text area. Note that dX, dY etc are set below, by
5115 buffer_posn_from_coords. */ 5157 buffer_posn_from_coords. */
5116 if (part == ON_TEXT) 5158 if (part == ON_TEXT)
5117 { 5159 {
5118 xret = XFIXNUM (x) - window_box_left (w, TEXT_AREA); 5160 xret = mx - window_box_left (w, TEXT_AREA);
5119 yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); 5161 yret = wy - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w);
5120 } 5162 }
5121 /* For mode line and header line clicks, return X, Y relative to 5163 /* For mode line and header line clicks, return X, Y relative to
@@ -5239,7 +5281,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5239 : (part == ON_RIGHT_FRINGE || part == ON_RIGHT_MARGIN 5281 : (part == ON_RIGHT_FRINGE || part == ON_RIGHT_MARGIN
5240 || (part == ON_VERTICAL_SCROLL_BAR 5282 || (part == ON_VERTICAL_SCROLL_BAR
5241 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))) 5283 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
5242 ? (XFIXNUM (x) - window_box_left (w, TEXT_AREA)) 5284 ? (mx - window_box_left (w, TEXT_AREA))
5243 : 0; 5285 : 0;
5244 int y2 = wy; 5286 int y2 = wy;
5245 5287
@@ -5291,17 +5333,17 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
5291 make_fixnum (row)), 5333 make_fixnum (row)),
5292 extra_info))); 5334 extra_info)));
5293 } 5335 }
5294
5295 else if (f) 5336 else if (f)
5296 { 5337 {
5297 /* Return mouse pixel coordinates here. */ 5338 /* Return mouse pixel coordinates here. */
5298 XSETFRAME (window_or_frame, f); 5339 XSETFRAME (window_or_frame, f);
5299 xret = XFIXNUM (x); 5340 xret = mx;
5300 yret = XFIXNUM (y); 5341 yret = my;
5301 5342
5302#ifdef HAVE_WINDOW_SYSTEM 5343#ifdef HAVE_WINDOW_SYSTEM
5303 if (FRAME_WINDOW_P (f) 5344 if (FRAME_WINDOW_P (f)
5304 && FRAME_LIVE_P (f) 5345 && FRAME_LIVE_P (f)
5346 && NILP (posn)
5305 && FRAME_INTERNAL_BORDER_WIDTH (f) > 0 5347 && FRAME_INTERNAL_BORDER_WIDTH (f) > 0
5306 && !NILP (get_frame_param (f, Qdrag_internal_border))) 5348 && !NILP (get_frame_param (f, Qdrag_internal_border)))
5307 { 5349 {
@@ -5650,6 +5692,11 @@ make_lispy_event (struct input_event *event)
5650 5692
5651 position = make_lispy_position (f, event->x, event->y, 5693 position = make_lispy_position (f, event->x, event->y,
5652 event->timestamp); 5694 event->timestamp);
5695
5696 /* For tab-bar clicks, add the propertized string with
5697 button information as OBJECT member of POSITION. */
5698 if (CONSP (event->arg) && EQ (XCAR (event->arg), Qtab_bar))
5699 position = nconc2 (position, Fcons (XCDR (event->arg), Qnil));
5653 } 5700 }
5654#ifndef USE_TOOLKIT_SCROLL_BARS 5701#ifndef USE_TOOLKIT_SCROLL_BARS
5655 else 5702 else
@@ -6079,23 +6126,20 @@ make_lispy_event (struct input_event *event)
6079 6126
6080#ifdef HAVE_DBUS 6127#ifdef HAVE_DBUS
6081 case DBUS_EVENT: 6128 case DBUS_EVENT:
6082 { 6129 return Fcons (Qdbus_event, event->arg);
6083 return Fcons (Qdbus_event, event->arg);
6084 }
6085#endif /* HAVE_DBUS */ 6130#endif /* HAVE_DBUS */
6086 6131
6087#ifdef THREADS_ENABLED 6132#ifdef THREADS_ENABLED
6088 case THREAD_EVENT: 6133 case THREAD_EVENT:
6089 { 6134 return Fcons (Qthread_event, event->arg);
6090 return Fcons (Qthread_event, event->arg);
6091 }
6092#endif /* THREADS_ENABLED */ 6135#endif /* THREADS_ENABLED */
6093 6136
6094#ifdef HAVE_XWIDGETS 6137#ifdef HAVE_XWIDGETS
6095 case XWIDGET_EVENT: 6138 case XWIDGET_EVENT:
6096 { 6139 return Fcons (Qxwidget_event, event->arg);
6097 return Fcons (Qxwidget_event, event->arg); 6140
6098 } 6141 case XWIDGET_DISPLAY_EVENT:
6142 return list2 (Qxwidget_display_event, event->arg);
6099#endif 6143#endif
6100 6144
6101#ifdef USE_FILE_NOTIFY 6145#ifdef USE_FILE_NOTIFY
@@ -7796,7 +7840,9 @@ parse_menu_item (Lisp_Object item, int inmenubar)
7796 else if (EQ (tem, QCkeys)) 7840 else if (EQ (tem, QCkeys))
7797 { 7841 {
7798 tem = XCAR (item); 7842 tem = XCAR (item);
7799 if (CONSP (tem) || STRINGP (tem)) 7843 if (FUNCTIONP (tem))
7844 ASET (item_properties, ITEM_PROPERTY_KEYEQ, call0 (tem));
7845 else if (CONSP (tem) || STRINGP (tem))
7800 ASET (item_properties, ITEM_PROPERTY_KEYEQ, tem); 7846 ASET (item_properties, ITEM_PROPERTY_KEYEQ, tem);
7801 } 7847 }
7802 else if (EQ (tem, QCbutton) && CONSP (XCAR (item))) 7848 else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
@@ -9193,8 +9239,7 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt,
9193 /* If the function returned something invalid, 9239 /* If the function returned something invalid,
9194 barf--don't ignore it. */ 9240 barf--don't ignore it. */
9195 if (! (NILP (next) || VECTORP (next) || STRINGP (next))) 9241 if (! (NILP (next) || VECTORP (next) || STRINGP (next)))
9196 error ("Function %s returns invalid key sequence", 9242 signal_error ("Function returns invalid key sequence", tem);
9197 SSDATA (SYMBOL_NAME (tem)));
9198 } 9243 }
9199 return next; 9244 return next;
9200} 9245}
@@ -10125,7 +10170,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
10125 use the corresponding lower-case letter instead. */ 10170 use the corresponding lower-case letter instead. */
10126 if (NILP (current_binding) 10171 if (NILP (current_binding)
10127 && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t 10172 && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
10128 && FIXNUMP (key)) 10173 && FIXNUMP (key)
10174 && translate_upper_case_key_bindings)
10129 { 10175 {
10130 Lisp_Object new_key; 10176 Lisp_Object new_key;
10131 EMACS_INT k = XFIXNUM (key); 10177 EMACS_INT k = XFIXNUM (key);
@@ -10177,12 +10223,14 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
10177 int modifiers 10223 int modifiers
10178 = CONSP (breakdown) ? (XFIXNUM (XCAR (XCDR (breakdown)))) : 0; 10224 = CONSP (breakdown) ? (XFIXNUM (XCAR (XCDR (breakdown)))) : 0;
10179 10225
10180 if (modifiers & shift_modifier 10226 if (translate_upper_case_key_bindings
10181 /* Treat uppercase keys as shifted. */ 10227 && (modifiers & shift_modifier
10182 || (FIXNUMP (key) 10228 /* Treat uppercase keys as shifted. */
10183 && (KEY_TO_CHAR (key) 10229 || (FIXNUMP (key)
10184 < XCHAR_TABLE (BVAR (current_buffer, downcase_table))->header.size) 10230 && (KEY_TO_CHAR (key)
10185 && uppercasep (KEY_TO_CHAR (key)))) 10231 < XCHAR_TABLE (BVAR (current_buffer,
10232 downcase_table))->header.size)
10233 && uppercasep (KEY_TO_CHAR (key)))))
10186 { 10234 {
10187 Lisp_Object new_key 10235 Lisp_Object new_key
10188 = (modifiers & shift_modifier 10236 = (modifiers & shift_modifier
@@ -11289,6 +11337,8 @@ The elements of this list correspond to the arguments of
11289DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0, 11337DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
11290 doc: /* Return position information for pixel coordinates X and Y. 11338 doc: /* Return position information for pixel coordinates X and Y.
11291By default, X and Y are relative to text area of the selected window. 11339By default, X and Y are relative to text area of the selected window.
11340Note that the text area includes the header-line and the tab-line of
11341the window, if any of them are present.
11292Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window. 11342Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window.
11293If optional fourth arg WHOLE is non-nil, X is relative to the left 11343If optional fourth arg WHOLE is non-nil, X is relative to the left
11294edge of the window. 11344edge of the window.
@@ -11556,6 +11606,52 @@ static const struct event_head head_table[] = {
11556 {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)} 11606 {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)}
11557}; 11607};
11558 11608
11609static Lisp_Object
11610init_while_no_input_ignore_events (void)
11611{
11612 Lisp_Object events = listn (9, Qselect_window, Qhelp_echo, Qmove_frame,
11613 Qiconify_frame, Qmake_frame_visible,
11614 Qfocus_in, Qfocus_out, Qconfig_changed_event,
11615 Qselection_request);
11616
11617#ifdef HAVE_DBUS
11618 events = Fcons (Qdbus_event, events);
11619#endif
11620#ifdef USE_FILE_NOTIFY
11621 events = Fcons (Qfile_notify, events);
11622#endif
11623#ifdef THREADS_ENABLED
11624 events = Fcons (Qthread_event, events);
11625#endif
11626
11627 return events;
11628}
11629
11630static bool
11631is_ignored_event (union buffered_input_event *event)
11632{
11633 Lisp_Object ignore_event;
11634
11635 switch (event->kind)
11636 {
11637 case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break;
11638 case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break;
11639 case HELP_EVENT: ignore_event = Qhelp_echo; break;
11640 case ICONIFY_EVENT: ignore_event = Qiconify_frame; break;
11641 case DEICONIFY_EVENT: ignore_event = Qmake_frame_visible; break;
11642 case SELECTION_REQUEST_EVENT: ignore_event = Qselection_request; break;
11643#ifdef USE_FILE_NOTIFY
11644 case FILE_NOTIFY_EVENT: ignore_event = Qfile_notify; break;
11645#endif
11646#ifdef HAVE_DBUS
11647 case DBUS_EVENT: ignore_event = Qdbus_event; break;
11648#endif
11649 default: ignore_event = Qnil; break;
11650 }
11651
11652 return !NILP (Fmemq (ignore_event, Vwhile_no_input_ignore_events));
11653}
11654
11559static void syms_of_keyboard_for_pdumper (void); 11655static void syms_of_keyboard_for_pdumper (void);
11560 11656
11561void 11657void
@@ -11642,6 +11738,7 @@ syms_of_keyboard (void)
11642 11738
11643#ifdef HAVE_XWIDGETS 11739#ifdef HAVE_XWIDGETS
11644 DEFSYM (Qxwidget_event, "xwidget-event"); 11740 DEFSYM (Qxwidget_event, "xwidget-event");
11741 DEFSYM (Qxwidget_display_event, "xwidget-display-event");
11645#endif 11742#endif
11646 11743
11647#ifdef USE_FILE_NOTIFY 11744#ifdef USE_FILE_NOTIFY
@@ -12450,7 +12547,29 @@ If nil, Emacs crashes immediately in response to fatal signals. */);
12450 12547
12451 DEFVAR_LISP ("while-no-input-ignore-events", 12548 DEFVAR_LISP ("while-no-input-ignore-events",
12452 Vwhile_no_input_ignore_events, 12549 Vwhile_no_input_ignore_events,
12453 doc: /* Ignored events from while-no-input. */); 12550 doc: /* Ignored events from `while-no-input'.
12551Events in this list do not count as pending input while running
12552`while-no-input' and do not cause any idle timers to get reset when they
12553occur. */);
12554 Vwhile_no_input_ignore_events = init_while_no_input_ignore_events ();
12555
12556 DEFVAR_BOOL ("translate-upper-case-key-bindings",
12557 translate_upper_case_key_bindings,
12558 doc: /* If non-nil, interpret upper case keys as lower case (when applicable).
12559Emacs allows binding both upper and lower case key sequences to
12560commands. However, if there is a lower case key sequence bound to a
12561command, and the user enters an upper case key sequence that is not
12562bound to a command, Emacs will use the lower case binding. Setting
12563this variable to nil inhibits this behaviour. */);
12564 translate_upper_case_key_bindings = true;
12565
12566 DEFVAR_BOOL ("input-pending-p-filter-events",
12567 input_pending_p_filter_events,
12568 doc: /* If non-nil, `input-pending-p' ignores some input events.
12569If this variable is non-nil (the default), `input-pending-p' and
12570other similar functions ignore input events in `while-no-input-ignore-events'.
12571This flag may eventually be removed once this behavior is deemed safe. */);
12572 input_pending_p_filter_events = true;
12454 12573
12455 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper); 12574 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
12456} 12575}
diff --git a/src/keyboard.h b/src/keyboard.h
index 8bdffaa2bff..21c51ec3862 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -491,7 +491,7 @@ extern void process_pending_signals (void);
491extern struct timespec timer_check (void); 491extern struct timespec timer_check (void);
492extern void mark_kboards (void); 492extern void mark_kboards (void);
493 493
494#ifdef HAVE_NTGUI 494#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS
495extern const char *const lispy_function_keys[]; 495extern const char *const lispy_function_keys[];
496#endif 496#endif
497 497
diff --git a/src/keymap.c b/src/keymap.c
index fb8eceaec18..29d2ca7ab7e 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -65,6 +65,9 @@ static Lisp_Object exclude_keys;
65/* Pre-allocated 2-element vector for Fcommand_remapping to use. */ 65/* Pre-allocated 2-element vector for Fcommand_remapping to use. */
66static Lisp_Object command_remapping_vector; 66static Lisp_Object command_remapping_vector;
67 67
68/* Char table for the backwards-compatibility part in Flookup_key. */
69static Lisp_Object unicode_case_table;
70
68/* Hash table used to cache a reverse-map to speed up calls to where-is. */ 71/* Hash table used to cache a reverse-map to speed up calls to where-is. */
69static Lisp_Object where_is_cache; 72static Lisp_Object where_is_cache;
70/* Which keymaps are reverse-stored in the cache. */ 73/* Which keymaps are reverse-stored in the cache. */
@@ -629,6 +632,9 @@ the definition it is bound to. The event may be a character range.
629If KEYMAP has a parent, the parent's bindings are included as well. 632If KEYMAP has a parent, the parent's bindings are included as well.
630This works recursively: if the parent has itself a parent, then the 633This works recursively: if the parent has itself a parent, then the
631grandparent's bindings are also included and so on. 634grandparent's bindings are also included and so on.
635
636For more information, see Info node `(elisp) Keymaps'.
637
632usage: (map-keymap FUNCTION KEYMAP) */) 638usage: (map-keymap FUNCTION KEYMAP) */)
633 (Lisp_Object function, Lisp_Object keymap, Lisp_Object sort_first) 639 (Lisp_Object function, Lisp_Object keymap, Lisp_Object sort_first)
634{ 640{
@@ -1024,6 +1030,28 @@ is not copied. */)
1024 1030
1025/* Simple Keymap mutators and accessors. */ 1031/* Simple Keymap mutators and accessors. */
1026 1032
1033static Lisp_Object
1034possibly_translate_key_sequence (Lisp_Object key, ptrdiff_t *length)
1035{
1036 if (VECTORP (key) && ASIZE (key) == 1 && STRINGP (AREF (key, 0)))
1037 {
1038 /* KEY is on the ["C-c"] format, so translate to internal
1039 format. */
1040 if (NILP (Ffboundp (Qkbd_valid_p)))
1041 xsignal2 (Qerror,
1042 build_string ("`kbd-valid-p' is not defined, so this syntax can't be used: %s"),
1043 key);
1044 if (NILP (call1 (Qkbd_valid_p, AREF (key, 0))))
1045 xsignal2 (Qerror, build_string ("Invalid `kbd' syntax: %S"), key);
1046 key = call1 (Qkbd, AREF (key, 0));
1047 *length = CHECK_VECTOR_OR_STRING (key);
1048 if (*length == 0)
1049 xsignal2 (Qerror, build_string ("Invalid `kbd' syntax: %S"), key);
1050 }
1051
1052 return key;
1053}
1054
1027/* GC is possible in this function if it autoloads a keymap. */ 1055/* GC is possible in this function if it autoloads a keymap. */
1028 1056
1029DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0, 1057DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
@@ -1047,7 +1075,9 @@ DEF is anything that can be a key's definition:
1047 function definition, which should at that time be one of the above, 1075 function definition, which should at that time be one of the above,
1048 or another symbol whose function definition is used, etc.), 1076 or another symbol whose function definition is used, etc.),
1049 a cons (STRING . DEFN), meaning that DEFN is the definition 1077 a cons (STRING . DEFN), meaning that DEFN is the definition
1050 (DEFN should be a valid definition in its own right), 1078 (DEFN should be a valid definition in its own right) and
1079 STRING is the menu item name (which is used only if the containing
1080 keymap has been created with a menu name, see `make-keymap'),
1051 or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP, 1081 or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
1052 or an extended menu item definition. 1082 or an extended menu item definition.
1053 (See info node `(elisp)Extended Menu Items'.) 1083 (See info node `(elisp)Extended Menu Items'.)
@@ -1082,6 +1112,8 @@ binding KEY to DEF is added at the front of KEYMAP. */)
1082 def = tmp; 1112 def = tmp;
1083 } 1113 }
1084 1114
1115 key = possibly_translate_key_sequence (key, &length);
1116
1085 ptrdiff_t idx = 0; 1117 ptrdiff_t idx = 0;
1086 while (1) 1118 while (1)
1087 { 1119 {
@@ -1180,27 +1212,8 @@ remapping in all currently active keymaps. */)
1180 return FIXNUMP (command) ? Qnil : command; 1212 return FIXNUMP (command) ? Qnil : command;
1181} 1213}
1182 1214
1183/* Value is number if KEY is too long; nil if valid but has no definition. */ 1215static Lisp_Object
1184/* GC is possible in this function. */ 1216lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
1185
1186DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
1187 doc: /* Look up key sequence KEY in KEYMAP. Return the definition.
1188A value of nil means undefined. See doc of `define-key'
1189for kinds of definitions.
1190
1191A number as value means KEY is "too long";
1192that is, characters or symbols in it except for the last one
1193fail to be a valid sequence of prefix characters in KEYMAP.
1194The number is how many characters at the front of KEY
1195it takes to reach a non-prefix key.
1196KEYMAP can also be a list of keymaps.
1197
1198Normally, `lookup-key' ignores bindings for t, which act as default
1199bindings, used when nothing else in the keymap applies; this makes it
1200usable as a general function for probing keymaps. However, if the
1201third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
1202recognize the default bindings, just as `read-key-sequence' does. */)
1203 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
1204{ 1217{
1205 bool t_ok = !NILP (accept_default); 1218 bool t_ok = !NILP (accept_default);
1206 1219
@@ -1211,6 +1224,8 @@ recognize the default bindings, just as `read-key-sequence' does. */)
1211 if (length == 0) 1224 if (length == 0)
1212 return keymap; 1225 return keymap;
1213 1226
1227 key = possibly_translate_key_sequence (key, &length);
1228
1214 ptrdiff_t idx = 0; 1229 ptrdiff_t idx = 0;
1215 while (1) 1230 while (1)
1216 { 1231 {
@@ -1240,6 +1255,156 @@ recognize the default bindings, just as `read-key-sequence' does. */)
1240 } 1255 }
1241} 1256}
1242 1257
1258/* Value is number if KEY is too long; nil if valid but has no definition. */
1259/* GC is possible in this function. */
1260
1261DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
1262 doc: /* Look up key sequence KEY in KEYMAP. Return the definition.
1263A value of nil means undefined. See doc of `define-key'
1264for kinds of definitions.
1265
1266A number as value means KEY is "too long";
1267that is, characters or symbols in it except for the last one
1268fail to be a valid sequence of prefix characters in KEYMAP.
1269The number is how many characters at the front of KEY
1270it takes to reach a non-prefix key.
1271KEYMAP can also be a list of keymaps.
1272
1273Normally, `lookup-key' ignores bindings for t, which act as default
1274bindings, used when nothing else in the keymap applies; this makes it
1275usable as a general function for probing keymaps. However, if the
1276third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
1277recognize the default bindings, just as `read-key-sequence' does. */)
1278 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
1279{
1280 Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
1281 if (!NILP (found) && !NUMBERP (found))
1282 return found;
1283
1284 /* Menu definitions might use mixed case symbols (notably in old
1285 versions of `easy-menu-define'), or use " " instead of "-".
1286 The rest of this function is about accepting these variations for
1287 backwards-compatibility. (Bug#50752) */
1288
1289 /* Just skip everything below unless this is a menu item. */
1290 if (!VECTORP (key) || !(ASIZE (key) > 0)
1291 || !EQ (AREF (key, 0), Qmenu_bar))
1292 return found;
1293
1294 /* Initialize the unicode case table, if it wasn't already. */
1295 if (NILP (unicode_case_table))
1296 {
1297 unicode_case_table = uniprop_table (intern ("lowercase"));
1298 /* uni-lowercase.el might be unavailable during bootstrap. */
1299 if (NILP (unicode_case_table))
1300 return found;
1301 staticpro (&unicode_case_table);
1302 }
1303
1304 ptrdiff_t key_len = ASIZE (key);
1305 Lisp_Object new_key = make_vector (key_len, Qnil);
1306
1307 /* Try both the Unicode case table, and the buffer local one.
1308 Otherwise, we will fail for e.g. the "Turkish" language
1309 environment where 'I' does not downcase to 'i'. */
1310 Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()};
1311 for (int tbl_num = 0; tbl_num < 2; tbl_num++)
1312 {
1313 /* First, let's try converting all symbols like "Foo-Bar-Baz" to
1314 "foo-bar-baz". */
1315 for (int i = 0; i < key_len; i++)
1316 {
1317 Lisp_Object item = AREF (key, i);
1318 if (!SYMBOLP (item))
1319 ASET (new_key, i, item);
1320 else
1321 {
1322 Lisp_Object key_item = Fsymbol_name (item);
1323 Lisp_Object new_item;
1324 if (!STRING_MULTIBYTE (key_item))
1325 new_item = Fdowncase (key_item);
1326 else
1327 {
1328 USE_SAFE_ALLOCA;
1329 ptrdiff_t size = SCHARS (key_item), n;
1330 if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
1331 n = PTRDIFF_MAX;
1332 unsigned char *dst = SAFE_ALLOCA (n);
1333 unsigned char *p = dst;
1334 ptrdiff_t j_char = 0, j_byte = 0;
1335
1336 while (j_char < size)
1337 {
1338 int ch = fetch_string_char_advance (key_item,
1339 &j_char, &j_byte);
1340 Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num],
1341 ch);
1342 if (!NILP (ch_conv))
1343 CHAR_STRING (XFIXNUM (ch_conv), p);
1344 else
1345 CHAR_STRING (ch, p);
1346 p = dst + j_byte;
1347 }
1348 new_item = make_multibyte_string ((char *) dst,
1349 SCHARS (key_item),
1350 SBYTES (key_item));
1351 SAFE_FREE ();
1352 }
1353 ASET (new_key, i, Fintern (new_item, Qnil));
1354 }
1355 }
1356
1357 /* Check for match. */
1358 found = lookup_key_1 (keymap, new_key, accept_default);
1359 if (!NILP (found) && !NUMBERP (found))
1360 break;
1361
1362 /* If we still don't have a match, let's convert any spaces in
1363 our lowercased string into dashes, e.g. "foo bar baz" to
1364 "foo-bar-baz". */
1365 for (int i = 0; i < key_len; i++)
1366 {
1367 if (!SYMBOLP (AREF (new_key, i)))
1368 continue;
1369
1370 Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
1371
1372 /* If there are no spaces in this symbol, just skip it. */
1373 if (!strstr (SSDATA (lc_key), " "))
1374 continue;
1375
1376 USE_SAFE_ALLOCA;
1377 ptrdiff_t size = SCHARS (lc_key), n;
1378 if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
1379 n = PTRDIFF_MAX;
1380 unsigned char *dst = SAFE_ALLOCA (n);
1381
1382 /* We can walk the string data byte by byte, because UTF-8
1383 encoding ensures that no other byte of any multibyte
1384 sequence will ever include a 7-bit byte equal to an ASCII
1385 single-byte character. */
1386 memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
1387 for (int i = 0; i < SBYTES (lc_key); ++i)
1388 {
1389 if (dst[i] == ' ')
1390 dst[i] = '-';
1391 }
1392 Lisp_Object new_it =
1393 make_multibyte_string ((char *) dst,
1394 SCHARS (lc_key), SBYTES (lc_key));
1395 ASET (new_key, i, Fintern (new_it, Qnil));
1396 SAFE_FREE ();
1397 }
1398
1399 /* Check for match. */
1400 found = lookup_key_1 (keymap, new_key, accept_default);
1401 if (!NILP (found) && !NUMBERP (found))
1402 break;
1403 }
1404
1405 return found;
1406}
1407
1243/* Make KEYMAP define event C as a keymap (i.e., as a prefix). 1408/* Make KEYMAP define event C as a keymap (i.e., as a prefix).
1244 Assume that currently it does not define C at all. 1409 Assume that currently it does not define C at all.
1245 Return the keymap. */ 1410 Return the keymap. */
@@ -2768,7 +2933,10 @@ You type Translation\n\
2768 { 2933 {
2769 if (EQ (start1, BVAR (XBUFFER (buffer), keymap))) 2934 if (EQ (start1, BVAR (XBUFFER (buffer), keymap)))
2770 { 2935 {
2771 Lisp_Object msg = build_unibyte_string ("\f\nMajor Mode Bindings"); 2936 Lisp_Object msg =
2937 CALLN (Fformat,
2938 build_unibyte_string ("\f\n`%s' Major Mode Bindings"),
2939 XBUFFER (buffer)->major_mode_);
2772 CALLN (Ffuncall, 2940 CALLN (Ffuncall,
2773 Qdescribe_map_tree, 2941 Qdescribe_map_tree,
2774 start1, Qt, shadow, prefix, 2942 start1, Qt, shadow, prefix,
@@ -2935,7 +3103,7 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
2935 Lisp_Object suppress = Qnil; 3103 Lisp_Object suppress = Qnil;
2936 bool first = true; 3104 bool first = true;
2937 /* Range of elements to be handled. */ 3105 /* Range of elements to be handled. */
2938 int from, to, stop; 3106 int to, stop;
2939 3107
2940 if (!keymap_p) 3108 if (!keymap_p)
2941 { 3109 {
@@ -2955,17 +3123,19 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
2955 if (partial) 3123 if (partial)
2956 suppress = intern ("suppress-keymap"); 3124 suppress = intern ("suppress-keymap");
2957 3125
2958 from = 0; 3126 /* STOP is a boundary between normal characters (-#x3FFF7F) and
3127 8-bit characters (#x3FFF80-), used below when VECTOR is a
3128 char-table. */
2959 if (CHAR_TABLE_P (vector)) 3129 if (CHAR_TABLE_P (vector))
2960 stop = MAX_5_BYTE_CHAR + 1, to = MAX_CHAR + 1; 3130 stop = MAX_5_BYTE_CHAR + 1, to = MAX_CHAR + 1;
2961 else 3131 else
2962 stop = to = ASIZE (vector); 3132 stop = to = ASIZE (vector);
2963 3133
2964 for (int i = from; ; i++) 3134 for (int i = 0; ; i++)
2965 { 3135 {
2966 bool this_shadowed = false; 3136 bool this_shadowed = false;
2967 Lisp_Object shadowed_by = Qnil; 3137 Lisp_Object shadowed_by = Qnil;
2968 int range_beg, range_end; 3138 int range_beg;
2969 Lisp_Object val, tem2; 3139 Lisp_Object val, tem2;
2970 3140
2971 maybe_quit (); 3141 maybe_quit ();
@@ -2981,6 +3151,10 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
2981 3151
2982 if (CHAR_TABLE_P (vector)) 3152 if (CHAR_TABLE_P (vector))
2983 { 3153 {
3154 /* Find the value in VECTOR for the first character in the
3155 range [RANGE_BEG..STOP), and update the range to include
3156 only the characters whose value is the same as that of
3157 the first in the range. */
2984 range_beg = i; 3158 range_beg = i;
2985 i = stop - 1; 3159 i = stop - 1;
2986 val = char_table_ref_and_range (vector, range_beg, &range_beg, &i); 3160 val = char_table_ref_and_range (vector, range_beg, &range_beg, &i);
@@ -3039,33 +3213,26 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
3039 insert1 (describe_key_maybe_fontify (kludge, prefix, keymap_p)); 3213 insert1 (describe_key_maybe_fontify (kludge, prefix, keymap_p));
3040 3214
3041 /* Find all consecutive characters or rows that have the same 3215 /* Find all consecutive characters or rows that have the same
3042 definition. But, if VECTOR is a char-table, we had better 3216 definition. */
3043 put a boundary between normal characters (-#x3FFF7F) and 3217 if (!CHAR_TABLE_P (vector))
3044 8-bit characters (#x3FFF80-). */
3045 if (CHAR_TABLE_P (vector))
3046 { 3218 {
3047 while (i + 1 < stop 3219 while (i + 1 < stop
3048 && (range_beg = i + 1, range_end = stop - 1, 3220 && (tem2 = get_keyelt (AREF (vector, i + 1), 0),
3049 val = char_table_ref_and_range (vector, range_beg, 3221 !NILP (tem2))
3050 &range_beg, &range_end),
3051 tem2 = get_keyelt (val, 0),
3052 !NILP (tem2))
3053 && !NILP (Fequal (tem2, definition))) 3222 && !NILP (Fequal (tem2, definition)))
3054 i = range_end; 3223 i++;
3055 } 3224 }
3056 else
3057 while (i + 1 < stop
3058 && (tem2 = get_keyelt (AREF (vector, i + 1), 0),
3059 !NILP (tem2))
3060 && !NILP (Fequal (tem2, definition)))
3061 i++;
3062 3225
3063 /* Make sure found consecutive keys are either not shadowed or, 3226 /* Make sure found consecutive keys are either not shadowed or,
3064 if they are, that they are shadowed by the same command. */ 3227 if they are, that they are shadowed by the same command. */
3065 if (CHAR_TABLE_P (vector) && i != starting_i) 3228 if (!NILP (Vdescribe_bindings_check_shadowing_in_ranges)
3229 && CHAR_TABLE_P (vector) && i != starting_i
3230 && (!EQ (Vdescribe_bindings_check_shadowing_in_ranges,
3231 Qignore_self_insert)
3232 || !EQ (definition, Qself_insert_command)))
3066 { 3233 {
3067 Lisp_Object key = make_nil_vector (1); 3234 Lisp_Object key = make_nil_vector (1);
3068 for (int j = starting_i + 1; j <= i; j++) 3235 for (int j = range_beg + 1; j <= i; j++)
3069 { 3236 {
3070 ASET (key, 0, make_fixnum (j)); 3237 ASET (key, 0, make_fixnum (j));
3071 Lisp_Object tem = shadow_lookup (shadow, key, Qt, 0); 3238 Lisp_Object tem = shadow_lookup (shadow, key, Qt, 0);
@@ -3181,6 +3348,24 @@ be preferred. */);
3181 Vwhere_is_preferred_modifier = Qnil; 3348 Vwhere_is_preferred_modifier = Qnil;
3182 where_is_preferred_modifier = 0; 3349 where_is_preferred_modifier = 0;
3183 3350
3351 DEFVAR_LISP ("describe-bindings-check-shadowing-in-ranges",
3352 Vdescribe_bindings_check_shadowing_in_ranges,
3353 doc: /* If non-nil, consider command shadowing when describing ranges of keys.
3354If the value is t, describing bindings of consecutive keys will not
3355report them as a single range if they are shadowed by different
3356minor-mode commands.
3357If the value is `ignore-self-insert', assume that consecutive keys
3358bound to `self-insert-command' are not all shadowed; this speeds up
3359commands such as \\[describe-bindings] and \\[describe-mode], but could miss some shadowing.
3360Any other non-nil value is treated is t.
3361
3362Beware: setting this non-nil could potentially slow down commands
3363that describe key bindings. That is why the default is nil. */);
3364 Vdescribe_bindings_check_shadowing_in_ranges = Qnil;
3365
3366 DEFSYM (Qself_insert_command, "self-insert-command");
3367 DEFSYM (Qignore_self_insert, "ignore-self-insert");
3368
3184 DEFSYM (Qmenu_bar, "menu-bar"); 3369 DEFSYM (Qmenu_bar, "menu-bar");
3185 DEFSYM (Qmode_line, "mode-line"); 3370 DEFSYM (Qmode_line, "mode-line");
3186 3371
@@ -3244,4 +3429,7 @@ be preferred. */);
3244 defsubr (&Stext_char_description); 3429 defsubr (&Stext_char_description);
3245 defsubr (&Swhere_is_internal); 3430 defsubr (&Swhere_is_internal);
3246 defsubr (&Sdescribe_buffer_bindings); 3431 defsubr (&Sdescribe_buffer_bindings);
3432
3433 DEFSYM (Qkbd, "kbd");
3434 DEFSYM (Qkbd_valid_p, "kbd-valid-p");
3247} 3435}
diff --git a/src/lisp.h b/src/lisp.h
index 15a42a44562..31656bb3b1c 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1555,6 +1555,14 @@ STRING_MULTIBYTE (Lisp_Object str)
1555 1555
1556/* Convenience functions for dealing with Lisp strings. */ 1556/* Convenience functions for dealing with Lisp strings. */
1557 1557
1558/* WARNING: Use the 'char *' pointers to string data with care in code
1559 that could GC: GC can relocate string data, invalidating such
1560 pointers. It is best to use string character or byte index
1561 instead, delaying the access through SDATA/SSDATA pointers to the
1562 latest possible moment. If you must use the 'char *' pointers
1563 (e.g., for speed), be sure to adjust them after any call that could
1564 potentially GC. */
1565
1558INLINE unsigned char * 1566INLINE unsigned char *
1559SDATA (Lisp_Object string) 1567SDATA (Lisp_Object string)
1560{ 1568{
@@ -1615,6 +1623,13 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize)
1615 XSTRING (string)->u.s.size = newsize; 1623 XSTRING (string)->u.s.size = newsize;
1616} 1624}
1617 1625
1626INLINE void
1627CHECK_STRING_NULL_BYTES (Lisp_Object string)
1628{
1629 CHECK_TYPE (memchr (SSDATA (string), '\0', SBYTES (string)) == NULL,
1630 Qfilenamep, string);
1631}
1632
1618/* A regular vector is just a header plus an array of Lisp_Objects. */ 1633/* A regular vector is just a header plus an array of Lisp_Objects. */
1619 1634
1620struct Lisp_Vector 1635struct Lisp_Vector
@@ -2812,9 +2827,8 @@ enum Lisp_Compiled
2812 }; 2827 };
2813 2828
2814/* Flag bits in a character. These also get used in termhooks.h. 2829/* Flag bits in a character. These also get used in termhooks.h.
2815 Richard Stallman <rms@gnu.ai.mit.edu> thinks that MULE 2830 Emacs needs 22 bits for the character value itself, see MAX_CHAR,
2816 (MUlti-Lingual Emacs) might need 22 bits for the character value 2831 so we shouldn't use any bits lower than 0x0400000. */
2817 itself, so we probably shouldn't use any bits lower than 0x0400000. */
2818enum char_bits 2832enum char_bits
2819 { 2833 {
2820 CHAR_ALT = 0x0400000, 2834 CHAR_ALT = 0x0400000,
@@ -3717,7 +3731,8 @@ extern void adjust_markers_for_delete (ptrdiff_t, ptrdiff_t,
3717 ptrdiff_t, ptrdiff_t); 3731 ptrdiff_t, ptrdiff_t);
3718extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t, 3732extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t,
3719 ptrdiff_t, ptrdiff_t, int); 3733 ptrdiff_t, ptrdiff_t, int);
3720extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool, bool); 3734extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool,
3735 bool, bool, bool);
3721extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, 3736extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
3722 const char *, ptrdiff_t, ptrdiff_t, bool); 3737 const char *, ptrdiff_t, ptrdiff_t, bool);
3723extern void syms_of_insdel (void); 3738extern void syms_of_insdel (void);
@@ -3932,7 +3947,8 @@ build_string (const char *str)
3932 3947
3933extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object); 3948extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
3934extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object); 3949extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
3935extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t); 3950extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t)
3951 ATTRIBUTE_RETURNS_NONNULL;
3936 3952
3937/* Make an uninitialized vector for SIZE objects. NOTE: you must 3953/* Make an uninitialized vector for SIZE objects. NOTE: you must
3938 be sure that GC cannot happen until the vector is completely 3954 be sure that GC cannot happen until the vector is completely
@@ -3945,7 +3961,8 @@ extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
3945 3961
3946 allocate_vector has a similar problem. */ 3962 allocate_vector has a similar problem. */
3947 3963
3948extern struct Lisp_Vector *allocate_vector (ptrdiff_t); 3964extern struct Lisp_Vector *allocate_vector (ptrdiff_t)
3965 ATTRIBUTE_RETURNS_NONNULL;
3949 3966
3950INLINE Lisp_Object 3967INLINE Lisp_Object
3951make_uninit_vector (ptrdiff_t size) 3968make_uninit_vector (ptrdiff_t size)
@@ -3977,7 +3994,8 @@ make_nil_vector (ptrdiff_t size)
3977} 3994}
3978 3995
3979extern struct Lisp_Vector *allocate_pseudovector (int, int, int, 3996extern struct Lisp_Vector *allocate_pseudovector (int, int, int,
3980 enum pvec_type); 3997 enum pvec_type)
3998 ATTRIBUTE_RETURNS_NONNULL;
3981 3999
3982/* Allocate uninitialized pseudovector with no Lisp_Object slots. */ 4000/* Allocate uninitialized pseudovector with no Lisp_Object slots. */
3983 4001
@@ -4009,7 +4027,7 @@ extern void free_cons (struct Lisp_Cons *);
4009extern void init_alloc_once (void); 4027extern void init_alloc_once (void);
4010extern void init_alloc (void); 4028extern void init_alloc (void);
4011extern void syms_of_alloc (void); 4029extern void syms_of_alloc (void);
4012extern struct buffer * allocate_buffer (void); 4030extern struct buffer *allocate_buffer (void) ATTRIBUTE_RETURNS_NONNULL;
4013extern int valid_lisp_object_p (Lisp_Object); 4031extern int valid_lisp_object_p (Lisp_Object);
4014 4032
4015/* Defined in gmalloc.c. */ 4033/* Defined in gmalloc.c. */
@@ -4112,7 +4130,6 @@ intern_c_string (const char *str)
4112} 4130}
4113 4131
4114/* Defined in eval.c. */ 4132/* Defined in eval.c. */
4115extern EMACS_INT minibuffer_quit_level;
4116extern Lisp_Object Vautoload_queue; 4133extern Lisp_Object Vautoload_queue;
4117extern Lisp_Object Vrun_hooks; 4134extern Lisp_Object Vrun_hooks;
4118extern Lisp_Object Vsignaling_function; 4135extern Lisp_Object Vsignaling_function;
@@ -4168,7 +4185,8 @@ extern Lisp_Object internal_condition_case_n
4168 (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, 4185 (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *,
4169 Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); 4186 Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *));
4170extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object)); 4187extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object));
4171extern struct handler *push_handler (Lisp_Object, enum handlertype); 4188extern struct handler *push_handler (Lisp_Object, enum handlertype)
4189 ATTRIBUTE_RETURNS_NONNULL;
4172extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); 4190extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype);
4173extern void specbind (Lisp_Object, Lisp_Object); 4191extern void specbind (Lisp_Object, Lisp_Object);
4174extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object); 4192extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object);
@@ -4309,9 +4327,10 @@ extern void syms_of_marker (void);
4309 4327
4310/* Defined in fileio.c. */ 4328/* Defined in fileio.c. */
4311 4329
4312extern char *splice_dir_file (char *, char const *, char const *); 4330extern char *splice_dir_file (char *, char const *, char const *)
4331 ATTRIBUTE_RETURNS_NONNULL;
4313extern bool file_name_absolute_p (const char *); 4332extern bool file_name_absolute_p (const char *);
4314extern char const *get_homedir (void); 4333extern char const *get_homedir (void) ATTRIBUTE_RETURNS_NONNULL;
4315extern Lisp_Object expand_and_dir_to_file (Lisp_Object); 4334extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
4316extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, 4335extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
4317 Lisp_Object, Lisp_Object, Lisp_Object, 4336 Lisp_Object, Lisp_Object, Lisp_Object,
@@ -4465,7 +4484,7 @@ INLINE void fixup_locale (void) {}
4465INLINE void synchronize_system_messages_locale (void) {} 4484INLINE void synchronize_system_messages_locale (void) {}
4466INLINE void synchronize_system_time_locale (void) {} 4485INLINE void synchronize_system_time_locale (void) {}
4467#endif 4486#endif
4468extern char *emacs_strerror (int); 4487extern char *emacs_strerror (int) ATTRIBUTE_RETURNS_NONNULL;
4469extern void shut_down_emacs (int, Lisp_Object); 4488extern void shut_down_emacs (int, Lisp_Object);
4470 4489
4471/* True means don't do interactive redisplay and don't change tty modes. */ 4490/* True means don't do interactive redisplay and don't change tty modes. */
@@ -4531,7 +4550,7 @@ extern void setup_process_coding_systems (Lisp_Object);
4531 4550
4532extern int emacs_spawn (pid_t *, int, int, int, char **, char **, 4551extern int emacs_spawn (pid_t *, int, int, int, char **, char **,
4533 const char *, const char *, const sigset_t *); 4552 const char *, const char *, const sigset_t *);
4534extern char **make_environment_block (Lisp_Object); 4553extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL;
4535extern void init_callproc_1 (void); 4554extern void init_callproc_1 (void);
4536extern void init_callproc (void); 4555extern void init_callproc (void);
4537extern void set_initial_environment (void); 4556extern void set_initial_environment (void);
@@ -4651,6 +4670,7 @@ extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
4651 4670
4652/* Defined in terminal.c. */ 4671/* Defined in terminal.c. */
4653extern void syms_of_terminal (void); 4672extern void syms_of_terminal (void);
4673extern char * tty_type_name (Lisp_Object);
4654 4674
4655/* Defined in font.c. */ 4675/* Defined in font.c. */
4656extern void syms_of_font (void); 4676extern void syms_of_font (void);
@@ -4799,17 +4819,24 @@ extern char my_edata[];
4799extern char my_endbss[]; 4819extern char my_endbss[];
4800extern char *my_endbss_static; 4820extern char *my_endbss_static;
4801 4821
4802extern void *xmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); 4822extern void *xmalloc (size_t)
4803extern void *xzalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); 4823 ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
4804extern void *xrealloc (void *, size_t) ATTRIBUTE_ALLOC_SIZE ((2)); 4824extern void *xzalloc (size_t)
4825 ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
4826extern void *xrealloc (void *, size_t)
4827 ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL;
4805extern void xfree (void *); 4828extern void xfree (void *);
4806extern void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2)); 4829extern void *xnmalloc (ptrdiff_t, ptrdiff_t)
4830 ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL;
4807extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t) 4831extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
4808 ATTRIBUTE_ALLOC_SIZE ((2,3)); 4832 ATTRIBUTE_ALLOC_SIZE ((2,3)) ATTRIBUTE_RETURNS_NONNULL;
4809extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t); 4833extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t)
4810 4834 ATTRIBUTE_RETURNS_NONNULL;
4811extern char *xstrdup (const char *) ATTRIBUTE_MALLOC; 4835
4812extern char *xlispstrdup (Lisp_Object) ATTRIBUTE_MALLOC; 4836extern char *xstrdup (char const *)
4837 ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
4838extern char *xlispstrdup (Lisp_Object)
4839 ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
4813extern void dupstring (char **, char const *); 4840extern void dupstring (char **, char const *);
4814 4841
4815/* Make DEST a copy of STRING's data. Return a pointer to DEST's terminating 4842/* Make DEST a copy of STRING's data. Return a pointer to DEST's terminating
@@ -4859,7 +4886,8 @@ extern void init_system_name (void);
4859 4886
4860enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 }; 4887enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 };
4861 4888
4862extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1)); 4889extern void *record_xmalloc (size_t)
4890 ATTRIBUTE_ALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
4863 4891
4864#define USE_SAFE_ALLOCA \ 4892#define USE_SAFE_ALLOCA \
4865 ptrdiff_t sa_avail = MAX_ALLOCA; \ 4893 ptrdiff_t sa_avail = MAX_ALLOCA; \
diff --git a/src/lread.c b/src/lread.c
index a6c2db5d994..b3f9e6ff527 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -165,6 +165,12 @@ static void readevalloop (Lisp_Object, struct infile *, Lisp_Object, bool,
165 Lisp_Object, Lisp_Object); 165 Lisp_Object, Lisp_Object);
166 166
167static void build_load_history (Lisp_Object, bool); 167static void build_load_history (Lisp_Object, bool);
168
169static Lisp_Object oblookup_considering_shorthand (Lisp_Object, const char *,
170 ptrdiff_t, ptrdiff_t,
171 char **, ptrdiff_t *,
172 ptrdiff_t *);
173
168 174
169/* Functions that read one byte from the current source READCHARFUN 175/* Functions that read one byte from the current source READCHARFUN
170 or unreads one byte. If the integer argument C is -1, it returns 176 or unreads one byte. If the integer argument C is -1, it returns
@@ -192,7 +198,7 @@ static int readbyte_from_string (int, Lisp_Object);
192 Qlambda, or a cons, we use this to keep an unread character because 198 Qlambda, or a cons, we use this to keep an unread character because
193 a file stream can't handle multibyte-char unreading. The value -1 199 a file stream can't handle multibyte-char unreading. The value -1
194 means that there's no unread character. */ 200 means that there's no unread character. */
195static int unread_char; 201static int unread_char = -1;
196 202
197static int 203static int
198readchar (Lisp_Object readcharfun, bool *multibyte) 204readchar (Lisp_Object readcharfun, bool *multibyte)
@@ -1507,6 +1513,7 @@ Return t if the file exists and loads successfully. */)
1507 input.stream = stream; 1513 input.stream = stream;
1508 input.lookahead = 0; 1514 input.lookahead = 0;
1509 infile = &input; 1515 infile = &input;
1516 unread_char = -1;
1510 } 1517 }
1511 1518
1512 if (! NILP (Vpurify_flag)) 1519 if (! NILP (Vpurify_flag))
@@ -2955,7 +2962,6 @@ read_integer (Lisp_Object readcharfun, int radix,
2955 return unbind_to (count, string_to_number (read_buffer, radix, NULL)); 2962 return unbind_to (count, string_to_number (read_buffer, radix, NULL));
2956} 2963}
2957 2964
2958
2959/* If the next token is ')' or ']' or '.', we store that character 2965/* If the next token is ')' or ']' or '.', we store that character
2960 in *PCH and the return value is not interesting. Else, we store 2966 in *PCH and the return value is not interesting. Else, we store
2961 zero in *PCH and we read and return one lisp object. 2967 zero in *PCH and we read and return one lisp object.
@@ -2967,6 +2973,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2967{ 2973{
2968 int c; 2974 int c;
2969 bool uninterned_symbol = false; 2975 bool uninterned_symbol = false;
2976 bool skip_shorthand = false;
2970 bool multibyte; 2977 bool multibyte;
2971 char stackbuf[stackbufsize]; 2978 char stackbuf[stackbufsize];
2972 current_thread->stack_top = stackbuf; 2979 current_thread->stack_top = stackbuf;
@@ -3362,6 +3369,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3362 if (c == ':') 3369 if (c == ':')
3363 { 3370 {
3364 uninterned_symbol = true; 3371 uninterned_symbol = true;
3372 read_hash_prefixed_symbol:
3365 c = READCHAR; 3373 c = READCHAR;
3366 if (!(c > 040 3374 if (!(c > 040
3367 && c != NO_BREAK_SPACE 3375 && c != NO_BREAK_SPACE
@@ -3375,6 +3383,12 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3375 } 3383 }
3376 goto read_symbol; 3384 goto read_symbol;
3377 } 3385 }
3386 /* #_foo is really the symbol foo, regardless of shorthands */
3387 if (c == '_')
3388 {
3389 skip_shorthand = true;
3390 goto read_hash_prefixed_symbol;
3391 }
3378 /* ## is the empty symbol. */ 3392 /* ## is the empty symbol. */
3379 if (c == '#') 3393 if (c == '#')
3380 return Fintern (empty_unibyte_string, Qnil); 3394 return Fintern (empty_unibyte_string, Qnil);
@@ -3755,7 +3769,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3755 ptrdiff_t nbytes = p - read_buffer; 3769 ptrdiff_t nbytes = p - read_buffer;
3756 UNREAD (c); 3770 UNREAD (c);
3757 3771
3758 if (!quoted && !uninterned_symbol) 3772 if (!quoted && !uninterned_symbol && !skip_shorthand)
3759 { 3773 {
3760 ptrdiff_t len; 3774 ptrdiff_t len;
3761 Lisp_Object result = string_to_number (read_buffer, 10, &len); 3775 Lisp_Object result = string_to_number (read_buffer, 10, &len);
@@ -3785,11 +3799,36 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3785 3799
3786 Like intern_1 but supports multibyte names. */ 3800 Like intern_1 but supports multibyte names. */
3787 Lisp_Object obarray = check_obarray (Vobarray); 3801 Lisp_Object obarray = check_obarray (Vobarray);
3788 Lisp_Object tem = oblookup (obarray, read_buffer, 3802
3789 nchars, nbytes); 3803 char* longhand = NULL;
3804 ptrdiff_t longhand_chars = 0;
3805 ptrdiff_t longhand_bytes = 0;
3806
3807 Lisp_Object tem;
3808 if (skip_shorthand
3809 /* The following ASCII characters are used in the
3810 only "core" Emacs Lisp symbols that are comprised
3811 entirely of characters that have the 'symbol
3812 constituent' syntax. We exempt them from
3813 transforming according to shorthands. */
3814 || strspn (read_buffer, "^*+-/<=>_|") >= nbytes)
3815 tem = oblookup (obarray, read_buffer, nchars, nbytes);
3816 else
3817 tem = oblookup_considering_shorthand (obarray, read_buffer,
3818 nchars, nbytes, &longhand,
3819 &longhand_chars,
3820 &longhand_bytes);
3790 3821
3791 if (SYMBOLP (tem)) 3822 if (SYMBOLP (tem))
3792 result = tem; 3823 result = tem;
3824 else if (longhand)
3825 {
3826 Lisp_Object name
3827 = make_specified_string (longhand, longhand_chars,
3828 longhand_bytes, multibyte);
3829 xfree (longhand);
3830 result = intern_driver (name, obarray, tem);
3831 }
3793 else 3832 else
3794 { 3833 {
3795 Lisp_Object name 3834 Lisp_Object name
@@ -4338,6 +4377,7 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, Lisp_Object index)
4338Lisp_Object 4377Lisp_Object
4339intern_driver (Lisp_Object string, Lisp_Object obarray, Lisp_Object index) 4378intern_driver (Lisp_Object string, Lisp_Object obarray, Lisp_Object index)
4340{ 4379{
4380 SET_SYMBOL_VAL (XSYMBOL (Qobarray_cache), Qnil);
4341 return intern_sym (Fmake_symbol (string), obarray, index); 4381 return intern_sym (Fmake_symbol (string), obarray, index);
4342} 4382}
4343 4383
@@ -4406,10 +4446,28 @@ it defaults to the value of `obarray'. */)
4406 obarray = check_obarray (NILP (obarray) ? Vobarray : obarray); 4446 obarray = check_obarray (NILP (obarray) ? Vobarray : obarray);
4407 CHECK_STRING (string); 4447 CHECK_STRING (string);
4408 4448
4409 tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string)); 4449
4450 char* longhand = NULL;
4451 ptrdiff_t longhand_chars = 0;
4452 ptrdiff_t longhand_bytes = 0;
4453 tem = oblookup_considering_shorthand (obarray, SSDATA (string),
4454 SCHARS (string), SBYTES (string),
4455 &longhand, &longhand_chars,
4456 &longhand_bytes);
4457
4410 if (!SYMBOLP (tem)) 4458 if (!SYMBOLP (tem))
4411 tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string), 4459 {
4412 obarray, tem); 4460 if (longhand)
4461 {
4462 tem = intern_driver (make_specified_string (longhand, longhand_chars,
4463 longhand_bytes, true),
4464 obarray, tem);
4465 xfree (longhand);
4466 }
4467 else
4468 tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
4469 obarray, tem);
4470 }
4413 return tem; 4471 return tem;
4414} 4472}
4415 4473
@@ -4428,17 +4486,29 @@ it defaults to the value of `obarray'. */)
4428 4486
4429 if (!SYMBOLP (name)) 4487 if (!SYMBOLP (name))
4430 { 4488 {
4489 char *longhand = NULL;
4490 ptrdiff_t longhand_chars = 0;
4491 ptrdiff_t longhand_bytes = 0;
4492
4431 CHECK_STRING (name); 4493 CHECK_STRING (name);
4432 string = name; 4494 string = name;
4495 tem = oblookup_considering_shorthand (obarray, SSDATA (string),
4496 SCHARS (string), SBYTES (string),
4497 &longhand, &longhand_chars,
4498 &longhand_bytes);
4499 if (longhand)
4500 xfree (longhand);
4501 return FIXNUMP (tem) ? Qnil : tem;
4433 } 4502 }
4434 else 4503 else
4435 string = SYMBOL_NAME (name); 4504 {
4436 4505 /* If already a symbol, we don't do shorthand-longhand translation,
4437 tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string)); 4506 as promised in the docstring. */
4438 if (FIXNUMP (tem) || (SYMBOLP (name) && !EQ (name, tem))) 4507 string = SYMBOL_NAME (name);
4439 return Qnil; 4508 tem
4440 else 4509 = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
4441 return tem; 4510 return EQ (name, tem) ? name : Qnil;
4511 }
4442} 4512}
4443 4513
4444DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, 4514DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0,
@@ -4450,7 +4520,8 @@ OBARRAY, if nil, defaults to the value of the variable `obarray'.
4450usage: (unintern NAME OBARRAY) */) 4520usage: (unintern NAME OBARRAY) */)
4451 (Lisp_Object name, Lisp_Object obarray) 4521 (Lisp_Object name, Lisp_Object obarray)
4452{ 4522{
4453 register Lisp_Object string, tem; 4523 register Lisp_Object tem;
4524 Lisp_Object string;
4454 size_t hash; 4525 size_t hash;
4455 4526
4456 if (NILP (obarray)) obarray = Vobarray; 4527 if (NILP (obarray)) obarray = Vobarray;
@@ -4464,9 +4535,16 @@ usage: (unintern NAME OBARRAY) */)
4464 string = name; 4535 string = name;
4465 } 4536 }
4466 4537
4467 tem = oblookup (obarray, SSDATA (string), 4538 char *longhand = NULL;
4468 SCHARS (string), 4539 ptrdiff_t longhand_chars = 0;
4469 SBYTES (string)); 4540 ptrdiff_t longhand_bytes = 0;
4541 tem = oblookup_considering_shorthand (obarray, SSDATA (string),
4542 SCHARS (string), SBYTES (string),
4543 &longhand, &longhand_chars,
4544 &longhand_bytes);
4545 if (longhand)
4546 xfree(longhand);
4547
4470 if (FIXNUMP (tem)) 4548 if (FIXNUMP (tem))
4471 return Qnil; 4549 return Qnil;
4472 /* If arg was a symbol, don't delete anything but that symbol itself. */ 4550 /* If arg was a symbol, don't delete anything but that symbol itself. */
@@ -4553,6 +4631,70 @@ oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff
4553 XSETINT (tem, hash); 4631 XSETINT (tem, hash);
4554 return tem; 4632 return tem;
4555} 4633}
4634
4635/* Like 'oblookup', but considers 'Vread_symbol_shorthands',
4636 potentially recognizing that IN is shorthand for some other
4637 longhand name, which is then then placed in OUT. In that case,
4638 memory is malloc'ed for OUT (which the caller must free) while
4639 SIZE_OUT and SIZE_BYTE_OUT respectively hold the character and byte
4640 sizes of the transformed symbol name. If IN is not recognized
4641 shorthand for any other symbol, OUT is set to point to NULL and
4642 'oblookup' is called. */
4643
4644Lisp_Object
4645oblookup_considering_shorthand (Lisp_Object obarray, const char *in,
4646 ptrdiff_t size, ptrdiff_t size_byte, char **out,
4647 ptrdiff_t *size_out, ptrdiff_t *size_byte_out)
4648{
4649 Lisp_Object tail = Vread_symbol_shorthands;
4650
4651 /* First, assume no transformation will take place. */
4652 *out = NULL;
4653 /* Then, iterate each pair in Vread_symbol_shorthands. */
4654 FOR_EACH_TAIL_SAFE (tail)
4655 {
4656 Lisp_Object pair = XCAR (tail);
4657 /* Be lenient to 'read-symbol-shorthands': if some element isn't a
4658 cons, or some member of that cons isn't a string, just skip
4659 to the next element. */
4660 if (!CONSP (pair))
4661 continue;
4662 Lisp_Object sh_prefix = XCAR (pair);
4663 Lisp_Object lh_prefix = XCDR (pair);
4664 if (!STRINGP (sh_prefix) || !STRINGP (lh_prefix))
4665 continue;
4666 ptrdiff_t sh_prefix_size = SBYTES (sh_prefix);
4667
4668 /* Compare the prefix of the transformation pair to the symbol
4669 name. If a match occurs, do the renaming and exit the loop.
4670 In other words, only one such transformation may take place.
4671 Calculate the amount of memory to allocate for the longhand
4672 version of the symbol name with xrealloc. This isn't
4673 strictly needed, but it could later be used as a way for
4674 multiple transformations on a single symbol name. */
4675 if (sh_prefix_size <= size_byte
4676 && memcmp (SSDATA (sh_prefix), in, sh_prefix_size) == 0)
4677 {
4678 ptrdiff_t lh_prefix_size = SBYTES (lh_prefix);
4679 ptrdiff_t suffix_size = size_byte - sh_prefix_size;
4680 *out = xrealloc (*out, lh_prefix_size + suffix_size);
4681 memcpy (*out, SSDATA(lh_prefix), lh_prefix_size);
4682 memcpy (*out + lh_prefix_size, in + sh_prefix_size, suffix_size);
4683 *size_out = SCHARS (lh_prefix) - SCHARS (sh_prefix) + size;
4684 *size_byte_out = lh_prefix_size + suffix_size;
4685 break;
4686 }
4687 }
4688 /* Now, as promised, call oblookup with the "final" symbol name to
4689 lookup. That function remains oblivious to whether a
4690 transformation happened here or not, but the caller of this
4691 function can tell by inspecting the OUT parameter. */
4692 if (*out)
4693 return oblookup (obarray, *out, *size_out, *size_byte_out);
4694 else
4695 return oblookup (obarray, in, size, size_byte);
4696}
4697
4556 4698
4557void 4699void
4558map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Object arg) 4700map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Object arg)
@@ -5309,4 +5451,11 @@ that are loaded before your customizations are read! */);
5309 DEFSYM (Qrehash_threshold, "rehash-threshold"); 5451 DEFSYM (Qrehash_threshold, "rehash-threshold");
5310 5452
5311 DEFSYM (Qchar_from_name, "char-from-name"); 5453 DEFSYM (Qchar_from_name, "char-from-name");
5454
5455 DEFVAR_LISP ("read-symbol-shorthands", Vread_symbol_shorthands,
5456 doc: /* Alist of known symbol-name shorthands.
5457This variable's value can only be set via file-local variables.
5458See Info node `(elisp)Shorthands' for more details. */);
5459 Vread_symbol_shorthands = Qnil;
5460 DEFSYM (Qobarray_cache, "obarray-cache");
5312} 5461}
diff --git a/src/macfont.m b/src/macfont.m
index d86f09f4850..1426cae6dc4 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -613,6 +613,21 @@ get_cgcolor(unsigned long idx, struct frame *f)
613 return cgColor; 613 return cgColor;
614} 614}
615 615
616static CGColorRef
617get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f)
618{
619 [nsColor set];
620 CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
621 NSInteger noc = [nsColor numberOfComponents];
622 CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
623 CGColorRef cgColor;
624
625 [nsColor getComponents: components];
626 cgColor = CGColorCreate (colorSpace, components);
627 xfree (components);
628 return cgColor;
629}
630
616#define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ 631#define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \
617 do { \ 632 do { \
618 CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ 633 CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \
@@ -2415,8 +2430,12 @@ macfont_list (struct frame *f, Lisp_Object spec)
2415 continue; 2430 continue;
2416 2431
2417 /* Don't use a color bitmap font unless its family is 2432 /* Don't use a color bitmap font unless its family is
2418 explicitly specified. */ 2433 explicitly specified or we're looking for a font for
2419 if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family)) 2434 emoji. */
2435 if ((sym_traits & kCTFontTraitColorGlyphs)
2436 && NILP (family)
2437 && !EQ (CDR_SAFE (assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX))),
2438 Qemoji))
2420 continue; 2439 continue;
2421 2440
2422 if (j > 0 2441 if (j > 0
@@ -2907,14 +2926,14 @@ macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2907 2926
2908 if (!CGRectIsNull (background_rect)) 2927 if (!CGRectIsNull (background_rect))
2909 { 2928 {
2910 if (s->hl == DRAW_MOUSE_FACE) 2929 if (s->hl == DRAW_CURSOR)
2911 { 2930 {
2912 face = FACE_FROM_ID_OR_NULL (s->f, 2931 CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f);
2913 MOUSE_HL_INFO (s->f)->mouse_face_face_id); 2932 CGContextSetFillColorWithColor (context, colorref);
2914 if (!face) 2933 CGColorRelease (colorref);
2915 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2916 } 2934 }
2917 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); 2935 else
2936 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2918 CGContextFillRects (context, &background_rect, 1); 2937 CGContextFillRects (context, &background_rect, 1);
2919 } 2938 }
2920 2939
@@ -2923,7 +2942,14 @@ macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2923 CGAffineTransform atfm; 2942 CGAffineTransform atfm;
2924 2943
2925 CGContextScaleCTM (context, 1, -1); 2944 CGContextScaleCTM (context, 1, -1);
2926 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); 2945 if (s->hl == DRAW_CURSOR)
2946 {
2947 CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f);
2948 CGContextSetFillColorWithColor (context, colorref);
2949 CGColorRelease (colorref);
2950 }
2951 else
2952 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2927 if (macfont_info->synthetic_italic_p) 2953 if (macfont_info->synthetic_italic_p)
2928 atfm = synthetic_italic_atfm; 2954 atfm = synthetic_italic_atfm;
2929 else 2955 else
diff --git a/src/menu.c b/src/menu.c
index a2738ebd8a2..780b71eba6b 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1127,9 +1127,12 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
1127 1127
1128 /* Decode the first argument: find the window and the coordinates. */ 1128 /* Decode the first argument: find the window and the coordinates. */
1129 if (EQ (position, Qt) 1129 if (EQ (position, Qt)
1130 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) 1130 || (CONSP (position)
1131 || EQ (XCAR (position), Qtab_bar) 1131 && (EQ (XCAR (position), Qmenu_bar)
1132 || EQ (XCAR (position), Qtool_bar)))) 1132 || EQ (XCAR (position), Qtab_bar)
1133 || (CONSP (XCDR (position))
1134 && EQ (XCAR (XCDR (position)), Qtab_bar))
1135 || EQ (XCAR (position), Qtool_bar))))
1133 { 1136 {
1134 get_current_pos_p = 1; 1137 get_current_pos_p = 1;
1135 } 1138 }
@@ -1284,12 +1287,16 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
1284 /* Search for a string appearing directly as an element of the keymap. 1287 /* Search for a string appearing directly as an element of the keymap.
1285 That string is the title of the menu. */ 1288 That string is the title of the menu. */
1286 prompt = Fkeymap_prompt (keymap); 1289 prompt = Fkeymap_prompt (keymap);
1287 if (!NILP (prompt)) 1290
1288 title = prompt; 1291#if defined (USE_GTK) || defined (HAVE_NS)
1289#ifdef HAVE_NS /* Is that needed and NS-specific? --Stef */ 1292 if (STRINGP (prompt)
1293 && SCHARS (prompt) > 0
1294 && !NILP (Fget_text_property (make_fixnum (0), Qhide, prompt)))
1295 title = Qnil;
1290 else 1296 else
1291 title = build_string ("Select");
1292#endif 1297#endif
1298 if (!NILP (prompt))
1299 title = prompt;
1293 1300
1294 /* Make that be the pane title of the first pane. */ 1301 /* Make that be the pane title of the first pane. */
1295 if (!NILP (prompt) && menu_items_n_panes >= 0) 1302 if (!NILP (prompt) && menu_items_n_panes >= 0)
@@ -1575,6 +1582,8 @@ syms_of_menu (void)
1575 menu_items = Qnil; 1582 menu_items = Qnil;
1576 staticpro (&menu_items); 1583 staticpro (&menu_items);
1577 1584
1585 DEFSYM (Qhide, "hide");
1586
1578 defsubr (&Sx_popup_menu); 1587 defsubr (&Sx_popup_menu);
1579 defsubr (&Sx_popup_dialog); 1588 defsubr (&Sx_popup_dialog);
1580 defsubr (&Smenu_bar_menu_at_x_y); 1589 defsubr (&Smenu_bar_menu_at_x_y);
diff --git a/src/minibuf.c b/src/minibuf.c
index 0f4349e70b8..6c0cd358c50 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -491,8 +491,13 @@ confirm the aborting of the current minibuffer and all contained ones. */)
491 array[1] = make_fixnum (minibuf_level - minibuf_depth + 1); 491 array[1] = make_fixnum (minibuf_level - minibuf_depth + 1);
492 if (!NILP (Fyes_or_no_p (Fformat (2, array)))) 492 if (!NILP (Fyes_or_no_p (Fformat (2, array))))
493 { 493 {
494 minibuffer_quit_level = minibuf_depth; 494 /* Due to the above check, the current minibuffer is in the
495 Fthrow (Qexit, Qt); 495 most nested command loop, which means that we don't have
496 to abort any extra non-minibuffer recursive edits. Thus,
497 the number of recursive edits we have to abort equals the
498 number of minibuffers we have to abort. */
499 CALLN (Ffuncall, intern ("minibuffer-quit-recursive-edit"),
500 array[1]);
496 } 501 }
497 } 502 }
498 else 503 else
@@ -689,12 +694,15 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
689 call1 (Qpush_window_buffer_onto_prev, minibuf_window); 694 call1 (Qpush_window_buffer_onto_prev, minibuf_window);
690 695
691 record_unwind_protect_void (minibuffer_unwind); 696 record_unwind_protect_void (minibuffer_unwind);
692 record_unwind_protect (restore_window_configuration, 697 if (read_minibuffer_restore_windows)
693 list3 (Fcurrent_window_configuration (Qnil), Qt, Qt)); 698 record_unwind_protect (restore_window_configuration,
699 list3 (Fcurrent_window_configuration (Qnil),
700 Qt, Qt));
694 701
695 /* If the minibuffer window is on a different frame, save that 702 /* If the minibuffer window is on a different frame, save that
696 frame's configuration too. */ 703 frame's configuration too. */
697 if (!EQ (mini_frame, selected_frame)) 704 if (read_minibuffer_restore_windows &&
705 !EQ (mini_frame, selected_frame))
698 record_unwind_protect (restore_window_configuration, 706 record_unwind_protect (restore_window_configuration,
699 list3 (Fcurrent_window_configuration (mini_frame), 707 list3 (Fcurrent_window_configuration (mini_frame),
700 Qnil, Qt)); 708 Qnil, Qt));
@@ -997,7 +1005,7 @@ set_minibuffer_mode (Lisp_Object buf, EMACS_INT depth)
997 if (!NILP (Ffboundp (Qminibuffer_inactive_mode))) 1005 if (!NILP (Ffboundp (Qminibuffer_inactive_mode)))
998 call0 (Qminibuffer_inactive_mode); 1006 call0 (Qminibuffer_inactive_mode);
999 else 1007 else
1000 Fkill_all_local_variables (); 1008 Fkill_all_local_variables (Qnil);
1001 } 1009 }
1002 buf = unbind_to (count, buf); 1010 buf = unbind_to (count, buf);
1003} 1011}
@@ -1284,8 +1292,8 @@ Fifth arg HIST, if non-nil, specifies a history list and optionally
1284 HISTPOS is the initial position for use by the minibuffer history 1292 HISTPOS is the initial position for use by the minibuffer history
1285 commands. For consistency, you should also specify that element of 1293 commands. For consistency, you should also specify that element of
1286 the history as the value of INITIAL-CONTENTS. Positions are counted 1294 the history as the value of INITIAL-CONTENTS. Positions are counted
1287 starting from 1 at the beginning of the list. If HIST is the symbol 1295 starting from 1 at the beginning of the list. If HIST is t, history
1288 `t', history is not recorded. 1296 is not recorded.
1289 1297
1290 If `history-add-new-input' is non-nil (the default), the result will 1298 If `history-add-new-input' is non-nil (the default), the result will
1291 be added to the history list using `add-to-history'. 1299 be added to the history list using `add-to-history'.
@@ -1537,6 +1545,27 @@ minibuf_conform_representation (Lisp_Object string, Lisp_Object basis)
1537 return Fstring_make_multibyte (string); 1545 return Fstring_make_multibyte (string);
1538} 1546}
1539 1547
1548static bool
1549match_regexps (Lisp_Object string, Lisp_Object regexps,
1550 bool ignore_case)
1551{
1552 ptrdiff_t val;
1553 for (; CONSP (regexps); regexps = XCDR (regexps))
1554 {
1555 CHECK_STRING (XCAR (regexps));
1556
1557 val = fast_string_match_internal
1558 (XCAR (regexps), string,
1559 (ignore_case ? BVAR (current_buffer, case_canon_table) : Qnil));
1560
1561 if (val == -2)
1562 error ("Stack overflow in regexp matcher");
1563 if (val < 0)
1564 return false;
1565 }
1566 return true;
1567}
1568
1540DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0, 1569DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0,
1541 doc: /* Return common substring of all completions of STRING in COLLECTION. 1570 doc: /* Return common substring of all completions of STRING in COLLECTION.
1542Test each possible completion specified by COLLECTION 1571Test each possible completion specified by COLLECTION
@@ -1570,6 +1599,7 @@ Additionally to this predicate, `completion-regexp-list'
1570is used to further constrain the set of candidates. */) 1599is used to further constrain the set of candidates. */)
1571 (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) 1600 (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate)
1572{ 1601{
1602
1573 Lisp_Object bestmatch, tail, elt, eltstring; 1603 Lisp_Object bestmatch, tail, elt, eltstring;
1574 /* Size in bytes of BESTMATCH. */ 1604 /* Size in bytes of BESTMATCH. */
1575 ptrdiff_t bestmatchsize = 0; 1605 ptrdiff_t bestmatchsize = 0;
@@ -1583,7 +1613,6 @@ is used to further constrain the set of candidates. */)
1583 ? list_table : function_table)); 1613 ? list_table : function_table));
1584 ptrdiff_t idx = 0, obsize = 0; 1614 ptrdiff_t idx = 0, obsize = 0;
1585 int matchcount = 0; 1615 int matchcount = 0;
1586 ptrdiff_t bindcount = -1;
1587 Lisp_Object bucket, zero, end, tem; 1616 Lisp_Object bucket, zero, end, tem;
1588 1617
1589 CHECK_STRING (string); 1618 CHECK_STRING (string);
@@ -1662,27 +1691,10 @@ is used to further constrain the set of candidates. */)
1662 completion_ignore_case ? Qt : Qnil), 1691 completion_ignore_case ? Qt : Qnil),
1663 EQ (Qt, tem))) 1692 EQ (Qt, tem)))
1664 { 1693 {
1665 /* Yes. */
1666 Lisp_Object regexps;
1667
1668 /* Ignore this element if it fails to match all the regexps. */ 1694 /* Ignore this element if it fails to match all the regexps. */
1669 { 1695 if (!match_regexps (eltstring, Vcompletion_regexp_list,
1670 for (regexps = Vcompletion_regexp_list; CONSP (regexps); 1696 completion_ignore_case))
1671 regexps = XCDR (regexps)) 1697 continue;
1672 {
1673 if (bindcount < 0)
1674 {
1675 bindcount = SPECPDL_INDEX ();
1676 specbind (Qcase_fold_search,
1677 completion_ignore_case ? Qt : Qnil);
1678 }
1679 tem = Fstring_match (XCAR (regexps), eltstring, zero);
1680 if (NILP (tem))
1681 break;
1682 }
1683 if (CONSP (regexps))
1684 continue;
1685 }
1686 1698
1687 /* Ignore this element if there is a predicate 1699 /* Ignore this element if there is a predicate
1688 and the predicate doesn't like it. */ 1700 and the predicate doesn't like it. */
@@ -1693,11 +1705,6 @@ is used to further constrain the set of candidates. */)
1693 tem = Fcommandp (elt, Qnil); 1705 tem = Fcommandp (elt, Qnil);
1694 else 1706 else
1695 { 1707 {
1696 if (bindcount >= 0)
1697 {
1698 unbind_to (bindcount, Qnil);
1699 bindcount = -1;
1700 }
1701 tem = (type == hash_table 1708 tem = (type == hash_table
1702 ? call2 (predicate, elt, 1709 ? call2 (predicate, elt,
1703 HASH_VALUE (XHASH_TABLE (collection), 1710 HASH_VALUE (XHASH_TABLE (collection),
@@ -1779,9 +1786,6 @@ is used to further constrain the set of candidates. */)
1779 } 1786 }
1780 } 1787 }
1781 1788
1782 if (bindcount >= 0)
1783 unbind_to (bindcount, Qnil);
1784
1785 if (NILP (bestmatch)) 1789 if (NILP (bestmatch))
1786 return Qnil; /* No completions found. */ 1790 return Qnil; /* No completions found. */
1787 /* If we are ignoring case, and there is no exact match, 1791 /* If we are ignoring case, and there is no exact match,
@@ -1841,7 +1845,6 @@ with a space are ignored unless STRING itself starts with a space. */)
1841 : VECTORP (collection) ? 2 1845 : VECTORP (collection) ? 2
1842 : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection)); 1846 : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection));
1843 ptrdiff_t idx = 0, obsize = 0; 1847 ptrdiff_t idx = 0, obsize = 0;
1844 ptrdiff_t bindcount = -1;
1845 Lisp_Object bucket, tem, zero; 1848 Lisp_Object bucket, tem, zero;
1846 1849
1847 CHECK_STRING (string); 1850 CHECK_STRING (string);
@@ -1926,27 +1929,10 @@ with a space are ignored unless STRING itself starts with a space. */)
1926 completion_ignore_case ? Qt : Qnil), 1929 completion_ignore_case ? Qt : Qnil),
1927 EQ (Qt, tem))) 1930 EQ (Qt, tem)))
1928 { 1931 {
1929 /* Yes. */
1930 Lisp_Object regexps;
1931
1932 /* Ignore this element if it fails to match all the regexps. */ 1932 /* Ignore this element if it fails to match all the regexps. */
1933 { 1933 if (!match_regexps (eltstring, Vcompletion_regexp_list,
1934 for (regexps = Vcompletion_regexp_list; CONSP (regexps); 1934 completion_ignore_case))
1935 regexps = XCDR (regexps)) 1935 continue;
1936 {
1937 if (bindcount < 0)
1938 {
1939 bindcount = SPECPDL_INDEX ();
1940 specbind (Qcase_fold_search,
1941 completion_ignore_case ? Qt : Qnil);
1942 }
1943 tem = Fstring_match (XCAR (regexps), eltstring, zero);
1944 if (NILP (tem))
1945 break;
1946 }
1947 if (CONSP (regexps))
1948 continue;
1949 }
1950 1936
1951 /* Ignore this element if there is a predicate 1937 /* Ignore this element if there is a predicate
1952 and the predicate doesn't like it. */ 1938 and the predicate doesn't like it. */
@@ -1957,11 +1943,6 @@ with a space are ignored unless STRING itself starts with a space. */)
1957 tem = Fcommandp (elt, Qnil); 1943 tem = Fcommandp (elt, Qnil);
1958 else 1944 else
1959 { 1945 {
1960 if (bindcount >= 0)
1961 {
1962 unbind_to (bindcount, Qnil);
1963 bindcount = -1;
1964 }
1965 tem = type == 3 1946 tem = type == 3
1966 ? call2 (predicate, elt, 1947 ? call2 (predicate, elt,
1967 HASH_VALUE (XHASH_TABLE (collection), idx - 1)) 1948 HASH_VALUE (XHASH_TABLE (collection), idx - 1))
@@ -1974,9 +1955,6 @@ with a space are ignored unless STRING itself starts with a space. */)
1974 } 1955 }
1975 } 1956 }
1976 1957
1977 if (bindcount >= 0)
1978 unbind_to (bindcount, Qnil);
1979
1980 return Fnreverse (allmatches); 1958 return Fnreverse (allmatches);
1981} 1959}
1982 1960
@@ -2029,8 +2007,7 @@ HIST, if non-nil, specifies a history list and optionally the initial
2029 (This is the only case in which you should use INITIAL-INPUT instead 2007 (This is the only case in which you should use INITIAL-INPUT instead
2030 of DEF.) Positions are counted starting from 1 at the beginning of 2008 of DEF.) Positions are counted starting from 1 at the beginning of
2031 the list. The variable `history-length' controls the maximum length 2009 the list. The variable `history-length' controls the maximum length
2032 of a history list. If HIST is the symbol `t', history is not 2010 of a history list. If HIST is t, history is not recorded.
2033 recorded.
2034 2011
2035DEF, if non-nil, is the default value or the list of default values. 2012DEF, if non-nil, is the default value or the list of default values.
2036 2013
@@ -2052,12 +2029,16 @@ See also `completing-read-function'. */)
2052/* Test whether TXT is an exact completion. */ 2029/* Test whether TXT is an exact completion. */
2053DEFUN ("test-completion", Ftest_completion, Stest_completion, 2, 3, 0, 2030DEFUN ("test-completion", Ftest_completion, Stest_completion, 2, 3, 0,
2054 doc: /* Return non-nil if STRING is a valid completion. 2031 doc: /* Return non-nil if STRING is a valid completion.
2032For instance, if COLLECTION is a list of strings, STRING is a
2033valid completion if it appears in the list and PREDICATE is satisfied.
2034
2055Takes the same arguments as `all-completions' and `try-completion'. 2035Takes the same arguments as `all-completions' and `try-completion'.
2036
2056If COLLECTION is a function, it is called with three arguments: 2037If COLLECTION is a function, it is called with three arguments:
2057the values STRING, PREDICATE and `lambda'. */) 2038the values STRING, PREDICATE and `lambda'. */)
2058 (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) 2039 (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate)
2059{ 2040{
2060 Lisp_Object regexps, tail, tem = Qnil; 2041 Lisp_Object tail, tem = Qnil;
2061 ptrdiff_t i = 0; 2042 ptrdiff_t i = 0;
2062 2043
2063 CHECK_STRING (string); 2044 CHECK_STRING (string);
@@ -2143,20 +2124,9 @@ the values STRING, PREDICATE and `lambda'. */)
2143 return call3 (collection, string, predicate, Qlambda); 2124 return call3 (collection, string, predicate, Qlambda);
2144 2125
2145 /* Reject this element if it fails to match all the regexps. */ 2126 /* Reject this element if it fails to match all the regexps. */
2146 if (CONSP (Vcompletion_regexp_list)) 2127 if (!match_regexps (string, Vcompletion_regexp_list,
2147 { 2128 completion_ignore_case))
2148 ptrdiff_t count = SPECPDL_INDEX (); 2129 return Qnil;
2149 specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil);
2150 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
2151 regexps = XCDR (regexps))
2152 {
2153 /* We can test against STRING, because if we got here, then
2154 the element is equivalent to it. */
2155 if (NILP (Fstring_match (XCAR (regexps), string, Qnil)))
2156 return unbind_to (count, Qnil);
2157 }
2158 unbind_to (count, Qnil);
2159 }
2160 2130
2161 /* Finally, check the predicate. */ 2131 /* Finally, check the predicate. */
2162 if (!NILP (predicate)) 2132 if (!NILP (predicate))
@@ -2474,7 +2444,7 @@ is added with
2474 (set minibuffer-history-variable 2444 (set minibuffer-history-variable
2475 (cons STRING (symbol-value minibuffer-history-variable))) 2445 (cons STRING (symbol-value minibuffer-history-variable)))
2476 2446
2477 If the variable is the symbol `t', no history is recorded. */); 2447 If the variable is t, no history is recorded. */);
2478 XSETFASTINT (Vminibuffer_history_variable, 0); 2448 XSETFASTINT (Vminibuffer_history_variable, 0);
2479 2449
2480 DEFVAR_LISP ("minibuffer-history-position", Vminibuffer_history_position, 2450 DEFVAR_LISP ("minibuffer-history-position", Vminibuffer_history_position,
@@ -2527,6 +2497,19 @@ for instance when running a headless Emacs server. Functions like
2527instead. */); 2497instead. */);
2528 inhibit_interaction = 0; 2498 inhibit_interaction = 0;
2529 2499
2500 DEFVAR_BOOL ("read-minibuffer-restore-windows", read_minibuffer_restore_windows,
2501 doc: /* Non-nil means restore window configurations on exit from minibuffer.
2502If this is non-nil (the default), reading input with the minibuffer will
2503restore, on exit, the window configurations of the frame where the
2504minibuffer was entered from and, if it is different, the frame that owns
2505the associated minibuffer window.
2506
2507If this is nil, window configurations are not restored upon exiting
2508the minibuffer. However, if `minibuffer-restore-windows' is present
2509in `minibuffer-exit-hook', exiting the minibuffer will remove the window
2510showing the *Completions* buffer, if any. */);
2511 read_minibuffer_restore_windows = true;
2512
2530 defsubr (&Sactive_minibuffer_window); 2513 defsubr (&Sactive_minibuffer_window);
2531 defsubr (&Sset_minibuffer_window); 2514 defsubr (&Sset_minibuffer_window);
2532 defsubr (&Sread_from_minibuffer); 2515 defsubr (&Sread_from_minibuffer);
diff --git a/src/module-env-28.h b/src/module-env-28.h
index f8820b0606b..bea80a5553a 100644
--- a/src/module-env-28.h
+++ b/src/module-env-28.h
@@ -1,7 +1,3 @@
1 /* Add module environment functions newly added in Emacs 28 here.
2 Before Emacs 28 is released, remove this comment and start
3 module-env-29.h on the master branch. */
4
5 void (*(*EMACS_ATTRIBUTE_NONNULL (1) 1 void (*(*EMACS_ATTRIBUTE_NONNULL (1)
6 get_function_finalizer) (emacs_env *env, 2 get_function_finalizer) (emacs_env *env,
7 emacs_value arg)) (void *) EMACS_NOEXCEPT; 3 emacs_value arg)) (void *) EMACS_NOEXCEPT;
diff --git a/src/module-env-29.h b/src/module-env-29.h
new file mode 100644
index 00000000000..6ca03773181
--- /dev/null
+++ b/src/module-env-29.h
@@ -0,0 +1,3 @@
1 /* Add module environment functions newly added in Emacs 29 here.
2 Before Emacs 29 is released, remove this comment and start
3 module-env-30.h on the master branch. */
diff --git a/src/msdos.c b/src/msdos.c
index 5da01c9e7ca..bf058c8aff9 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -1794,7 +1794,7 @@ internal_terminal_init (void)
1794 } 1794 }
1795 1795
1796 Vinitial_window_system = Qpc; 1796 Vinitial_window_system = Qpc;
1797 Vwindow_system_version = make_fixnum (28); /* RE Emacs version */ 1797 Vwindow_system_version = make_fixnum (29); /* RE Emacs version */
1798 tty->terminal->type = output_msdos_raw; 1798 tty->terminal->type = output_msdos_raw;
1799 1799
1800 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM 1800 /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
diff --git a/src/nsfns.m b/src/nsfns.m
index 454a6fdab62..f4d81722460 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -609,13 +609,72 @@ ns_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
609 } 609 }
610} 610}
611 611
612void
613ns_change_tab_bar_height (struct frame *f, int height)
614{
615 int unit = FRAME_LINE_HEIGHT (f);
616 int old_height = FRAME_TAB_BAR_HEIGHT (f);
617 int lines = (height + unit - 1) / unit;
618 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
619
620 /* Make sure we redisplay all windows in this frame. */
621 fset_redisplay (f);
622
623 /* Recalculate tab bar and frame text sizes. */
624 FRAME_TAB_BAR_HEIGHT (f) = height;
625 FRAME_TAB_BAR_LINES (f) = lines;
626 store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
627
628 if (FRAME_NS_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
629 {
630 clear_frame (f);
631 clear_current_matrices (f);
632 }
633
634 if ((height < old_height) && WINDOWP (f->tab_bar_window))
635 clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
636
637 if (!f->tab_bar_resized)
638 {
639 /* As long as tab_bar_resized is false, effectively try to change
640 F's native height. */
641 if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
642 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
643 1, false, Qtab_bar_lines);
644 else
645 adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
646
647 f->tab_bar_resized = f->tab_bar_redisplayed;
648 }
649 else
650 /* Any other change may leave the native size of F alone. */
651 adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
652
653 /* adjust_frame_size might not have done anything, garbage frame
654 here. */
655 adjust_frame_glyphs (f);
656 SET_FRAME_GARBAGED (f);
657}
612 658
613/* tabbar support */ 659/* tabbar support */
614static void 660static void
615ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) 661ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
616{ 662{
617 /* Currently unimplemented. */ 663 int olines = FRAME_TAB_BAR_LINES (f);
618 NSTRACE ("ns_set_tab_bar_lines"); 664 int nlines;
665
666 /* Treat tab bars like menu bars. */
667 if (FRAME_MINIBUF_ONLY_P (f))
668 return;
669
670 /* Use VALUE only if an int >= 0. */
671 if (RANGED_FIXNUMP (0, value, INT_MAX))
672 nlines = XFIXNAT (value);
673 else
674 nlines = 0;
675
676 if (nlines != olines && (olines == 0 || nlines == 0))
677 ns_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
619} 678}
620 679
621 680
@@ -947,11 +1006,7 @@ frame_parm_handler ns_frame_parm_handlers[] =
947 0, /* x_set_sticky */ 1006 0, /* x_set_sticky */
948 0, /* x_set_tool_bar_position */ 1007 0, /* x_set_tool_bar_position */
949 0, /* x_set_inhibit_double_buffering */ 1008 0, /* x_set_inhibit_double_buffering */
950#ifdef NS_IMPL_COCOA
951 ns_set_undecorated, 1009 ns_set_undecorated,
952#else
953 0, /* ns_set_undecorated */
954#endif
955 ns_set_parent_frame, 1010 ns_set_parent_frame,
956 0, /* x_set_skip_taskbar */ 1011 0, /* x_set_skip_taskbar */
957 ns_set_no_focus_on_map, 1012 ns_set_no_focus_on_map,
@@ -1181,6 +1236,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1181 "fontBackend", "FontBackend", RES_TYPE_STRING); 1236 "fontBackend", "FontBackend", RES_TYPE_STRING);
1182 1237
1183 { 1238 {
1239#ifdef NS_IMPL_COCOA
1184 /* use for default font name */ 1240 /* use for default font name */
1185 id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ 1241 id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
1186 gui_default_parameter (f, parms, Qfontsize, 1242 gui_default_parameter (f, parms, Qfontsize,
@@ -1195,6 +1251,11 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1195 build_string (fontname), 1251 build_string (fontname),
1196 "font", "Font", RES_TYPE_STRING); 1252 "font", "Font", RES_TYPE_STRING);
1197 xfree (fontname); 1253 xfree (fontname);
1254#else
1255 gui_default_parameter (f, parms, Qfont,
1256 build_string ("fixed"),
1257 "font", "Font", RES_TYPE_STRING);
1258#endif
1198 } 1259 }
1199 unblock_input (); 1260 unblock_input ();
1200 1261
@@ -1347,6 +1408,11 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1347 1408
1348 f->output_data.ns->in_animation = NO; 1409 f->output_data.ns->in_animation = NO;
1349 1410
1411#ifdef NS_IMPL_COCOA
1412 /* If the app has previously been disabled, start it up again. */
1413 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
1414#endif
1415
1350 [[EmacsView alloc] initFrameFromEmacs: f]; 1416 [[EmacsView alloc] initFrameFromEmacs: f];
1351 1417
1352 ns_icon (f, parms); 1418 ns_icon (f, parms);
@@ -1965,12 +2031,14 @@ is layered in front of the windows of other applications. */)
1965 [NSApp unhide: NSApp]; 2031 [NSApp unhide: NSApp];
1966 [NSApp activateIgnoringOtherApps: YES]; 2032 [NSApp activateIgnoringOtherApps: YES];
1967 } 2033 }
2034#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION >= 27
1968 else if (EQ (on, intern ("activate-front"))) 2035 else if (EQ (on, intern ("activate-front")))
1969 { 2036 {
1970 [NSApp unhide: NSApp]; 2037 [NSApp unhide: NSApp];
1971 [[NSRunningApplication currentApplication] 2038 [[NSRunningApplication currentApplication]
1972 activateWithOptions: NSApplicationActivateIgnoringOtherApps]; 2039 activateWithOptions: NSApplicationActivateIgnoringOtherApps];
1973 } 2040 }
2041#endif
1974 else if (NILP (on)) 2042 else if (NILP (on))
1975 [NSApp unhide: NSApp]; 2043 [NSApp unhide: NSApp];
1976 else 2044 else
diff --git a/src/nsfont.m b/src/nsfont.m
index 5a9cdfebc01..b3224629f05 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -1,4 +1,4 @@
1/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. 1/* Font back-end driver for the GNUstep window system.
2 See font.h 2 See font.h
3 Copyright (C) 2006-2021 Free Software Foundation, Inc. 3 Copyright (C) 2006-2021 Free Software Foundation, Inc.
4 4
@@ -38,47 +38,269 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
38#include "termchar.h" 38#include "termchar.h"
39#include "pdumper.h" 39#include "pdumper.h"
40 40
41/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ 41#import <Foundation/NSException.h>
42#import <AppKit/NSFontDescriptor.h> 42#import <AppKit/NSFontDescriptor.h>
43#import <AppKit/NSLayoutManager.h>
44#import <GNUstepGUI/GSLayoutManager.h>
45#import <GNUstepGUI/GSFontInfo.h>
43 46
44#define NSFONT_TRACE 0 47#define NSFONT_TRACE 0
45#define LCD_SMOOTHING_MARGIN 2
46 48
47/* Font glyph and metrics caching functions, implemented at end. */ 49/* Structure used by GS `shape' functions for storing layout
48static void ns_uni_to_glyphs (struct nsfont_info *font_info, 50 information for each glyph. Borrowed from macfont.h. */
49 unsigned char block); 51struct ns_glyph_layout
50static void ns_glyph_metrics (struct nsfont_info *font_info, 52{
51 unsigned char block); 53 /* Range of indices of the characters composed into the group of
54 glyphs that share the cursor position with this glyph. The
55 members `location' and `length' are in UTF-16 indices. */
56 NSRange comp_range;
52 57
53#define INVALID_GLYPH 0xFFFF 58 /* UTF-16 index in the source string for the first character
59 associated with this glyph. */
60 NSUInteger string_index;
54 61
55/* ========================================================================== 62 /* Horizontal and vertical adjustments of glyph position. The
63 coordinate space is that of Core Text. So, the `baseline_delta'
64 value is negative if the glyph should be placed below the
65 baseline. */
66 CGFloat advance_delta, baseline_delta;
56 67
57 Utilities 68 /* Typographical width of the glyph. */
69 CGFloat advance;
58 70
59 ========================================================================== */ 71 /* Glyph ID of the glyph. */
72 NSGlyph glyph_id;
73};
74
75
76enum lgstring_direction
77 {
78 DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1
79 };
80
81enum gs_font_slant
82 {
83 GS_FONT_SLANT_ITALIC,
84 GS_FONT_SLANT_REVERSE_ITALIC,
85 GS_FONT_SLANT_NORMAL
86 };
87
88enum gs_font_weight
89 {
90 GS_FONT_WEIGHT_LIGHT,
91 GS_FONT_WEIGHT_BOLD,
92 GS_FONT_WEIGHT_NORMAL
93 };
94
95enum gs_font_width
96 {
97 GS_FONT_WIDTH_CONDENSED,
98 GS_FONT_WIDTH_EXPANDED,
99 GS_FONT_WIDTH_NORMAL
100 };
101
102enum gs_specified
103 {
104 GS_SPECIFIED_SLANT = 1,
105 GS_SPECIFIED_WEIGHT = 1 << 1,
106 GS_SPECIFIED_WIDTH = 1 << 2,
107 GS_SPECIFIED_FAMILY = 1 << 3,
108 GS_SPECIFIED_SPACING = 1 << 4
109 };
60 110
111struct gs_font_data
112{
113 int specified;
114 enum gs_font_slant slant;
115 enum gs_font_weight weight;
116 enum gs_font_width width;
117 bool monospace_p;
118 char *family_name;
119};
61 120
62/* Replace spaces w/another character so emacs core font parsing routines
63 aren't thrown off. */
64static void 121static void
65ns_escape_name (char *name) 122ns_done_font_data (struct gs_font_data *data)
66{ 123{
67 for (; *name; name++) 124 if (data->specified & GS_SPECIFIED_FAMILY)
68 if (*name == ' ') 125 xfree (data->family_name);
69 *name = '_';
70} 126}
71 127
72
73/* Reconstruct spaces in a font family name passed through emacs. */
74static void 128static void
75ns_unescape_name (char *name) 129ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat)
76{ 130{
77 for (; *name; name++) 131 NSNumber *tem;
78 if (*name == '_') 132 NSFontSymbolicTraits traits = [desc symbolicTraits];
79 *name = ' '; 133 NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute];
134 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
135
136 dat->specified = 0;
137
138 if (family != nil)
139 {
140 dat->specified |= GS_SPECIFIED_FAMILY;
141 dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]);
142 }
143
144 tem = [desc objectForKey: NSFontFixedAdvanceAttribute];
145
146 if ((tem != nil && [tem boolValue] != NO)
147 || (traits & NSFontMonoSpaceTrait))
148 {
149 dat->specified |= GS_SPECIFIED_SPACING;
150 dat->monospace_p = true;
151 }
152 else if (tem != nil && [tem boolValue] == NO)
153 {
154 dat->specified |= GS_SPECIFIED_SPACING;
155 dat->monospace_p = false;
156 }
157
158 if (traits & NSFontBoldTrait)
159 {
160 dat->specified |= GS_SPECIFIED_WEIGHT;
161 dat->weight = GS_FONT_WEIGHT_BOLD;
162 }
163
164 if (traits & NSFontItalicTrait)
165 {
166 dat->specified |= GS_SPECIFIED_SLANT;
167 dat->slant = GS_FONT_SLANT_ITALIC;
168 }
169
170 if (traits & NSFontCondensedTrait)
171 {
172 dat->specified |= GS_SPECIFIED_WIDTH;
173 dat->width = GS_FONT_WIDTH_CONDENSED;
174 }
175 else if (traits & NSFontExpandedTrait)
176 {
177 dat->specified |= GS_SPECIFIED_WIDTH;
178 dat->width = GS_FONT_WIDTH_EXPANDED;
179 }
180
181 if (dict != nil)
182 {
183 tem = [dict objectForKey: NSFontSlantTrait];
184
185 if (tem != nil)
186 {
187 dat->specified |= GS_SPECIFIED_SLANT;
188
189 dat->slant = [tem floatValue] > 0
190 ? GS_FONT_SLANT_ITALIC
191 : ([tem floatValue] < 0
192 ? GS_FONT_SLANT_REVERSE_ITALIC
193 : GS_FONT_SLANT_NORMAL);
194 }
195
196 tem = [dict objectForKey: NSFontWeightTrait];
197
198 if (tem != nil)
199 {
200 dat->specified |= GS_SPECIFIED_WEIGHT;
201
202 dat->weight = [tem floatValue] > 0
203 ? GS_FONT_WEIGHT_BOLD
204 : ([tem floatValue] < -0.4f
205 ? GS_FONT_WEIGHT_LIGHT
206 : GS_FONT_WEIGHT_NORMAL);
207 }
208
209 tem = [dict objectForKey: NSFontWidthTrait];
210
211 if (tem != nil)
212 {
213 dat->specified |= GS_SPECIFIED_WIDTH;
214
215 dat->width = [tem floatValue] > 0
216 ? GS_FONT_WIDTH_EXPANDED
217 : ([tem floatValue] < 0
218 ? GS_FONT_WIDTH_NORMAL
219 : GS_FONT_WIDTH_CONDENSED);
220 }
221 }
222}
223
224static bool
225ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target)
226{
227 struct gs_font_data dat;
228 struct gs_font_data t;
229
230 ns_get_font_data (desc, &dat);
231 ns_get_font_data (target, &t);
232
233 if (!(t.specified & GS_SPECIFIED_WIDTH))
234 t.width = GS_FONT_WIDTH_NORMAL;
235 if (!(t.specified & GS_SPECIFIED_WEIGHT))
236 t.weight = GS_FONT_WEIGHT_NORMAL;
237 if (!(t.specified & GS_SPECIFIED_SPACING))
238 t.monospace_p = false;
239 if (!(t.specified & GS_SPECIFIED_SLANT))
240 t.slant = GS_FONT_SLANT_NORMAL;
241
242 if (!(t.specified & GS_SPECIFIED_FAMILY))
243 emacs_abort ();
244
245 bool match_p = true;
246
247 if (dat.specified & GS_SPECIFIED_WIDTH
248 && dat.width != t.width)
249 {
250 match_p = false;
251 goto gout;
252 }
253
254 if (dat.specified & GS_SPECIFIED_WEIGHT
255 && dat.weight != t.weight)
256 {
257 match_p = false;
258 goto gout;
259 }
260
261 if (dat.specified & GS_SPECIFIED_SPACING
262 && dat.monospace_p != t.monospace_p)
263 {
264 match_p = false;
265 goto gout;
266 }
267
268 if (dat.specified & GS_SPECIFIED_SLANT
269 && dat.monospace_p != t.monospace_p)
270 {
271 if (NSFONT_TRACE)
272 printf ("Matching monospace for %s: %d %d\n",
273 t.family_name, dat.monospace_p,
274 t.monospace_p);
275 match_p = false;
276 goto gout;
277 }
278
279 if (dat.specified & GS_SPECIFIED_FAMILY
280 && strcmp (dat.family_name, t.family_name))
281 match_p = false;
282
283 gout:
284 ns_done_font_data (&dat);
285 ns_done_font_data (&t);
286
287 return match_p;
80} 288}
81 289
290/* Font glyph and metrics caching functions, implemented at end. */
291static void ns_uni_to_glyphs (struct nsfont_info *font_info,
292 unsigned char block);
293static void ns_glyph_metrics (struct nsfont_info *font_info,
294 unsigned int block);
295
296#define INVALID_GLYPH 0xFFFF
297
298/* ==========================================================================
299
300 Utilities
301
302 ========================================================================== */
303
82 304
83/* Extract family name from a font spec. */ 305/* Extract family name from a font spec. */
84static NSString * 306static NSString *
@@ -91,66 +313,116 @@ ns_get_family (Lisp_Object font_spec)
91 { 313 {
92 char *tmp = xlispstrdup (SYMBOL_NAME (tem)); 314 char *tmp = xlispstrdup (SYMBOL_NAME (tem));
93 NSString *family; 315 NSString *family;
94 ns_unescape_name (tmp);
95 family = [NSString stringWithUTF8String: tmp]; 316 family = [NSString stringWithUTF8String: tmp];
96 xfree (tmp); 317 xfree (tmp);
97 return family; 318 return family;
98 } 319 }
99} 320}
100 321
101
102/* Return 0 if attr not set, else value (which might also be 0).
103 On Leopard 0 gets returned even on descriptors where the attribute
104 was never set, so there's no way to distinguish between unspecified
105 and set to not have. Callers should assume 0 means unspecified. */
106static float
107ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
108{
109 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
110 NSNumber *val = [tdict objectForKey: trait];
111 return val == nil ? 0.0F : [val floatValue];
112}
113
114
115/* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang 322/* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
116 to NSFont descriptor. Information under extra only needed for matching. */ 323 to NSFont descriptor. Information under extra only needed for matching. */
117#define STYLE_REF 100
118static NSFontDescriptor * 324static NSFontDescriptor *
119ns_spec_to_descriptor (Lisp_Object font_spec) 325ns_spec_to_descriptor (Lisp_Object font_spec)
120{ 326{
121 NSFontDescriptor *fdesc; 327 NSFontDescriptor *fdesc;
122 NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; 328 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
123 NSMutableDictionary *tdict = [NSMutableDictionary new];
124 NSString *family = ns_get_family (font_spec); 329 NSString *family = ns_get_family (font_spec);
125 float n; 330 NSMutableDictionary *tdict = [NSMutableDictionary new];
126
127 /* Add each attr in font_spec to fdAttrs. */
128 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
129 if (n != -1 && n != STYLE_REF)
130 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
131 forKey: NSFontWeightTrait];
132 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
133 if (n != -1 && n != STYLE_REF)
134 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
135 forKey: NSFontSlantTrait];
136 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
137 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
138 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
139 forKey: NSFontWidthTrait];
140 if ([tdict count] > 0)
141 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
142 331
143 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] 332 Lisp_Object tem;
144 retain] autorelease]; 333
334 tem = FONT_SLANT_SYMBOLIC (font_spec);
335 if (!NILP (tem))
336 {
337 if (EQ (tem, Qitalic) || EQ (tem, Qoblique))
338 [tdict setObject: [NSNumber numberWithFloat: 1.0]
339 forKey: NSFontSlantTrait];
340 else if (EQ (tem, intern ("reverse-italic")) ||
341 EQ (tem, intern ("reverse-oblique")))
342 [tdict setObject: [NSNumber numberWithFloat: -1.0]
343 forKey: NSFontSlantTrait];
344 else
345 [tdict setObject: [NSNumber numberWithFloat: 0.0]
346 forKey: NSFontSlantTrait];
347 }
348
349 tem = FONT_WIDTH_SYMBOLIC (font_spec);
350 if (!NILP (tem))
351 {
352 if (EQ (tem, Qcondensed))
353 [tdict setObject: [NSNumber numberWithFloat: -1.0]
354 forKey: NSFontWidthTrait];
355 else if (EQ (tem, Qexpanded))
356 [tdict setObject: [NSNumber numberWithFloat: 1.0]
357 forKey: NSFontWidthTrait];
358 else
359 [tdict setObject: [NSNumber numberWithFloat: 0.0]
360 forKey: NSFontWidthTrait];
361 }
362
363 tem = FONT_WEIGHT_SYMBOLIC (font_spec);
364
365 if (!NILP (tem))
366 {
367 if (EQ (tem, Qbold))
368 {
369 [tdict setObject: [NSNumber numberWithFloat: 1.0]
370 forKey: NSFontWeightTrait];
371 }
372 else if (EQ (tem, Qlight))
373 {
374 [tdict setObject: [NSNumber numberWithFloat: -1.0]
375 forKey: NSFontWeightTrait];
376 }
377 else
378 {
379 [tdict setObject: [NSNumber numberWithFloat: 0.0]
380 forKey: NSFontWeightTrait];
381 }
382 }
383
384 tem = AREF (font_spec, FONT_SPACING_INDEX);
145 385
146 if (family != nil) 386 if (family != nil)
147 { 387 {
148 NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; 388 [fdAttrs setObject: family
149 fdesc = [[fdesc2 retain] autorelease]; 389 forKey: NSFontFamilyAttribute];
150 } 390 }
151 391
152 [fdAttrs release]; 392 if (FIXNUMP (tem))
393 {
394 if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL)
395 {
396 [fdAttrs setObject: [NSNumber numberWithBool:YES]
397 forKey: NSFontFixedAdvanceAttribute];
398 }
399 else
400 {
401 [fdAttrs setObject: [NSNumber numberWithBool:NO]
402 forKey: NSFontFixedAdvanceAttribute];
403 }
404 }
405
406 /* Handle special families such as ``fixed'' or ``Sans Serif''. */
407
408 if ([family isEqualToString: @"fixed"])
409 {
410 [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName]
411 forKey: NSFontFamilyAttribute];
412 }
413 else if ([family isEqualToString: @"Sans Serif"])
414 {
415 [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName]
416 forKey: NSFontFamilyAttribute];
417 }
418
419 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
420
421 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
422 retain] autorelease];
423
153 [tdict release]; 424 [tdict release];
425 [fdAttrs release];
154 return fdesc; 426 return fdesc;
155} 427}
156 428
@@ -161,61 +433,64 @@ ns_descriptor_to_entity (NSFontDescriptor *desc,
161 Lisp_Object extra, 433 Lisp_Object extra,
162 const char *style) 434 const char *style)
163{ 435{
164 Lisp_Object font_entity = font_make_entity (); 436 Lisp_Object font_entity = font_make_entity ();
165 /* NSString *psName = [desc postscriptName]; */ 437 struct gs_font_data data;
166 NSString *family = [desc objectForKey: NSFontFamilyAttribute]; 438 ns_get_font_data (desc, &data);
167 unsigned int traits = [desc symbolicTraits]; 439
168 char *escapedFamily; 440 ASET (font_entity, FONT_TYPE_INDEX, Qns);
169 441 ASET (font_entity, FONT_FOUNDRY_INDEX, Qns);
170 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ 442 if (data.specified & GS_SPECIFIED_FAMILY)
171 if (family == nil) 443 ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name));
172 family = [desc objectForKey: NSFontNameAttribute]; 444 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
173 if (family == nil) 445 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
174 family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; 446
175 447 if (data.specified & GS_SPECIFIED_WEIGHT)
176 escapedFamily = xstrdup ([family UTF8String]); 448 {
177 ns_escape_name (escapedFamily); 449 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
178 450 data.weight == GS_FONT_WEIGHT_BOLD
179 ASET (font_entity, FONT_TYPE_INDEX, Qns); 451 ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT
180 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); 452 ? Qlight : Qnormal));
181 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); 453 }
182 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); 454 else
183 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); 455 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal);
184
185 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
186 traits & NSFontBoldTrait ? Qbold : Qmedium);
187/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
188 make_fixnum (100 + 100
189 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
190 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
191 traits & NSFontItalicTrait ? Qitalic : Qnormal);
192/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
193 make_fixnum (100 + 100
194 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
195 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
196 traits & NSFontCondensedTrait ? Qcondensed :
197 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
198/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199 make_fixnum (100 + 100
200 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
201
202 ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
203 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
204 ASET (font_entity, FONT_SPACING_INDEX,
205 make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait
206 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
207
208 ASET (font_entity, FONT_EXTRA_INDEX, extra);
209 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
210 456
211 if (NSFONT_TRACE) 457 if (data.specified & GS_SPECIFIED_SLANT)
212 { 458 {
213 fputs ("created font_entity:\n ", stderr); 459 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
214 debug_print (font_entity); 460 data.slant == GS_FONT_SLANT_ITALIC
215 } 461 ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC
462 ? intern ("reverse-italic") : Qnormal));
463 }
464 else
465 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal);
466
467 if (data.specified & GS_SPECIFIED_WIDTH)
468 {
469 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
470 data.width == GS_FONT_WIDTH_CONDENSED
471 ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED
472 ? intern ("expanded") : Qnormal));
473 }
474 else
475 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal);
216 476
217 xfree (escapedFamily); 477 ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
218 return font_entity; 478 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
479 ASET (font_entity, FONT_SPACING_INDEX,
480 make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p)
481 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
482
483 ASET (font_entity, FONT_EXTRA_INDEX, extra);
484 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
485
486 if (NSFONT_TRACE)
487 {
488 fputs ("created font_entity:\n ", stderr);
489 debug_print (font_entity);
490 }
491
492 ns_done_font_data (&data);
493 return font_entity;
219} 494}
220 495
221 496
@@ -223,8 +498,7 @@ ns_descriptor_to_entity (NSFontDescriptor *desc,
223static Lisp_Object 498static Lisp_Object
224ns_fallback_entity (void) 499ns_fallback_entity (void)
225{ 500{
226 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] 501 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL);
227 fontDescriptor], Qnil, NULL);
228} 502}
229 503
230 504
@@ -510,21 +784,20 @@ static NSSet
510 return families; 784 return families;
511} 785}
512 786
787/* GNUstep font matching is very mediocre (it can't even compare
788 symbolic styles correctly), which is why our own font matching
789 mechanism must be implemented. */
513 790
514/* Implementation for list() and match(). List() can return nil, match() 791/* Implementation for list and match. */
515must return something. Strategy is to drop family name from attribute
516matching set for match. */
517static Lisp_Object 792static Lisp_Object
518ns_findfonts (Lisp_Object font_spec, BOOL isMatch) 793ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
519{ 794{
520 Lisp_Object tem, list = Qnil; 795 Lisp_Object tem, list = Qnil;
521 NSFontDescriptor *fdesc, *desc; 796 NSFontDescriptor *fdesc;
522 NSMutableSet *fkeys; 797 NSArray *all_descs;
523 NSArray *matchingDescs; 798 GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator];
524 NSEnumerator *dEnum; 799
525 NSString *family;
526 NSSet *cFamilies; 800 NSSet *cFamilies;
527 BOOL foundItal = NO;
528 801
529 block_input (); 802 block_input ();
530 if (NSFONT_TRACE) 803 if (NSFONT_TRACE)
@@ -537,43 +810,22 @@ ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
537 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); 810 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
538 811
539 fdesc = ns_spec_to_descriptor (font_spec); 812 fdesc = ns_spec_to_descriptor (font_spec);
540 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; 813 all_descs = [enumerator availableFontDescriptors];
541 if (isMatch)
542 [fkeys removeObject: NSFontFamilyAttribute];
543
544 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
545 814
546 if (NSFONT_TRACE) 815 for (NSFontDescriptor *desc in all_descs)
547 NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
548 (unsigned long)[matchingDescs count]);
549
550 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
551 { 816 {
552 if (![cFamilies containsObject: 817 if (![cFamilies containsObject:
553 [desc objectForKey: NSFontFamilyAttribute]]) 818 [desc objectForKey: NSFontFamilyAttribute]])
554 continue; 819 continue;
820 if (!ns_font_descs_match_p (fdesc, desc))
821 continue;
822
555 tem = ns_descriptor_to_entity (desc, 823 tem = ns_descriptor_to_entity (desc,
556 AREF (font_spec, FONT_EXTRA_INDEX), 824 AREF (font_spec, FONT_EXTRA_INDEX),
557 NULL); 825 NULL);
558 if (isMatch) 826 if (isMatch)
559 return tem; 827 return tem;
560 list = Fcons (tem, list); 828 list = Fcons (tem, list);
561 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
562 foundItal = YES;
563 }
564
565 /* Add synthItal member if needed. */
566 family = [fdesc objectForKey: NSFontFamilyAttribute];
567 if (family != nil && !foundItal && !NILP (list))
568 {
569 NSFontDescriptor *s1 = [NSFontDescriptor new];
570 NSFontDescriptor *sDesc
571 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
572 fontDescriptorWithFamily: family];
573 list = Fcons (ns_descriptor_to_entity (sDesc,
574 AREF (font_spec, FONT_EXTRA_INDEX),
575 "synthItal"), list);
576 [s1 release];
577 } 829 }
578 830
579 unblock_input (); 831 unblock_input ();
@@ -652,7 +904,6 @@ nsfont_list_family (struct frame *f)
652 objectEnumerator]; 904 objectEnumerator];
653 while ((family = [families nextObject])) 905 while ((family = [families nextObject]))
654 list = Fcons (intern ([family UTF8String]), list); 906 list = Fcons (intern ([family UTF8String]), list);
655 /* FIXME: escape the name? */
656 907
657 if (NSFONT_TRACE) 908 if (NSFONT_TRACE)
658 fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", 909 fprintf (stderr, "nsfont: list families returning %"pD"d entries\n",
@@ -668,18 +919,15 @@ nsfont_list_family (struct frame *f)
668static Lisp_Object 919static Lisp_Object
669nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) 920nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
670{ 921{
671 BOOL synthItal;
672 unsigned int traits = 0;
673 struct nsfont_info *font_info; 922 struct nsfont_info *font_info;
674 struct font *font; 923 struct font *font;
675 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); 924 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
676 NSFontManager *fontMgr = [NSFontManager sharedFontManager]; 925 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
677 NSString *family; 926 NSString *family;
678 NSFont *nsfont, *sfont; 927 NSFont *nsfont, *sfont;
679 Lisp_Object tem;
680 NSRect brect; 928 NSRect brect;
681 Lisp_Object font_object; 929 Lisp_Object font_object;
682 int fixLeopardBug; 930 Lisp_Object tem;
683 931
684 block_input (); 932 block_input ();
685 933
@@ -692,42 +940,20 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
692 if (pixel_size <= 0) 940 if (pixel_size <= 0)
693 { 941 {
694 /* try to get it out of frame params */ 942 /* try to get it out of frame params */
695 Lisp_Object tem = get_frame_param (f, Qfontsize); 943 tem = get_frame_param (f, Qfontsize);
696 pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); 944 pixel_size = NILP (tem) ? 0 : XFIXNAT (tem);
697 } 945 }
698 946
699 tem = AREF (font_entity, FONT_ADSTYLE_INDEX); 947 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
700 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
701 9);
702 family = ns_get_family (font_entity); 948 family = ns_get_family (font_entity);
703 if (family == nil) 949 if (family == nil)
704 family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; 950 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
705 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that 951
706 when setting family in ns_spec_to_descriptor(). */ 952 nsfont = [NSFont fontWithDescriptor: fontDesc
707 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) 953 size: pixel_size];
708 traits |= NSBoldFontMask;
709 if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F)
710 traits |= NSItalicFontMask;
711
712 /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */
713 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
714 nsfont = [fontMgr fontWithFamily: family
715 traits: traits weight: fixLeopardBug
716 size: pixel_size];
717 /* if didn't find, try synthetic italic */
718 if (nsfont == nil && synthItal)
719 {
720 nsfont = [fontMgr fontWithFamily: family
721 traits: traits & ~NSItalicFontMask
722 weight: fixLeopardBug size: pixel_size];
723 }
724 954
725 if (nsfont == nil) 955 if (nsfont == nil)
726 { 956 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
727 message_with_string ("*** Warning: font in family `%s' not found",
728 build_string ([family UTF8String]), 1);
729 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
730 }
731 957
732 if (NSFONT_TRACE) 958 if (NSFONT_TRACE)
733 NSLog (@"%@\n", nsfont); 959 NSLog (@"%@\n", nsfont);
@@ -740,7 +966,7 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
740 if (!font) 966 if (!font)
741 { 967 {
742 unblock_input (); 968 unblock_input ();
743 return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ 969 return Qnil;
744 } 970 }
745 971
746 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); 972 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
@@ -781,7 +1007,7 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
781 font_info->name = xstrdup (fontName); 1007 font_info->name = xstrdup (fontName);
782 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; 1008 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
783 font_info->ital = 1009 font_info->ital =
784 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); 1010 ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
785 1011
786 /* Metrics etc.; some fonts return an unusually large max advance, so we 1012 /* Metrics etc.; some fonts return an unusually large max advance, so we
787 only use it for fonts that have wide characters. */ 1013 only use it for fonts that have wide characters. */
@@ -808,8 +1034,6 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
808 lrint (brect.size.width - (CGFloat) font_info->width); 1034 lrint (brect.size.width - (CGFloat) font_info->width);
809 1035
810 /* set up metrics portion of font struct */ 1036 /* set up metrics portion of font struct */
811 font->ascent = lrint([sfont ascender]);
812 font->descent = -lrint(floor(adjusted_descender));
813 font->space_width = lrint (ns_char_width (sfont, ' ')); 1037 font->space_width = lrint (ns_char_width (sfont, ' '));
814 font->max_width = lrint (font_info->max_bounds.width); 1038 font->max_width = lrint (font_info->max_bounds.width);
815 font->min_width = font->space_width; /* Approximate. */ 1039 font->min_width = font->space_width; /* Approximate. */
@@ -871,7 +1095,7 @@ nsfont_encode_char (struct font *font, int c)
871{ 1095{
872 struct nsfont_info *font_info = (struct nsfont_info *)font; 1096 struct nsfont_info *font_info = (struct nsfont_info *)font;
873 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; 1097 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
874 unsigned short g; 1098 unsigned int g;
875 1099
876 if (c > 0xFFFF) 1100 if (c > 0xFFFF)
877 return FONT_INVALID_CODE; 1101 return FONT_INVALID_CODE;
@@ -934,51 +1158,23 @@ nsfont_text_extents (struct font *font, const unsigned int *code,
934static int 1158static int
935nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, 1159nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
936 bool with_background) 1160 bool with_background)
937/* NOTE: focus and clip must be set. */
938{ 1161{
939 static unsigned char cbuf[1024]; 1162 NSGlyph *c = alloca ((to - from) * sizeof *c);
940 unsigned char *c = cbuf; 1163
941#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
942 static CGFloat advances[1024];
943 CGFloat *adv = advances;
944#else
945 static float advances[1024];
946 float *adv = advances;
947#endif
948 struct face *face; 1164 struct face *face;
949 NSRect r; 1165 NSRect r;
950 struct nsfont_info *font; 1166 struct nsfont_info *font;
951 NSColor *col, *bgCol; 1167 NSColor *col;
952 unsigned *t = s->char2b; 1168 int len = to - from;
953 int i, len, flags;
954 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; 1169 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
955 1170
956 block_input (); 1171 block_input ();
957 1172
958 font = (struct nsfont_info *)s->face->font; 1173 font = (struct nsfont_info *) s->font;
959 if (font == NULL) 1174 if (font == NULL)
960 font = (struct nsfont_info *)FRAME_FONT (s->f); 1175 font = (struct nsfont_info *)FRAME_FONT (s->f);
961 1176
962 /* Select face based on input flags. */ 1177 face = s->face;
963 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
964 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
965 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
966 NS_DUMPGLYPH_NORMAL));
967
968 switch (flags)
969 {
970 case NS_DUMPGLYPH_CURSOR:
971 face = s->face;
972 break;
973 case NS_DUMPGLYPH_MOUSEFACE:
974 face = FACE_FROM_ID_OR_NULL (s->f,
975 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
976 if (!face)
977 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
978 break;
979 default:
980 face = s->face;
981 }
982 1178
983 r.origin.x = s->x; 1179 r.origin.x = s->x;
984 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) 1180 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
@@ -987,91 +1183,24 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
987 r.origin.y = s->y; 1183 r.origin.y = s->y;
988 r.size.height = FONT_HEIGHT (font); 1184 r.size.height = FONT_HEIGHT (font);
989 1185
990 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask 1186 for (int i = from; i < to; ++i)
991 NS to render the string, it will come out differently from the individual 1187 c[i] = s->char2b[i];
992 character widths added up because of layout processing. */
993 {
994 int cwidth, twidth = 0;
995 int hi, lo;
996 /* FIXME: composition: no vertical displacement is considered. */
997 t += from; /* advance into composition */
998 for (i = from; i < to; i++, t++)
999 {
1000 hi = (*t & 0xFF00) >> 8;
1001 lo = *t & 0x00FF;
1002 if (isComposite)
1003 {
1004 if (!s->first_glyph->u.cmp.automatic)
1005 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1006 else
1007 {
1008 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1009 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1010 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1011 cwidth = LGLYPH_WIDTH (glyph);
1012 else
1013 {
1014 cwidth = LGLYPH_WADJUST (glyph);
1015 *(adv-1) += LGLYPH_XOFF (glyph);
1016 }
1017 }
1018 }
1019 else
1020 {
1021 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1022 ns_glyph_metrics (font, hi);
1023 cwidth = font->metrics[hi][lo].width;
1024 }
1025 twidth += cwidth;
1026 *adv++ = cwidth;
1027 c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */
1028 }
1029 len = adv - advances;
1030 r.size.width = twidth;
1031 *c = 0;
1032 }
1033 1188
1034 /* Fill background if requested. */ 1189 /* Fill background if requested. */
1035 if (with_background && !isComposite) 1190 if (with_background && !isComposite)
1036 { 1191 {
1037 NSRect br = r; 1192 NSRect br = NSMakeRect (x, y - FONT_BASE (s->font),
1038 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); 1193 s->width, FONT_HEIGHT (s->font));
1039 int mbox_line_width = max (s->face->box_vertical_line_width, 0);
1040
1041 if (s->row->full_width_p)
1042 {
1043 if (br.origin.x <= fibw + 1 + mbox_line_width)
1044 {
1045 br.size.width += br.origin.x - mbox_line_width;
1046 br.origin.x = mbox_line_width;
1047 }
1048 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1049 <= fibw+1)
1050 br.size.width += fibw;
1051 }
1052 if (s->face->box == FACE_NO_BOX)
1053 {
1054 /* Expand unboxed top row over internal border. */
1055 if (br.origin.y <= fibw + 1 + mbox_line_width)
1056 {
1057 br.size.height += br.origin.y;
1058 br.origin.y = 0;
1059 }
1060 }
1061 else
1062 {
1063 int correction = abs (s->face->box_horizontal_line_width)+1;
1064 br.origin.y += correction;
1065 br.size.height -= 2*correction;
1066 correction = abs (s->face->box_vertical_line_width)+1;
1067 br.origin.x += correction;
1068 br.size.width -= 2*correction;
1069 }
1070 1194
1071 if (!s->face->stipple) 1195 if (!s->face->stipple)
1072 [(NS_FACE_BACKGROUND (face) != 0 1196 {
1073 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) 1197 if (s->hl != DRAW_CURSOR)
1074 : FRAME_BACKGROUND_COLOR (s->f)) set]; 1198 [(NS_FACE_BACKGROUND (face) != 0
1199 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1200 : FRAME_BACKGROUND_COLOR (s->f)) set];
1201 else
1202 [FRAME_CURSOR_COLOR (s->f) set];
1203 }
1075 else 1204 else
1076 { 1205 {
1077 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); 1206 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
@@ -1080,43 +1209,32 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1080 NSRectFill (br); 1209 NSRectFill (br);
1081 } 1210 }
1082 1211
1083
1084 /* set up for character rendering */ 1212 /* set up for character rendering */
1085 r.origin.y = y; 1213 r.origin.y = y;
1086 1214
1087 col = (NS_FACE_FOREGROUND (face) != 0 1215 if (s->hl == DRAW_CURSOR)
1088 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) 1216 col = FRAME_BACKGROUND_COLOR (s->f);
1089 : FRAME_FOREGROUND_COLOR (s->f)); 1217 else
1090 1218 col = (NS_FACE_FOREGROUND (face) != 0
1091 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil 1219 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1092 : (NS_FACE_BACKGROUND (face) != 0 1220 : FRAME_FOREGROUND_COLOR (s->f));
1093 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1094 : FRAME_BACKGROUND_COLOR (s->f)));
1095 1221
1096 /* render under GNUstep using DPS */ 1222 /* render under GNUstep using DPS */
1097 { 1223 {
1098 NSGraphicsContext *context = GSCurrentContext (); 1224 NSGraphicsContext *context = [NSGraphicsContext currentContext];
1099
1100 DPSgsave (context); 1225 DPSgsave (context);
1101 [font->nsfont set]; 1226 if (s->clip_head)
1102
1103 /* do erase if "foreground" mode */
1104 if (bgCol != nil)
1105 { 1227 {
1106 [bgCol set]; 1228 DPSrectclip (context, s->clip_head->x, 0,
1107 DPSmoveto (context, r.origin.x, r.origin.y); 1229 FRAME_PIXEL_WIDTH (s->f),
1108/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ 1230 FRAME_PIXEL_HEIGHT (s->f));
1109 DPSxshow (context, (const char *) cbuf, advances, len);
1110 DPSstroke (context);
1111 [col set];
1112/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1113 } 1231 }
1232 [font->nsfont set];
1114 1233
1115 [col set]; 1234 [col set];
1116 1235
1117 /* draw with DPSxshow () */
1118 DPSmoveto (context, r.origin.x, r.origin.y); 1236 DPSmoveto (context, r.origin.x, r.origin.y);
1119 DPSxshow (context, (const char *) cbuf, advances, len); 1237 GSShowGlyphs (context, c, len);
1120 DPSstroke (context); 1238 DPSstroke (context);
1121 1239
1122 DPSgrestore (context); 1240 DPSgrestore (context);
@@ -1126,6 +1244,360 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1126 return to-from; 1244 return to-from;
1127} 1245}
1128 1246
1247static NSUInteger
1248ns_font_shape (NSFont *font, NSString *string,
1249 struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len,
1250 enum lgstring_direction dir)
1251{
1252 NSUInteger i;
1253 NSUInteger result = 0;
1254 NSTextStorage *textStorage;
1255 NSLayoutManager *layoutManager;
1256 NSTextContainer *textContainer;
1257 NSUInteger stringLength;
1258 NSPoint spaceLocation;
1259 /* numberOfGlyphs can't actually be 0, but this pacifies GCC */
1260 NSUInteger used, numberOfGlyphs = 0;
1261
1262 textStorage = [[NSTextStorage alloc] initWithString:string];
1263 layoutManager = [[NSLayoutManager alloc] init];
1264 textContainer = [[NSTextContainer alloc] init];
1265
1266 /* Append a trailing space to measure baseline position. */
1267 [textStorage appendAttributedString:([[[NSAttributedString alloc]
1268 initWithString:@" "] autorelease])];
1269 [textStorage setFont:font];
1270 [textContainer setLineFragmentPadding:0];
1271
1272 [layoutManager addTextContainer:textContainer];
1273 [textContainer release];
1274 [textStorage addLayoutManager:layoutManager];
1275 [layoutManager release];
1276
1277 if (!(textStorage && layoutManager && textContainer))
1278 emacs_abort ();
1279
1280 stringLength = [string length];
1281
1282 /* Force layout. */
1283 (void) [layoutManager glyphRangeForTextContainer:textContainer];
1284
1285 spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
1286
1287 /* Remove the appended trailing space because otherwise it may
1288 generate a wrong result for a right-to-left text. */
1289 [textStorage beginEditing];
1290 [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
1291 [textStorage endEditing];
1292 (void) [layoutManager glyphRangeForTextContainer:textContainer];
1293
1294 i = 0;
1295 while (i < stringLength)
1296 {
1297 NSRange range;
1298 NSFont *fontInTextStorage =
1299 [textStorage attribute: NSFontAttributeName
1300 atIndex:i
1301 longestEffectiveRange: &range
1302 inRange: NSMakeRange (0, stringLength)];
1303
1304 if (!(fontInTextStorage == font
1305 || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
1306 break;
1307 i = NSMaxRange (range);
1308 }
1309 if (i < stringLength)
1310 /* Make the test `used <= glyph_len' below fail if textStorage
1311 contained some fonts other than the specified one. */
1312 used = glyph_len + 1;
1313 else
1314 {
1315 NSRange range = NSMakeRange (0, stringLength);
1316
1317 range = [layoutManager glyphRangeForCharacterRange:range
1318 actualCharacterRange:NULL];
1319 numberOfGlyphs = NSMaxRange (range);
1320 used = numberOfGlyphs;
1321 for (i = 0; i < numberOfGlyphs; i++)
1322 if ([layoutManager notShownAttributeForGlyphAtIndex:i])
1323 used--;
1324 }
1325
1326 if (0 < used && used <= glyph_len)
1327 {
1328 NSUInteger glyphIndex, prevGlyphIndex;
1329 NSUInteger *permutation;
1330 NSRange compRange, range;
1331 CGFloat totalAdvance;
1332
1333 glyphIndex = 0;
1334 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1335 glyphIndex++;
1336
1337 permutation = NULL;
1338#define RIGHT_TO_LEFT_P permutation
1339
1340 /* Fill the `comp_range' member of struct mac_glyph_layout, and
1341 setup a permutation for right-to-left text. */
1342 compRange = NSMakeRange (0, 0);
1343 for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
1344 range.length++)
1345 {
1346 struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
1347 NSUInteger characterIndex =
1348 [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
1349
1350 gl->string_index = characterIndex;
1351
1352 if (characterIndex >= NSMaxRange (compRange))
1353 {
1354 compRange.location = NSMaxRange (compRange);
1355 do
1356 {
1357 NSRange characterRange =
1358 [string
1359 rangeOfComposedCharacterSequenceAtIndex:characterIndex];
1360
1361 compRange.length =
1362 NSMaxRange (characterRange) - compRange.location;
1363 [layoutManager glyphRangeForCharacterRange:compRange
1364 actualCharacterRange:&characterRange];
1365 characterIndex = NSMaxRange (characterRange) - 1;
1366 }
1367 while (characterIndex >= NSMaxRange (compRange));
1368
1369 if (RIGHT_TO_LEFT_P)
1370 for (i = 0; i < range.length; i++)
1371 permutation[range.location + i] = NSMaxRange (range) - i - 1;
1372
1373 range = NSMakeRange (NSMaxRange (range), 0);
1374 }
1375
1376 gl->comp_range.location = compRange.location;
1377 gl->comp_range.length = compRange.length;
1378
1379 while (++glyphIndex < numberOfGlyphs)
1380 if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1381 break;
1382 }
1383 if (RIGHT_TO_LEFT_P)
1384 for (i = 0; i < range.length; i++)
1385 permutation[range.location + i] = NSMaxRange (range) - i - 1;
1386
1387 /* Then fill the remaining members. */
1388 glyphIndex = prevGlyphIndex = 0;
1389 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1390 glyphIndex++;
1391
1392 if (!RIGHT_TO_LEFT_P)
1393 totalAdvance = 0;
1394 else
1395 {
1396 NSUInteger nrects;
1397 NSRect *glyphRects =
1398 [layoutManager
1399 rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
1400 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1401 inTextContainer:textContainer rectCount:&nrects];
1402
1403 totalAdvance = NSMaxX (glyphRects[0]);
1404 }
1405
1406 for (i = 0; i < used; i++)
1407 {
1408 struct ns_glyph_layout *gl;
1409 NSPoint location;
1410 NSUInteger nextGlyphIndex;
1411 NSRange glyphRange;
1412 NSRect *glyphRects;
1413 NSUInteger nrects;
1414
1415 if (!RIGHT_TO_LEFT_P)
1416 gl = glyph_layouts + i;
1417 else
1418 {
1419 NSUInteger dest = permutation[i];
1420
1421 gl = glyph_layouts + dest;
1422 if (i < dest)
1423 {
1424 NSUInteger tmp = gl->string_index;
1425
1426 gl->string_index = glyph_layouts[i].string_index;
1427 glyph_layouts[i].string_index = tmp;
1428 }
1429 }
1430 gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex];
1431
1432 location = [layoutManager locationForGlyphAtIndex:glyphIndex];
1433 gl->baseline_delta = spaceLocation.y - location.y;
1434
1435 for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
1436 nextGlyphIndex++)
1437 if (![layoutManager
1438 notShownAttributeForGlyphAtIndex:nextGlyphIndex])
1439 break;
1440
1441 if (!RIGHT_TO_LEFT_P)
1442 {
1443 CGFloat maxX;
1444
1445 if (prevGlyphIndex == 0)
1446 glyphRange = NSMakeRange (0, nextGlyphIndex);
1447 else
1448 glyphRange = NSMakeRange (glyphIndex,
1449 nextGlyphIndex - glyphIndex);
1450 glyphRects =
1451 [layoutManager
1452 rectArrayForGlyphRange:glyphRange
1453 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1454 inTextContainer:textContainer rectCount:&nrects];
1455 maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
1456 gl->advance_delta = location.x - totalAdvance;
1457 gl->advance = maxX - totalAdvance;
1458 totalAdvance = maxX;
1459 }
1460 else
1461 {
1462 CGFloat minX;
1463
1464 if (nextGlyphIndex == numberOfGlyphs)
1465 glyphRange = NSMakeRange (prevGlyphIndex,
1466 numberOfGlyphs - prevGlyphIndex);
1467 else
1468 glyphRange = NSMakeRange (prevGlyphIndex,
1469 glyphIndex + 1 - prevGlyphIndex);
1470 glyphRects =
1471 [layoutManager
1472 rectArrayForGlyphRange:glyphRange
1473 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1474 inTextContainer:textContainer rectCount:&nrects];
1475 minX = min (NSMinX (glyphRects[0]), totalAdvance);
1476 gl->advance = totalAdvance - minX;
1477 totalAdvance = minX;
1478 gl->advance_delta = location.x - totalAdvance;
1479 }
1480
1481 prevGlyphIndex = glyphIndex + 1;
1482 glyphIndex = nextGlyphIndex;
1483 }
1484
1485 if (RIGHT_TO_LEFT_P)
1486 xfree (permutation);
1487
1488#undef RIGHT_TO_LEFT_P
1489
1490 result = used;
1491 }
1492 [textStorage release];
1493
1494 return result;
1495}
1496
1497static Lisp_Object
1498nsfont_shape (Lisp_Object lgstring, Lisp_Object direction)
1499{
1500 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
1501 struct nsfont_info *font_info = (struct nsfont_info *) font;
1502 struct ns_glyph_layout *glyph_layouts;
1503 NSFont *nsfont = font_info->nsfont;
1504 ptrdiff_t glyph_len, len, i;
1505 Lisp_Object tem;
1506 unichar *mb_buf;
1507 NSUInteger used;
1508
1509 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
1510 for (i = 0; i < glyph_len; ++i)
1511 {
1512 tem = LGSTRING_GLYPH (lgstring, i);
1513
1514 if (NILP (tem))
1515 break;
1516 }
1517
1518 len = i;
1519
1520 if (INT_MAX / 2 < len)
1521 memory_full (SIZE_MAX);
1522
1523 block_input ();
1524
1525 mb_buf = alloca (len * sizeof *mb_buf);
1526
1527 for (i = 0; i < len; ++i)
1528 {
1529 uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
1530 mb_buf[i] = (unichar) c;
1531 }
1532
1533 NSString *string = [NSString stringWithCharacters: mb_buf
1534 length: len];
1535 unblock_input ();
1536
1537 if (!string)
1538 return Qnil;
1539
1540 block_input ();
1541
1542 enum lgstring_direction dir = DIR_UNKNOWN;
1543
1544 if (EQ (direction, QL2R))
1545 dir = DIR_L2R;
1546 else if (EQ (direction, QR2L))
1547 dir = DIR_R2L;
1548 glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len);
1549 used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir);
1550
1551 for (i = 0; i < used; i++)
1552 {
1553 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
1554 struct ns_glyph_layout *gl = glyph_layouts + i;
1555 EMACS_INT from, to;
1556 struct font_metrics metrics;
1557
1558 if (NILP (lglyph))
1559 {
1560 lglyph = LGLYPH_NEW ();
1561 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
1562 }
1563
1564 from = gl->comp_range.location;
1565 LGLYPH_SET_FROM (lglyph, from);
1566
1567 to = gl->comp_range.location + gl->comp_range.length;
1568 LGLYPH_SET_TO (lglyph, to - 1);
1569
1570 /* LGLYPH_CHAR is used in `describe-char' for checking whether
1571 the composition is trivial. */
1572 {
1573 UTF32Char c;
1574
1575 if (mb_buf[gl->string_index] >= 0xD800
1576 && mb_buf[gl->string_index] < 0xDC00)
1577 c = (((mb_buf[gl->string_index] - 0xD800) << 10)
1578 + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000);
1579 else
1580 c = mb_buf[gl->string_index];
1581
1582 LGLYPH_SET_CHAR (lglyph, c);
1583 }
1584
1585 {
1586 unsigned long cc = gl->glyph_id;
1587 LGLYPH_SET_CODE (lglyph, cc);
1588 }
1589
1590 nsfont_text_extents (font, &gl->glyph_id, 1, &metrics);
1591 LGLYPH_SET_WIDTH (lglyph, metrics.width);
1592 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
1593 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
1594 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
1595 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
1596 }
1597 unblock_input ();
1598
1599 return make_fixnum (used);
1600}
1129 1601
1130 1602
1131/* ========================================================================== 1603/* ==========================================================================
@@ -1134,6 +1606,50 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1134 1606
1135 ========================================================================== */ 1607 ========================================================================== */
1136 1608
1609static NSGlyph
1610ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c)
1611{
1612 unichar characters[] = { c };
1613 NSString *string =
1614 [NSString stringWithCharacters: characters
1615 length: 1];
1616 NSDictionary *attributes =
1617 [NSDictionary dictionaryWithObjectsAndKeys:
1618 info->nsfont, NSFontAttributeName, nil];
1619 NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string
1620 attributes: attributes];
1621 NSTextContainer *text_container = [[NSTextContainer alloc] init];
1622 NSLayoutManager *manager = [[NSLayoutManager alloc] init];
1623
1624 [manager addTextContainer: text_container];
1625 [text_container release]; /* Retained by manager */
1626 [storage addLayoutManager: manager];
1627 [manager release]; /* Retained by storage */
1628
1629 NSFont *font_in_storage = [storage attribute: NSFontAttributeName
1630 atIndex:0
1631 effectiveRange: NULL];
1632 NSGlyph glyph = FONT_INVALID_CODE;
1633
1634 if ((font_in_storage == info->nsfont
1635 || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]]))
1636 {
1637 @try
1638 {
1639 glyph = [manager glyphAtIndex: 0];
1640 }
1641 @catch (NSException *e)
1642 {
1643 /* GNUstep bug? */
1644 glyph = 'X';
1645 }
1646 }
1647
1648 [storage release];
1649
1650 return glyph;
1651}
1652
1137/* Find and cache corresponding glyph codes for unicode values in given 1653/* Find and cache corresponding glyph codes for unicode values in given
1138 hi-byte block of 256. */ 1654 hi-byte block of 256. */
1139static void 1655static void
@@ -1141,7 +1657,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1141{ 1657{
1142 unichar *unichars = xmalloc (0x101 * sizeof (unichar)); 1658 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1143 unsigned int i, g, idx; 1659 unsigned int i, g, idx;
1144 unsigned short *glyphs; 1660 unsigned int *glyphs;
1145 1661
1146 if (NSFONT_TRACE) 1662 if (NSFONT_TRACE)
1147 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", 1663 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
@@ -1149,7 +1665,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1149 1665
1150 block_input (); 1666 block_input ();
1151 1667
1152 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); 1668 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int));
1153 if (!unichars || !(font_info->glyphs[block])) 1669 if (!unichars || !(font_info->glyphs[block]))
1154 emacs_abort (); 1670 emacs_abort ();
1155 1671
@@ -1166,7 +1682,8 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1166 for (i = 0; i < 0x100; i++, glyphs++) 1682 for (i = 0; i < 0x100; i++, glyphs++)
1167 { 1683 {
1168 g = unichars[i]; 1684 g = unichars[i];
1169 *glyphs = g; 1685 NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g);
1686 *glyphs = glyph;
1170 } 1687 }
1171 } 1688 }
1172 1689
@@ -1175,18 +1692,19 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1175} 1692}
1176 1693
1177 1694
1178/* Determine and cache metrics for corresponding glyph codes in given 1695/* Determine and cache metrics for glyphs in given hi-byte block of
1179 hi-byte block of 256. */ 1696 256. */
1180static void 1697static void
1181ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) 1698ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block)
1182{ 1699{
1183 unsigned int i, g; 1700 unsigned int i;
1701 NSGlyph g;
1184 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; 1702 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1185 NSFont *sfont; 1703 NSFont *sfont;
1186 struct font_metrics *metrics; 1704 struct font_metrics *metrics;
1187 1705
1188 if (NSFONT_TRACE) 1706 if (NSFONT_TRACE)
1189 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", 1707 fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n",
1190 font_info, block); 1708 font_info, block);
1191 1709
1192 /* not implemented yet (as of startup 0.18), so punt */ 1710 /* not implemented yet (as of startup 0.18), so punt */
@@ -1209,19 +1727,14 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1209 w = max ([sfont advancementForGlyph: g].width, 2.0); 1727 w = max ([sfont advancementForGlyph: g].width, 2.0);
1210 metrics->width = lrint (w); 1728 metrics->width = lrint (w);
1211 1729
1212 lb = r.origin.x; 1730 lb = NSMinX (r);
1213 rb = r.size.width - w; 1731 rb = NSMaxX (r);
1214 // Add to bearing for LCD smoothing. We don't know if it is there. 1732
1215 if (lb < 0) 1733 metrics->rbearing = lrint (rb);
1216 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); 1734 metrics->lbearing = lrint (lb);
1217 if (font_info->ital) 1735
1218 rb += (CGFloat) (0.22F * font_info->height); 1736 metrics->descent = NSMinY (r);
1219 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); 1737 metrics->ascent = NSMaxY (r);
1220
1221 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1222 /* lrint (hshrink * [sfont ascender] + expand * hd/2); */
1223 metrics->ascent = r.size.height - metrics->descent;
1224 /* -lrint (hshrink* [sfont descender] - expand * hd/2); */
1225 } 1738 }
1226 unblock_input (); 1739 unblock_input ();
1227} 1740}
@@ -1257,6 +1770,7 @@ struct font_driver const nsfont_driver =
1257 .has_char = nsfont_has_char, 1770 .has_char = nsfont_has_char,
1258 .encode_char = nsfont_encode_char, 1771 .encode_char = nsfont_encode_char,
1259 .text_extents = nsfont_text_extents, 1772 .text_extents = nsfont_text_extents,
1773 .shape = nsfont_shape,
1260 .draw = nsfont_draw, 1774 .draw = nsfont_draw,
1261 }; 1775 };
1262 1776
@@ -1265,7 +1779,6 @@ syms_of_nsfont (void)
1265{ 1779{
1266 DEFSYM (Qcondensed, "condensed"); 1780 DEFSYM (Qcondensed, "condensed");
1267 DEFSYM (Qexpanded, "expanded"); 1781 DEFSYM (Qexpanded, "expanded");
1268 DEFSYM (Qapple, "apple");
1269 DEFSYM (Qmedium, "medium"); 1782 DEFSYM (Qmedium, "medium");
1270 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, 1783 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1271 doc: /* Internal use: maps font registry to Unicode script. */); 1784 doc: /* Internal use: maps font registry to Unicode script. */);
diff --git a/src/nsimage.m b/src/nsimage.m
index 3c16cd371e6..dd2bb3b0d7b 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -265,16 +265,12 @@ ns_image_size_in_bytes (void *img)
265 image = [[EmacsImage alloc] initByReferencingFile:filename]; 265 image = [[EmacsImage alloc] initByReferencingFile:filename];
266 266
267 image->bmRep = nil; 267 image->bmRep = nil;
268#ifdef NS_IMPL_COCOA 268 if (![image isValid])
269 imgRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
270#else
271 imgRep = [image bestRepresentationForDevice: nil];
272#endif
273 if (imgRep == nil)
274 { 269 {
275 [image release]; 270 [image release];
276 return nil; 271 return nil;
277 } 272 }
273 imgRep = [[image representations] firstObject];
278 274
279 [image setSize: NSMakeSize([imgRep pixelsWide], [imgRep pixelsHigh])]; 275 [image setSize: NSMakeSize([imgRep pixelsWide], [imgRep pixelsHigh])];
280 [image setName:filename]; 276 [image setName:filename];
@@ -381,51 +377,10 @@ ns_image_size_in_bytes (void *img)
381 } 377 }
382 } 378 }
383 379
384 xbm_fg = fg;
385 [self addRepresentation: bmRep]; 380 [self addRepresentation: bmRep];
386 return self; 381 return self;
387} 382}
388 383
389/* Set color for a bitmap image. */
390- (instancetype)setXBMColor: (NSColor *)color
391{
392 NSSize s = [self size];
393 unsigned char *planes[5];
394 EmacsCGFloat r, g, b, a;
395 NSColor *rgbColor;
396
397 if (bmRep == nil || color == nil)
398 return self;
399
400 if ([color colorSpace] != [NSColorSpace genericRGBColorSpace])
401 rgbColor = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
402 else
403 rgbColor = color;
404
405 [rgbColor getRed: &r green: &g blue: &b alpha: &a];
406
407 [bmRep getBitmapDataPlanes: planes];
408
409 {
410 int i, len = s.width*s.height;
411 int rr = r * 0xff, gg = g * 0xff, bb = b * 0xff;
412 unsigned char fgr = (xbm_fg >> 16) & 0xff;
413 unsigned char fgg = (xbm_fg >> 8) & 0xff;
414 unsigned char fgb = xbm_fg & 0xff;
415
416 for (i = 0; i < len; ++i)
417 if (planes[0][i] == fgr && planes[1][i] == fgg && planes[2][i] == fgb)
418 {
419 planes[0][i] = rr;
420 planes[1][i] = gg;
421 planes[2][i] = bb;
422 }
423 xbm_fg = ((rr << 16) & 0xff0000) + ((gg << 8) & 0xff00) + (bb & 0xff);
424 }
425
426 return self;
427}
428
429 384
430- (instancetype)initForXPMWithDepth: (int)depth width: (int)width height: (int)height 385- (instancetype)initForXPMWithDepth: (int)depth width: (int)width height: (int)height
431{ 386{
diff --git a/src/nsmenu.m b/src/nsmenu.m
index 1b03fe91a8b..29201e69079 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -101,6 +101,15 @@ popup_activated (void)
101static void 101static void
102ns_update_menubar (struct frame *f, bool deep_p) 102ns_update_menubar (struct frame *f, bool deep_p)
103{ 103{
104#ifdef NS_IMPL_GNUSTEP
105 static int inside = 0;
106
107 if (inside)
108 return;
109
110 inside++;
111#endif
112
104 BOOL needsSet = NO; 113 BOOL needsSet = NO;
105 id menu = [NSApp mainMenu]; 114 id menu = [NSApp mainMenu];
106 bool owfi; 115 bool owfi;
@@ -120,7 +129,12 @@ ns_update_menubar (struct frame *f, bool deep_p)
120 NSTRACE ("ns_update_menubar"); 129 NSTRACE ("ns_update_menubar");
121 130
122 if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) 131 if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0)
132 {
133#ifdef NS_IMPL_GNUSTEP
134 inside--;
135#endif
123 return; 136 return;
137 }
124 XSETFRAME (Vmenu_updating_frame, f); 138 XSETFRAME (Vmenu_updating_frame, f);
125/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ 139/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
126 140
@@ -144,10 +158,6 @@ ns_update_menubar (struct frame *f, bool deep_p)
144 t = -(1000*tb.time+tb.millitm); 158 t = -(1000*tb.time+tb.millitm);
145#endif 159#endif
146 160
147#ifdef NS_IMPL_GNUSTEP
148 deep_p = 1; /* See comment in menuNeedsUpdate. */
149#endif
150
151 if (deep_p) 161 if (deep_p)
152 { 162 {
153 /* Make a widget-value tree representing the entire menu trees. */ 163 /* Make a widget-value tree representing the entire menu trees. */
@@ -275,6 +285,9 @@ ns_update_menubar (struct frame *f, bool deep_p)
275 free_menubar_widget_value_tree (first_wv); 285 free_menubar_widget_value_tree (first_wv);
276 discard_menu_items (); 286 discard_menu_items ();
277 unbind_to (specpdl_count, Qnil); 287 unbind_to (specpdl_count, Qnil);
288#ifdef NS_IMPL_GNUSTEP
289 inside--;
290#endif
278 return; 291 return;
279 } 292 }
280 293
@@ -408,6 +421,10 @@ ns_update_menubar (struct frame *f, bool deep_p)
408 if (needsSet) 421 if (needsSet)
409 [NSApp setMainMenu: menu]; 422 [NSApp setMainMenu: menu];
410 423
424#ifdef NS_IMPL_GNUSTEP
425 inside--;
426#endif
427
411 unblock_input (); 428 unblock_input ();
412 429
413} 430}
@@ -452,17 +469,34 @@ set_frame_menubar (struct frame *f, bool deep_p)
452 call to ns_update_menubar. */ 469 call to ns_update_menubar. */
453- (void)menuNeedsUpdate: (NSMenu *)menu 470- (void)menuNeedsUpdate: (NSMenu *)menu
454{ 471{
472#ifdef NS_IMPL_GNUSTEP
473 static int inside = 0;
474#endif
475
455 if (!FRAME_LIVE_P (SELECTED_FRAME ())) 476 if (!FRAME_LIVE_P (SELECTED_FRAME ()))
456 return; 477 return;
457 478
458#ifdef NS_IMPL_COCOA 479#ifdef NS_IMPL_GNUSTEP
459/* TODO: GNUstep calls this method when the menu is still being built 480 /* GNUstep calls this method when the menu is still being built
460 which results in a recursive stack overflow. One possible solution 481 which results in a recursive stack overflow, which this variable
461 is to use menuWillOpen instead, but the Apple docs explicitly warn 482 prevents. */
462 against changing the contents of the menu in it. I don't know what 483
463 the right thing to do for GNUstep is. */ 484 if (!inside)
485 ++inside;
486 else
487 return;
488#endif
489
464 if (needsUpdate) 490 if (needsUpdate)
465 ns_update_menubar (SELECTED_FRAME (), true); 491 {
492#ifdef NS_IMPL_GNUSTEP
493 needsUpdate = NO;
494#endif
495 ns_update_menubar (SELECTED_FRAME (), true);
496 }
497
498#ifdef NS_IMPL_GNUSTEP
499 --inside;
466#endif 500#endif
467} 501}
468 502
@@ -789,6 +823,9 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
789 823
790 p.x = x; p.y = y; 824 p.x = x; p.y = y;
791 825
826 /* Don't GC due to a mysterious bug. */
827 inhibit_garbage_collection ();
828
792 /* now parse stage 2 as in ns_update_menubar */ 829 /* now parse stage 2 as in ns_update_menubar */
793 wv = make_widget_value ("contextmenu", NULL, true, Qnil); 830 wv = make_widget_value ("contextmenu", NULL, true, Qnil);
794 wv->button_type = BUTTON_TYPE_NONE; 831 wv->button_type = BUTTON_TYPE_NONE;
@@ -959,16 +996,18 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
959 } 996 }
960 997
961 pmenu = [[EmacsMenu alloc] initWithTitle: 998 pmenu = [[EmacsMenu alloc] initWithTitle:
962 [NSString stringWithLispString: title]]; 999 NILP (title) ? @"" : [NSString stringWithLispString: title]];
1000 /* On GNUstep, this call makes menu_items nil for whatever reason
1001 when displaying a context menu from `context-menu-mode'. */
1002 Lisp_Object items = menu_items;
963 [pmenu fillWithWidgetValue: first_wv->contents]; 1003 [pmenu fillWithWidgetValue: first_wv->contents];
1004 menu_items = items;
964 free_menubar_widget_value_tree (first_wv); 1005 free_menubar_widget_value_tree (first_wv);
965 unbind_to (specpdl_count, Qnil);
966
967 popup_activated_flag = 1; 1006 popup_activated_flag = 1;
968 tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; 1007 tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
969 popup_activated_flag = 0; 1008 popup_activated_flag = 0;
970 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; 1009 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
971 1010 unbind_to (specpdl_count, Qnil);
972 unblock_input (); 1011 unblock_input ();
973 return tem; 1012 return tem;
974} 1013}
@@ -991,36 +1030,43 @@ free_frame_tool_bar (struct frame *f)
991 NSTRACE ("free_frame_tool_bar"); 1030 NSTRACE ("free_frame_tool_bar");
992 1031
993 block_input (); 1032 block_input ();
994 view->wait_for_tool_bar = NO;
995 1033
996 /* Note: This triggers an animation, which calls windowDidResize 1034 /* Note: This triggers an animation, which calls windowDidResize
997 repeatedly. */ 1035 repeatedly. */
998 f->output_data.ns->in_animation = 1; 1036 f->output_data.ns->in_animation = 1;
999 [[view toolbar] setVisible: NO]; 1037 [[[view window] toolbar] setVisible:NO];
1000 f->output_data.ns->in_animation = 0; 1038 f->output_data.ns->in_animation = 0;
1001 1039
1040 [[view window] setToolbar:nil];
1041
1002 unblock_input (); 1042 unblock_input ();
1003} 1043}
1004 1044
1005void 1045void
1006update_frame_tool_bar (struct frame *f) 1046update_frame_tool_bar_1 (struct frame *f, EmacsToolbar *toolbar)
1007/* -------------------------------------------------------------------------- 1047/* --------------------------------------------------------------------------
1008 Update toolbar contents. 1048 Update toolbar contents.
1009 -------------------------------------------------------------------------- */ 1049 -------------------------------------------------------------------------- */
1010{ 1050{
1011 int i, k = 0; 1051 int i, k = 0;
1012 EmacsView *view = FRAME_NS_VIEW (f);
1013 EmacsToolbar *toolbar = [view toolbar];
1014 1052
1015 NSTRACE ("update_frame_tool_bar"); 1053 NSTRACE ("update_frame_tool_bar");
1016 1054
1017 if (view == nil || toolbar == nil) return;
1018 block_input (); 1055 block_input ();
1019 1056
1020#ifdef NS_IMPL_COCOA 1057#ifdef NS_IMPL_COCOA
1021 [toolbar clearActive]; 1058 [toolbar clearActive];
1022#else 1059#else
1023 [toolbar clearAll]; 1060 [toolbar clearAll];
1061 /* It takes at least 3 such adjustments to fix an issue where the
1062 tool bar is 2x too tall when a frame's tool bar is first shown.
1063 This is ugly, but I have no other solution for this problem. */
1064 if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3)
1065 {
1066 [toolbar setVisible: NO];
1067 FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++;
1068 [toolbar setVisible: YES];
1069 }
1024#endif 1070#endif
1025 1071
1026 /* Update EmacsToolbar as in GtkUtils, build items list. */ 1072 /* Update EmacsToolbar as in GtkUtils, build items list. */
@@ -1034,6 +1080,8 @@ update_frame_tool_bar (struct frame *f)
1034 ptrdiff_t img_id; 1080 ptrdiff_t img_id;
1035 struct image *img; 1081 struct image *img;
1036 Lisp_Object image; 1082 Lisp_Object image;
1083 Lisp_Object labelObj;
1084 const char *labelText;
1037 Lisp_Object helpObj; 1085 Lisp_Object helpObj;
1038 const char *helpText; 1086 const char *helpText;
1039 1087
@@ -1060,6 +1108,8 @@ update_frame_tool_bar (struct frame *f)
1060 { 1108 {
1061 idx = -1; 1109 idx = -1;
1062 } 1110 }
1111 labelObj = TOOLPROP (TOOL_BAR_ITEM_LABEL);
1112 labelText = NILP (labelObj) ? "" : SSDATA (labelObj);
1063 helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP); 1113 helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
1064 if (NILP (helpObj)) 1114 if (NILP (helpObj))
1065 helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION); 1115 helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
@@ -1085,18 +1135,12 @@ update_frame_tool_bar (struct frame *f)
1085 [toolbar addDisplayItemWithImage: img->pixmap 1135 [toolbar addDisplayItemWithImage: img->pixmap
1086 idx: k++ 1136 idx: k++
1087 tag: i 1137 tag: i
1138 labelText: labelText
1088 helpText: helpText 1139 helpText: helpText
1089 enabled: enabled_p]; 1140 enabled: enabled_p];
1090#undef TOOLPROP 1141#undef TOOLPROP
1091 } 1142 }
1092 1143
1093 if (![toolbar isVisible])
1094 {
1095 f->output_data.ns->in_animation = 1;
1096 [toolbar setVisible: YES];
1097 f->output_data.ns->in_animation = 0;
1098 }
1099
1100#ifdef NS_IMPL_COCOA 1144#ifdef NS_IMPL_COCOA
1101 if ([toolbar changed]) 1145 if ([toolbar changed])
1102 { 1146 {
@@ -1121,13 +1165,25 @@ update_frame_tool_bar (struct frame *f)
1121 } 1165 }
1122#endif 1166#endif
1123 1167
1124 if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0) 1168 [toolbar setVisible:YES];
1169 unblock_input ();
1170}
1171
1172void
1173update_frame_tool_bar (struct frame *f)
1174{
1175 EmacsWindow *window = (EmacsWindow *)[FRAME_NS_VIEW (f) window];
1176 EmacsToolbar *toolbar = (EmacsToolbar *)[window toolbar];
1177
1178 if (!toolbar)
1125 { 1179 {
1126 view->wait_for_tool_bar = NO; 1180 [window createToolbar:f];
1127 [view setNeedsDisplay: YES]; 1181 return;
1128 } 1182 }
1129 1183
1130 unblock_input (); 1184 if (window == nil || toolbar == nil) return;
1185
1186 update_frame_tool_bar_1 (f, toolbar);
1131} 1187}
1132 1188
1133 1189
@@ -1196,6 +1252,7 @@ update_frame_tool_bar (struct frame *f)
1196- (void) addDisplayItemWithImage: (EmacsImage *)img 1252- (void) addDisplayItemWithImage: (EmacsImage *)img
1197 idx: (int)idx 1253 idx: (int)idx
1198 tag: (int)tag 1254 tag: (int)tag
1255 labelText: (const char *)label
1199 helpText: (const char *)help 1256 helpText: (const char *)help
1200 enabled: (BOOL)enabled 1257 enabled: (BOOL)enabled
1201{ 1258{
@@ -1213,6 +1270,7 @@ update_frame_tool_bar (struct frame *f)
1213 item = [[[NSToolbarItem alloc] initWithItemIdentifier: identifier] 1270 item = [[[NSToolbarItem alloc] initWithItemIdentifier: identifier]
1214 autorelease]; 1271 autorelease];
1215 [item setImage: img]; 1272 [item setImage: img];
1273 [item setLabel: [NSString stringWithUTF8String: label]];
1216 [item setToolTip: [NSString stringWithUTF8String: help]]; 1274 [item setToolTip: [NSString stringWithUTF8String: help]];
1217 [item setTarget: emacsView]; 1275 [item setTarget: emacsView];
1218 [item setAction: @selector (toolbarClicked:)]; 1276 [item setAction: @selector (toolbarClicked:)];
diff --git a/src/nsterm.h b/src/nsterm.h
index b29e76cc63f..8175f996644 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1,3 +1,4 @@
1/* -*- objc -*- */
1/* Definitions and headers for communication with NeXT/Open/GNUstep API. 2/* Definitions and headers for communication with NeXT/Open/GNUstep API.
2 Copyright (C) 1989, 1993, 2005, 2008-2021 Free Software Foundation, 3 Copyright (C) 1989, 1993, 2005, 2008-2021 Free Software Foundation,
3 Inc. 4 Inc.
@@ -348,16 +349,6 @@ typedef id instancetype;
348#endif 349#endif
349 350
350 351
351/* macOS 10.14 and above cannot draw directly "to the glass" and
352 therefore we draw to an offscreen buffer and swap it in when the
353 toolkit wants to draw the frame. GNUstep and macOS 10.7 and below
354 do not support this method, so we revert to drawing directly to the
355 glass. */
356#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
357#define NS_DRAW_TO_BUFFER 1
358#endif
359
360
361/* ========================================================================== 352/* ==========================================================================
362 353
363 NSColor, EmacsColor category. 354 NSColor, EmacsColor category.
@@ -416,6 +407,26 @@ typedef id instancetype;
416@end 407@end
417#endif 408#endif
418 409
410/* EmacsWindow */
411@interface EmacsWindow : NSWindow
412{
413 NSPoint grabOffset;
414}
415
416#ifdef NS_IMPL_GNUSTEP
417- (NSInteger) orderedIndex;
418#endif
419
420- (instancetype)initWithEmacsFrame:(struct frame *)f;
421- (instancetype)initWithEmacsFrame:(struct frame *)f fullscreen:(BOOL)fullscreen screen:(NSScreen *)screen;
422- (void)createToolbar:(struct frame *)f;
423- (void)setParentChildRelationships;
424- (NSInteger)borderWidth;
425- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above;
426- (void)setAppearance;
427@end
428
429
419/* ========================================================================== 430/* ==========================================================================
420 431
421 The main Emacs view 432 The main Emacs view
@@ -423,7 +434,7 @@ typedef id instancetype;
423 ========================================================================== */ 434 ========================================================================== */
424 435
425@class EmacsToolbar; 436@class EmacsToolbar;
426@class EmacsSurface; 437@class EmacsLayer;
427 438
428#ifdef NS_IMPL_COCOA 439#ifdef NS_IMPL_COCOA
429@interface EmacsView : NSView <NSTextInput, NSWindowDelegate> 440@interface EmacsView : NSView <NSTextInput, NSWindowDelegate>
@@ -439,19 +450,13 @@ typedef id instancetype;
439 NSString *workingText; 450 NSString *workingText;
440 BOOL processingCompose; 451 BOOL processingCompose;
441 int fs_state, fs_before_fs, next_maximized; 452 int fs_state, fs_before_fs, next_maximized;
442 int bwidth;
443 int maximized_width, maximized_height; 453 int maximized_width, maximized_height;
444 NSWindow *nonfs_window; 454 EmacsWindow *nonfs_window;
445 BOOL fs_is_native; 455 BOOL fs_is_native;
446#ifdef NS_DRAW_TO_BUFFER
447 EmacsSurface *surface;
448#endif
449@public 456@public
450 struct frame *emacsframe; 457 struct frame *emacsframe;
451 int scrollbarsNeedingUpdate; 458 int scrollbarsNeedingUpdate;
452 EmacsToolbar *toolbar;
453 NSRect ns_userRect; 459 NSRect ns_userRect;
454 BOOL wait_for_tool_bar;
455 } 460 }
456 461
457/* AppKit-side interface */ 462/* AppKit-side interface */
@@ -465,9 +470,7 @@ typedef id instancetype;
465 470
466/* Emacs-side interface */ 471/* Emacs-side interface */
467- (instancetype) initFrameFromEmacs: (struct frame *) f; 472- (instancetype) initFrameFromEmacs: (struct frame *) f;
468- (void) createToolbar: (struct frame *)f;
469- (void) setWindowClosing: (BOOL)closing; 473- (void) setWindowClosing: (BOOL)closing;
470- (EmacsToolbar *) toolbar;
471- (void) deleteWorkingText; 474- (void) deleteWorkingText;
472- (void) handleFS; 475- (void) handleFS;
473- (void) setFSValue: (int)value; 476- (void) setFSValue: (int)value;
@@ -483,11 +486,11 @@ typedef id instancetype;
483#endif 486#endif
484- (int)fullscreenState; 487- (int)fullscreenState;
485 488
486#ifdef NS_DRAW_TO_BUFFER 489#ifdef NS_IMPL_COCOA
487- (void)focusOnDrawingBuffer; 490- (void)lockFocus;
488- (void)unfocusDrawingBuffer; 491- (void)unlockFocus;
489#endif 492#endif
490- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect; 493- (void)copyRect:(NSRect)srcRect to:(NSPoint)dest;
491 494
492/* Non-notification versions of NSView methods. Used for direct calls. */ 495/* Non-notification versions of NSView methods. Used for direct calls. */
493- (void)windowWillEnterFullScreen; 496- (void)windowWillEnterFullScreen;
@@ -498,27 +501,6 @@ typedef id instancetype;
498@end 501@end
499 502
500 503
501/* Small utility used for processing resize events under Cocoa. */
502@interface EmacsWindow : NSWindow
503{
504 NSPoint grabOffset;
505}
506
507#ifdef NS_IMPL_GNUSTEP
508- (NSInteger) orderedIndex;
509#endif
510
511- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above;
512- (void)setAppearance;
513@end
514
515
516/* Fullscreen version of the above. */
517@interface EmacsFSWindow : EmacsWindow
518{
519}
520@end
521
522/* ========================================================================== 504/* ==========================================================================
523 505
524 The main menu implementation 506 The main menu implementation
@@ -568,6 +550,7 @@ typedef id instancetype;
568- (void) addDisplayItemWithImage: (EmacsImage *)img 550- (void) addDisplayItemWithImage: (EmacsImage *)img
569 idx: (int)idx 551 idx: (int)idx
570 tag: (int)tag 552 tag: (int)tag
553 labelText: (const char *)label
571 helpText: (const char *)help 554 helpText: (const char *)help
572 enabled: (BOOL)enabled; 555 enabled: (BOOL)enabled;
573 556
@@ -647,7 +630,6 @@ typedef id instancetype;
647 NSBitmapImageRep *bmRep; /* used for accessing pixel data */ 630 NSBitmapImageRep *bmRep; /* used for accessing pixel data */
648 unsigned char *pixmapData[5]; /* shortcut to access pixel data */ 631 unsigned char *pixmapData[5]; /* shortcut to access pixel data */
649 NSColor *stippleMask; 632 NSColor *stippleMask;
650 unsigned long xbm_fg;
651@public 633@public
652 NSAffineTransform *transform; 634 NSAffineTransform *transform;
653 BOOL smoothing; 635 BOOL smoothing;
@@ -657,7 +639,6 @@ typedef id instancetype;
657- (instancetype)initFromXBM: (unsigned char *)bits width: (int)w height: (int)h 639- (instancetype)initFromXBM: (unsigned char *)bits width: (int)w height: (int)h
658 fg: (unsigned long)fg bg: (unsigned long)bg 640 fg: (unsigned long)fg bg: (unsigned long)bg
659 reverseBytes: (BOOL)reverse; 641 reverseBytes: (BOOL)reverse;
660- (instancetype)setXBMColor: (NSColor *)color;
661- (instancetype)initForXPMWithDepth: (int)depth width: (int)width height: (int)height; 642- (instancetype)initForXPMWithDepth: (int)depth width: (int)width height: (int)height;
662- (void)setPixmapData; 643- (void)setPixmapData;
663- (unsigned long)getPixelAtX: (int)x Y: (int)y; 644- (unsigned long)getPixelAtX: (int)x Y: (int)y;
@@ -716,23 +697,17 @@ typedef id instancetype;
716+ (CGFloat)scrollerWidth; 697+ (CGFloat)scrollerWidth;
717@end 698@end
718 699
719#ifdef NS_DRAW_TO_BUFFER 700#ifdef NS_IMPL_COCOA
720@interface EmacsSurface : NSObject 701@interface EmacsLayer : CALayer
721{ 702{
722 NSMutableArray *cache; 703 NSMutableArray *cache;
723 NSSize size;
724 CGColorSpaceRef colorSpace; 704 CGColorSpaceRef colorSpace;
725 IOSurfaceRef currentSurface; 705 IOSurfaceRef currentSurface;
726 IOSurfaceRef lastSurface;
727 CGContextRef context; 706 CGContextRef context;
728 CGFloat scale;
729} 707}
730- (id) initWithSize: (NSSize)s ColorSpace: (CGColorSpaceRef)cs Scale: (CGFloat)scale; 708- (id) initWithColorSpace: (CGColorSpaceRef)cs;
731- (void) dealloc; 709- (void) setColorSpace: (CGColorSpaceRef)cs;
732- (NSSize) getSize;
733- (CGContextRef) getContext; 710- (CGContextRef) getContext;
734- (void) releaseContext;
735- (IOSurfaceRef) getSurface;
736@end 711@end
737#endif 712#endif
738 713
@@ -845,7 +820,7 @@ struct nsfont_info
845 XCharStruct max_bounds; 820 XCharStruct max_bounds;
846 /* We compute glyph codes and metrics on-demand in blocks of 256 indexed 821 /* We compute glyph codes and metrics on-demand in blocks of 256 indexed
847 by hibyte, lobyte. */ 822 by hibyte, lobyte. */
848 unsigned short **glyphs; /* map Unicode index to glyph */ 823 unsigned int **glyphs; /* map Unicode index to glyph */
849 struct font_metrics **metrics; 824 struct font_metrics **metrics;
850}; 825};
851#endif 826#endif
@@ -1003,6 +978,12 @@ struct ns_output
1003 978
1004 /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ 979 /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */
1005 int in_animation; 980 int in_animation;
981
982#ifdef NS_IMPL_GNUSTEP
983 /* Zero if this is the first time a toolbar has been updated on this
984 frame. */
985 int tool_bar_adjusted;
986#endif
1006}; 987};
1007 988
1008/* This dummy declaration needed to support TTYs. */ 989/* This dummy declaration needed to support TTYs. */
@@ -1161,6 +1142,7 @@ extern void ns_implicitly_set_name (struct frame *f, Lisp_Object arg,
1161 Lisp_Object oldval); 1142 Lisp_Object oldval);
1162extern void ns_set_scroll_bar_default_width (struct frame *f); 1143extern void ns_set_scroll_bar_default_width (struct frame *f);
1163extern void ns_set_scroll_bar_default_height (struct frame *f); 1144extern void ns_set_scroll_bar_default_height (struct frame *f);
1145extern void ns_change_tab_bar_height (struct frame *f, int height);
1164extern const char *ns_get_string_resource (void *_rdb, 1146extern const char *ns_get_string_resource (void *_rdb,
1165 const char *name, 1147 const char *name,
1166 const char *class); 1148 const char *class);
@@ -1175,6 +1157,10 @@ extern void ns_init_locale (void);
1175 1157
1176/* in nsmenu */ 1158/* in nsmenu */
1177extern void update_frame_tool_bar (struct frame *f); 1159extern void update_frame_tool_bar (struct frame *f);
1160#ifdef __OBJC__
1161extern void update_frame_tool_bar_1 (struct frame *f, EmacsToolbar *toolbar);
1162#endif
1163
1178extern void free_frame_tool_bar (struct frame *f); 1164extern void free_frame_tool_bar (struct frame *f);
1179extern Lisp_Object find_and_return_menu_selection (struct frame *f, 1165extern Lisp_Object find_and_return_menu_selection (struct frame *f,
1180 bool keymaps, 1166 bool keymaps,
diff --git a/src/nsterm.m b/src/nsterm.m
index b9e2c9b6916..1f17a30272c 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -65,14 +65,12 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
65 65
66#ifdef NS_IMPL_GNUSTEP 66#ifdef NS_IMPL_GNUSTEP
67#include "process.h" 67#include "process.h"
68#import <GNUstepGUI/GSDisplayServer.h>
68#endif 69#endif
69 70
70#ifdef NS_IMPL_COCOA 71#ifdef NS_IMPL_COCOA
71#include "macfont.h" 72#include "macfont.h"
72#include <Carbon/Carbon.h> 73#include <Carbon/Carbon.h>
73#endif
74
75#ifdef NS_DRAW_TO_BUFFER
76#include <IOSurface/IOSurface.h> 74#include <IOSurface/IOSurface.h>
77#endif 75#endif
78 76
@@ -272,9 +270,6 @@ long context_menu_value = 0;
272 270
273/* display update */ 271/* display update */
274static struct frame *ns_updating_frame; 272static struct frame *ns_updating_frame;
275#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
276static NSView *focus_view = NULL;
277#endif
278static int ns_window_num = 0; 273static int ns_window_num = 0;
279static BOOL gsaved = NO; 274static BOOL gsaved = NO;
280#ifdef NS_IMPL_COCOA 275#ifdef NS_IMPL_COCOA
@@ -1027,38 +1022,8 @@ ns_update_begin (struct frame *f)
1027 1022
1028 ns_update_auto_hide_menu_bar (); 1023 ns_update_auto_hide_menu_bar ();
1029 1024
1030#ifdef NS_IMPL_COCOA
1031 if ([view isFullscreen] && [view fsIsNative])
1032 {
1033 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1034 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1035 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1036 if (! tbar_visible != ! [toolbar isVisible])
1037 [toolbar setVisible: tbar_visible];
1038 }
1039#endif
1040
1041 ns_updating_frame = f; 1025 ns_updating_frame = f;
1042#ifdef NS_DRAW_TO_BUFFER 1026 [view lockFocus];
1043#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1044 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1045 {
1046#endif
1047 [view focusOnDrawingBuffer];
1048#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1049 }
1050 else
1051 {
1052#endif
1053#endif /* NS_DRAW_TO_BUFFER */
1054
1055#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1056 [view lockFocus];
1057#endif
1058#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1059 }
1060#endif
1061
1062} 1027}
1063 1028
1064 1029
@@ -1069,39 +1034,21 @@ ns_update_end (struct frame *f)
1069 external (RIF) call; for whole frame, called after gui_update_window_end 1034 external (RIF) call; for whole frame, called after gui_update_window_end
1070 -------------------------------------------------------------------------- */ 1035 -------------------------------------------------------------------------- */
1071{ 1036{
1072#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1073 EmacsView *view = FRAME_NS_VIEW (f); 1037 EmacsView *view = FRAME_NS_VIEW (f);
1074#endif
1075 1038
1076 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end"); 1039 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1077 1040
1078/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */ 1041/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1079 MOUSE_HL_INFO (f)->mouse_face_defer = 0; 1042 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1080 1043
1081#ifdef NS_DRAW_TO_BUFFER 1044 block_input ();
1082#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1083 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1084 {
1085#endif
1086 [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
1087#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1088 }
1089 else
1090 {
1091#endif
1092#endif /* NS_DRAW_TO_BUFFER */
1093
1094#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1095 block_input ();
1096
1097 [view unlockFocus];
1098 [[view window] flushWindow];
1099 1045
1100 unblock_input (); 1046 [view unlockFocus];
1101#endif 1047#if defined (NS_IMPL_GNUSTEP)
1102#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1048 [[view window] flushWindow];
1103 }
1104#endif 1049#endif
1050
1051 unblock_input ();
1105 ns_updating_frame = NULL; 1052 ns_updating_frame = NULL;
1106} 1053}
1107 1054
@@ -1116,8 +1063,6 @@ ns_focus (struct frame *f, NSRect *r, int n)
1116 the entire window. 1063 the entire window.
1117 -------------------------------------------------------------------------- */ 1064 -------------------------------------------------------------------------- */
1118{ 1065{
1119 EmacsView *view = FRAME_NS_VIEW (f);
1120
1121 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus"); 1066 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1122 if (r != NULL) 1067 if (r != NULL)
1123 { 1068 {
@@ -1126,47 +1071,23 @@ ns_focus (struct frame *f, NSRect *r, int n)
1126 1071
1127 if (f != ns_updating_frame) 1072 if (f != ns_updating_frame)
1128 { 1073 {
1129#ifdef NS_DRAW_TO_BUFFER 1074 EmacsView *view = FRAME_NS_VIEW (f);
1130#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1075 [view lockFocus];
1131 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1132 {
1133#endif
1134 [view focusOnDrawingBuffer];
1135#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1136 }
1137 else
1138 {
1139#endif
1140#endif /* NS_DRAW_TO_BUFFER */
1141
1142#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1143 if (view != focus_view)
1144 {
1145 if (focus_view != NULL)
1146 {
1147 [focus_view unlockFocus];
1148 [[focus_view window] flushWindow];
1149 }
1150
1151 if (view)
1152 [view lockFocus];
1153 focus_view = view;
1154 }
1155#endif
1156#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1157 }
1158#endif
1159 } 1076 }
1160 1077
1161
1162 /* clipping */ 1078 /* clipping */
1163 if (r) 1079 if (r)
1164 { 1080 {
1165 [[NSGraphicsContext currentContext] saveGraphicsState]; 1081 NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
1082 [ctx saveGraphicsState];
1083#ifdef NS_IMPL_COCOA
1166 if (n == 2) 1084 if (n == 2)
1167 NSRectClipList (r, 2); 1085 NSRectClipList (r, 2);
1168 else 1086 else
1169 NSRectClip (*r); 1087 NSRectClip (*r);
1088#else
1089 GSRectClipList (ctx, r, n);
1090#endif
1170 gsaved = YES; 1091 gsaved = YES;
1171 } 1092 }
1172} 1093}
@@ -1186,35 +1107,14 @@ ns_unfocus (struct frame *f)
1186 gsaved = NO; 1107 gsaved = NO;
1187 } 1108 }
1188 1109
1189#ifdef NS_DRAW_TO_BUFFER 1110 if (f != ns_updating_frame)
1190 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1191 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1192 {
1193#endif
1194 if (! ns_updating_frame)
1195 [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
1196 [FRAME_NS_VIEW (f) setNeedsDisplay:YES];
1197#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1198 }
1199 else
1200 { 1111 {
1112 EmacsView *view = FRAME_NS_VIEW (f);
1113 [view unlockFocus];
1114#if defined (NS_IMPL_GNUSTEP)
1115 [[view window] flushWindow];
1201#endif 1116#endif
1202#endif /* NS_DRAW_TO_BUFFER */
1203
1204#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1205 if (f != ns_updating_frame)
1206 {
1207 if (focus_view != NULL)
1208 {
1209 [focus_view unlockFocus];
1210 [[focus_view window] flushWindow];
1211 focus_view = NULL;
1212 }
1213 }
1214#endif
1215#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1216 } 1117 }
1217#endif
1218} 1118}
1219 1119
1220 1120
@@ -1381,7 +1281,7 @@ ns_ring_bell (struct frame *f)
1381 } 1281 }
1382} 1282}
1383 1283
1384#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1284#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1385static void 1285static void
1386hide_bell (void) 1286hide_bell (void)
1387/* -------------------------------------------------------------------------- 1287/* --------------------------------------------------------------------------
@@ -1548,7 +1448,7 @@ ns_make_frame_visible (struct frame *f)
1548 if (!FRAME_VISIBLE_P (f)) 1448 if (!FRAME_VISIBLE_P (f))
1549 { 1449 {
1550 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1450 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1551 NSWindow *window = [view window]; 1451 EmacsWindow *window = (EmacsWindow *)[view window];
1552 1452
1553 SET_FRAME_VISIBLE (f, 1); 1453 SET_FRAME_VISIBLE (f, 1);
1554 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f)); 1454 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
@@ -1571,11 +1471,8 @@ ns_make_frame_visible (struct frame *f)
1571 relationship, so reinstate it. */ 1471 relationship, so reinstate it. */
1572 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL) 1472 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1573 { 1473 {
1574 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1575
1576 block_input (); 1474 block_input ();
1577 [parent addChildWindow: window 1475 [window setParentChildRelationships];
1578 ordered: NSWindowAbove];
1579 unblock_input (); 1476 unblock_input ();
1580 1477
1581 /* If the parent frame moved while the child frame was 1478 /* If the parent frame moved while the child frame was
@@ -1732,52 +1629,35 @@ ns_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1732 1629
1733 block_input (); 1630 block_input ();
1734 1631
1735 if (FRAME_PARENT_FRAME (f)) 1632 /* If there is no parent frame then just convert to screen
1736 { 1633 coordinates, UNLESS we have negative values, in which case I
1737 /* Convert the parent frame's view rectangle into screen 1634 think it's best to position from the bottom and right of the
1738 coords. */ 1635 current screen rather than the main screen or whole display. */
1739 EmacsView *parentView = FRAME_NS_VIEW (FRAME_PARENT_FRAME (f));
1740 NSRect parentRect = [parentView convertRect:[parentView frame]
1741 toView:nil];
1742 parentRect = [[parentView window] convertRectToScreen:parentRect];
1743 1636
1744 if (f->size_hint_flags & XNegative) 1637 NSRect parentRect = ns_parent_window_rect (f);
1745 topLeft.x = NSMaxX (parentRect) - NSWidth (windowFrame) + xoff;
1746 else
1747 topLeft.x = NSMinX (parentRect) + xoff;
1748 1638
1749 if (f->size_hint_flags & YNegative) 1639 if (f->size_hint_flags & XNegative)
1750 topLeft.y = NSMinY (parentRect) + NSHeight (windowFrame) - yoff; 1640 topLeft.x = NSMaxX (parentRect) - NSWidth (windowFrame) + xoff;
1751 else 1641 else if (FRAME_PARENT_FRAME (f))
1752 topLeft.y = NSMaxY (parentRect) - yoff; 1642 topLeft.x = NSMinX (parentRect) + xoff;
1753 }
1754 else 1643 else
1755 { 1644 topLeft.x = xoff;
1756 /* If there is no parent frame then just convert to screen
1757 coordinates, UNLESS we have negative values, in which case I
1758 think it's best to position from the bottom and right of the
1759 current screen rather than the main screen or whole
1760 display. */
1761 NSRect screenFrame = [[[view window] screen] frame];
1762 1645
1763 if (f->size_hint_flags & XNegative) 1646 if (f->size_hint_flags & YNegative)
1764 topLeft.x = NSMaxX (screenFrame) - NSWidth (windowFrame) + xoff; 1647 topLeft.y = NSMinY (parentRect) + NSHeight (windowFrame) - yoff;
1765 else 1648 else if (FRAME_PARENT_FRAME (f))
1766 topLeft.x = xoff; 1649 topLeft.y = NSMaxY (parentRect) - yoff;
1767 1650 else
1768 if (f->size_hint_flags & YNegative) 1651 topLeft.y = NSMaxY ([[[NSScreen screens] objectAtIndex:0] frame]) - yoff;
1769 topLeft.y = NSMinY (screenFrame) + NSHeight (windowFrame) - yoff;
1770 else
1771 topLeft.y = NSMaxY ([[[NSScreen screens] objectAtIndex:0] frame]) - yoff;
1772 1652
1773#ifdef NS_IMPL_GNUSTEP 1653#ifdef NS_IMPL_GNUSTEP
1774 /* Don't overlap the menu. 1654 /* Don't overlap the menu.
1775 1655
1776 FIXME: Surely there's a better way than just hardcoding 100 1656 FIXME: Surely there's a better way than just hardcoding 100 in
1777 in here? */ 1657 here? */
1778 topLeft.x = 100; 1658 if (topLeft.x < 100)
1659 topLeft.x = 100;
1779#endif 1660#endif
1780 }
1781 1661
1782 NSTRACE_POINT ("setFrameTopLeftPoint", topLeft); 1662 NSTRACE_POINT ("setFrameTopLeftPoint", topLeft);
1783 [[view window] setFrameTopLeftPoint:topLeft]; 1663 [[view window] setFrameTopLeftPoint:topLeft];
@@ -1800,45 +1680,38 @@ ns_set_window_size (struct frame *f,
1800{ 1680{
1801 EmacsView *view = FRAME_NS_VIEW (f); 1681 EmacsView *view = FRAME_NS_VIEW (f);
1802 NSWindow *window = [view window]; 1682 NSWindow *window = [view window];
1803 NSRect wr = [window frame]; 1683 NSRect frameRect;
1804 int orig_height = wr.size.height;
1805 1684
1806 NSTRACE ("ns_set_window_size"); 1685 NSTRACE ("ns_set_window_size");
1807 1686
1808 if (view == nil) 1687 if (view == nil)
1809 return; 1688 return;
1810 1689
1811 NSTRACE_RECT ("current", wr); 1690 NSTRACE_RECT ("current", [window frame]);
1812 NSTRACE_MSG ("Width:%d Height:%d", width, height); 1691 NSTRACE_MSG ("Width:%d Height:%d", width, height);
1813 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); 1692 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1814 1693
1815 block_input (); 1694 block_input ();
1816 1695
1817 wr.size.width = width + f->border_width; 1696 frameRect = [window frameRectForContentRect:NSMakeRect (0, 0, width, height)];
1818 wr.size.height = height; 1697
1819 if (! [view isFullscreen]) 1698 /* Set the origin so the top left of the frame doesn't move. */
1820 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f) 1699 frameRect.origin = [window frame].origin;
1821 + FRAME_TOOLBAR_HEIGHT (f); 1700 frameRect.origin.y += NSHeight ([view frame]) - height;
1822 1701
1823 /* Do not try to constrain to this screen. We may have multiple 1702 if (f->output_data.ns->zooming)
1824 screens, and want Emacs to span those. Constraining to screen 1703 f->output_data.ns->zooming = 0;
1825 prevents that, and that is not nice to the user. */
1826 if (f->output_data.ns->zooming)
1827 f->output_data.ns->zooming = 0;
1828 else
1829 wr.origin.y += orig_height - wr.size.height;
1830 1704
1831 /* Usually it seems safe to delay changing the frame size, but when a 1705 /* Usually it seems safe to delay changing the frame size, but when a
1832 series of actions are taken with no redisplay between them then we 1706 series of actions are taken with no redisplay between them then we
1833 can end up using old values so don't delay here. */ 1707 can end up using old values so don't delay here. */
1834 change_frame_size (f, width, height, false, NO, false); 1708 change_frame_size (f, width, height, false, NO, false);
1835 1709
1836 [window setFrame:wr display:NO]; 1710 [window setFrame:frameRect display:NO];
1837 1711
1838 unblock_input (); 1712 unblock_input ();
1839} 1713}
1840 1714
1841#ifdef NS_IMPL_COCOA
1842void 1715void
1843ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1716ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1844/* -------------------------------------------------------------------------- 1717/* --------------------------------------------------------------------------
@@ -1848,45 +1721,34 @@ ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
1848 dragged, resized, iconified, maximized or deleted with the mouse. If 1721 dragged, resized, iconified, maximized or deleted with the mouse. If
1849 nil, draw the frame with all the elements listed above unless these 1722 nil, draw the frame with all the elements listed above unless these
1850 have been suspended via window manager settings. 1723 have been suspended via window manager settings.
1851
1852 GNUStep cannot change an existing window's style.
1853 -------------------------------------------------------------------------- */ 1724 -------------------------------------------------------------------------- */
1854{ 1725{
1855 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1856 NSWindow *window = [view window];
1857
1858 NSTRACE ("ns_set_undecorated"); 1726 NSTRACE ("ns_set_undecorated");
1859 1727
1860 if (!EQ (new_value, old_value)) 1728 if (!EQ (new_value, old_value))
1861 { 1729 {
1730 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1731 NSWindow *oldWindow = [view window];
1732 NSWindow *newWindow;
1733
1862 block_input (); 1734 block_input ();
1863 1735
1864 if (NILP (new_value)) 1736 FRAME_UNDECORATED (f) = !NILP (new_value);
1865 {
1866 FRAME_UNDECORATED (f) = false;
1867 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1868 ^ FRAME_UNDECORATED_FLAGS)];
1869 1737
1870 [view createToolbar: f]; 1738 newWindow = [[EmacsWindow alloc] initWithEmacsFrame:f];
1871 }
1872 else
1873 {
1874 [window setToolbar: nil];
1875 /* Do I need to release the toolbar here? */
1876 1739
1877 FRAME_UNDECORATED (f) = true; 1740 if ([oldWindow isKeyWindow])
1878 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS) 1741 [newWindow makeKeyAndOrderFront:NSApp];
1879 ^ FRAME_DECORATED_FLAGS)];
1880 }
1881 1742
1882 /* At this point it seems we don't have an active NSResponder, 1743 [newWindow setIsVisible:[oldWindow isVisible]];
1883 so some key presses (TAB) are swallowed by the system. */ 1744 if ([oldWindow isMiniaturized])
1884 [window makeFirstResponder: view]; 1745 [newWindow miniaturize:NSApp];
1746
1747 [oldWindow close];
1885 1748
1886 unblock_input (); 1749 unblock_input ();
1887 } 1750 }
1888} 1751}
1889#endif /* NS_IMPL_COCOA */
1890 1752
1891void 1753void
1892ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1754ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
@@ -1913,7 +1775,6 @@ ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_val
1913 -------------------------------------------------------------------------- */ 1775 -------------------------------------------------------------------------- */
1914{ 1776{
1915 struct frame *p = NULL; 1777 struct frame *p = NULL;
1916 NSWindow *parent, *child;
1917 1778
1918 NSTRACE ("ns_set_parent_frame"); 1779 NSTRACE ("ns_set_parent_frame");
1919 1780
@@ -1926,72 +1787,11 @@ ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_val
1926 error ("Invalid specification of `parent-frame'"); 1787 error ("Invalid specification of `parent-frame'");
1927 } 1788 }
1928 1789
1929 if (p != FRAME_PARENT_FRAME (f)) 1790 fset_parent_frame (f, new_value);
1930 {
1931 block_input ();
1932 child = [FRAME_NS_VIEW (f) window];
1933
1934#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
1935 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1936#endif
1937
1938 if ([child parentWindow] != nil)
1939 {
1940#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
1941 parent = [child parentWindow];
1942#endif
1943
1944 [[child parentWindow] removeChildWindow:child];
1945#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
1946#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
1947 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)])
1948#endif
1949 [child setAccessibilitySubrole:NSAccessibilityStandardWindowSubrole];
1950#endif
1951#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
1952 if (NILP (new_value))
1953 {
1954 NSTRACE ("child setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary");
1955 [child setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
1956 // if current parent in fullscreen and no new parent make child fullscreen
1957 while (parent) {
1958 if (([parent styleMask] & NSWindowStyleMaskFullScreen) != 0)
1959 {
1960 [view toggleFullScreen:child];
1961 break;
1962 }
1963 // check all parents
1964 parent = [parent parentWindow];
1965 }
1966 }
1967#endif
1968 }
1969 1791
1970 if (!NILP (new_value)) 1792 block_input ();
1971 { 1793 [(EmacsWindow *)[FRAME_NS_VIEW (f) window] setParentChildRelationships];
1972#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 1794 unblock_input ();
1973 // child frame must not be in fullscreen
1974 if ([view fsIsNative] && [view isFullscreen])
1975 [view toggleFullScreen:child];
1976 NSTRACE ("child setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary");
1977 [child setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
1978#endif
1979 parent = [FRAME_NS_VIEW (p) window];
1980
1981 [parent addChildWindow: child
1982 ordered: NSWindowAbove];
1983#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
1984#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
1985 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)])
1986#endif
1987 [child setAccessibilitySubrole:NSAccessibilityFloatingWindowSubrole];
1988#endif
1989 }
1990
1991 unblock_input ();
1992
1993 fset_parent_frame (f, new_value);
1994 }
1995} 1795}
1996 1796
1997void 1797void
@@ -2433,12 +2233,10 @@ ns_set_frame_alpha (struct frame *f)
2433 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0) 2233 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2434 alpha = alpha_min; 2234 alpha = alpha_min;
2435 2235
2436#ifdef NS_IMPL_COCOA
2437 { 2236 {
2438 EmacsView *view = FRAME_NS_VIEW (f); 2237 EmacsView *view = FRAME_NS_VIEW (f);
2439 [[view window] setAlphaValue: alpha]; 2238 [[view window] setAlphaValue: alpha];
2440 } 2239 }
2441#endif
2442} 2240}
2443 2241
2444 2242
@@ -2457,13 +2255,19 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2457{ 2255{
2458 NSTRACE ("frame_set_mouse_pixel_position"); 2256 NSTRACE ("frame_set_mouse_pixel_position");
2459 2257
2460 /* FIXME: what about GNUstep? */
2461#ifdef NS_IMPL_COCOA 2258#ifdef NS_IMPL_COCOA
2462 CGPoint mouse_pos = 2259 CGPoint mouse_pos =
2463 CGPointMake(f->left_pos + pix_x, 2260 CGPointMake(f->left_pos + pix_x,
2464 f->top_pos + pix_y + 2261 f->top_pos + pix_y +
2465 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); 2262 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2466 CGWarpMouseCursorPosition (mouse_pos); 2263 CGWarpMouseCursorPosition (mouse_pos);
2264#else
2265 GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]);
2266 [server setMouseLocation: NSMakePoint (f->left_pos + pix_x,
2267 f->top_pos + pix_y
2268 + FRAME_NS_TITLEBAR_HEIGHT(f)
2269 + FRAME_TOOLBAR_HEIGHT(f))
2270 onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]];
2467#endif 2271#endif
2468} 2272}
2469 2273
@@ -2641,9 +2445,6 @@ ns_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
2641 EmacsView *view = FRAME_NS_VIEW (f); 2445 EmacsView *view = FRAME_NS_VIEW (f);
2642 FRAME_POINTER_TYPE (f) = cursor; 2446 FRAME_POINTER_TYPE (f) = cursor;
2643 [[view window] invalidateCursorRectsForView: view]; 2447 [[view window] invalidateCursorRectsForView: view];
2644 /* Redisplay assumes this function also draws the changed frame
2645 cursor, but this function doesn't, so do it explicitly. */
2646 gui_update_cursor (f, 1);
2647 } 2448 }
2648} 2449}
2649 2450
@@ -2779,8 +2580,7 @@ ns_get_shifted_character (NSEvent *event)
2779 ========================================================================== */ 2580 ========================================================================== */
2780 2581
2781 2582
2782#if 0 2583#ifdef NS_IMPL_GNUSTEP
2783/* FIXME: Remove this function. */
2784static void 2584static void
2785ns_redraw_scroll_bars (struct frame *f) 2585ns_redraw_scroll_bars (struct frame *f)
2786{ 2586{
@@ -2825,10 +2625,9 @@ ns_clear_frame (struct frame *f)
2825 NSRectFill (r); 2625 NSRectFill (r);
2826 ns_unfocus (f); 2626 ns_unfocus (f);
2827 2627
2828 /* as of 2006/11 or so this is now needed */ 2628#ifdef NS_IMPL_GNUSTEP
2829 /* FIXME: I don't see any reason for this and removing it makes no 2629 ns_redraw_scroll_bars (f);
2830 difference here. Do we need it for GNUstep? */ 2630#endif
2831 //ns_redraw_scroll_bars (f);
2832 unblock_input (); 2631 unblock_input ();
2833} 2632}
2834 2633
@@ -2909,10 +2708,10 @@ ns_scroll_run (struct window *w, struct run *run)
2909 2708
2910 { 2709 {
2911 NSRect srcRect = NSMakeRect (x, from_y, width, height); 2710 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2912 NSRect dstRect = NSMakeRect (x, to_y, width, height); 2711 NSPoint dest = NSMakePoint (x, to_y);
2913 EmacsView *view = FRAME_NS_VIEW (f); 2712 EmacsView *view = FRAME_NS_VIEW (f);
2914 2713
2915 [view copyRect:srcRect to:dstRect]; 2714 [view copyRect:srcRect to:dest];
2916#ifdef NS_IMPL_COCOA 2715#ifdef NS_IMPL_COCOA
2917 [view setNeedsDisplayInRect:srcRect]; 2716 [view setNeedsDisplayInRect:srcRect];
2918#endif 2717#endif
@@ -2929,11 +2728,10 @@ ns_clear_under_internal_border (struct frame *f)
2929 2728
2930 if (FRAME_LIVE_P (f) && FRAME_INTERNAL_BORDER_WIDTH (f) > 0) 2729 if (FRAME_LIVE_P (f) && FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
2931 { 2730 {
2932 int border_width = FRAME_INTERNAL_BORDER_WIDTH (f); 2731 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
2933 NSView *view = FRAME_NS_VIEW (f); 2732 int width = FRAME_PIXEL_WIDTH (f);
2934 NSRect edge_rect, frame_rect = [view bounds]; 2733 int height = FRAME_PIXEL_HEIGHT (f);
2935 NSRectEdge edge[] = {NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge}; 2734 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
2936
2937 int face_id = 2735 int face_id =
2938 (FRAME_PARENT_FRAME (f) 2736 (FRAME_PARENT_FRAME (f)
2939 ? (!NILP (Vface_remapping_alist) 2737 ? (!NILP (Vface_remapping_alist)
@@ -2955,12 +2753,12 @@ ns_clear_under_internal_border (struct frame *f)
2955 2753
2956 ns_focus (f, NULL, 1); 2754 ns_focus (f, NULL, 1);
2957 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set]; 2755 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2958 for (int i = 0; i < 4 ; i++)
2959 {
2960 NSDivideRect (frame_rect, &edge_rect, &frame_rect, border_width, edge[i]);
2961 2756
2962 NSRectFill (edge_rect); 2757 NSRectFill (NSMakeRect (0, margin, width, border));
2963 } 2758 NSRectFill (NSMakeRect (0, 0, border, height));
2759 NSRectFill (NSMakeRect (0, margin, width, border));
2760 NSRectFill (NSMakeRect (width - border, 0, border, height));
2761 NSRectFill (NSMakeRect (0, height - border, width, border));
2964 ns_unfocus (f); 2762 ns_unfocus (f);
2965 } 2763 }
2966} 2764}
@@ -3034,11 +2832,11 @@ ns_shift_glyphs_for_insert (struct frame *f,
3034 -------------------------------------------------------------------------- */ 2832 -------------------------------------------------------------------------- */
3035{ 2833{
3036 NSRect srcRect = NSMakeRect (x, y, width, height); 2834 NSRect srcRect = NSMakeRect (x, y, width, height);
3037 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height); 2835 NSPoint dest = NSMakePoint (x+shift_by, y);
3038 2836
3039 NSTRACE ("ns_shift_glyphs_for_insert"); 2837 NSTRACE ("ns_shift_glyphs_for_insert");
3040 2838
3041 [FRAME_NS_VIEW (f) copyRect:srcRect to:dstRect]; 2839 [FRAME_NS_VIEW (f) copyRect:srcRect to:dest];
3042} 2840}
3043 2841
3044 2842
@@ -3056,31 +2854,31 @@ ns_compute_glyph_string_overhangs (struct glyph_string *s)
3056 External (RIF); compute left/right overhang of whole string and set in s 2854 External (RIF); compute left/right overhang of whole string and set in s
3057 -------------------------------------------------------------------------- */ 2855 -------------------------------------------------------------------------- */
3058{ 2856{
3059 struct font *font = s->font; 2857 if (s->cmp == NULL
3060 2858 && (s->first_glyph->type == CHAR_GLYPH
3061 if (s->char2b) 2859 || s->first_glyph->type == COMPOSITE_GLYPH))
3062 { 2860 {
3063 struct font_metrics metrics; 2861 struct font_metrics metrics;
3064 unsigned int codes[2];
3065 codes[0] = *(s->char2b);
3066 codes[1] = *(s->char2b + s->nchars - 1);
3067 2862
3068 font->driver->text_extents (font, codes, 2, &metrics); 2863 if (s->first_glyph->type == CHAR_GLYPH)
3069 s->left_overhang = -metrics.lbearing; 2864 {
3070 s->right_overhang 2865 struct font *font = s->font;
3071 = metrics.rbearing > metrics.width 2866 font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
3072 ? metrics.rbearing - metrics.width : 0; 2867 }
2868 else
2869 {
2870 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
2871
2872 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
2873 }
2874 s->right_overhang = (metrics.rbearing > metrics.width
2875 ? metrics.rbearing - metrics.width : 0);
2876 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
3073 } 2877 }
3074 else 2878 else if (s->cmp)
3075 { 2879 {
3076 s->left_overhang = 0; 2880 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
3077#ifdef NS_IMPL_GNUSTEP 2881 s->left_overhang = - s->cmp->lbearing;
3078 if (EQ (font->driver->type, Qns))
3079 s->right_overhang = ((struct nsfont_info *)font)->ital ?
3080 FONT_HEIGHT (font) * 0.2 : 0;
3081 else
3082#endif
3083 s->right_overhang = 0;
3084 } 2882 }
3085} 2883}
3086 2884
@@ -3092,8 +2890,40 @@ ns_compute_glyph_string_overhangs (struct glyph_string *s)
3092 2890
3093 ========================================================================== */ 2891 ========================================================================== */
3094 2892
2893static NSMutableDictionary *fringe_bmp;
2894
2895static void
2896ns_define_fringe_bitmap (int which, unsigned short *bits, int h, int w)
2897{
2898 NSBezierPath *p = [NSBezierPath bezierPath];
2899
2900 if (!fringe_bmp)
2901 fringe_bmp = [[NSMutableDictionary alloc] initWithCapacity:25];
2902
2903 [p moveToPoint:NSMakePoint (0, 0)];
2904
2905 for (int y = 0 ; y < h ; y++)
2906 for (int x = 0 ; x < w ; x++)
2907 {
2908 /* XBM rows are always round numbers of bytes, with any unused
2909 bits ignored. */
2910 int byte = y * (w/8 + (w%8 ? 1 : 0)) + x/8;
2911 bool bit = bits[byte] & (0x80 >> x%8);
2912 if (bit)
2913 [p appendBezierPathWithRect:NSMakeRect (x, y, 1, 1)];
2914 }
2915
2916 [fringe_bmp setObject:p forKey:[NSNumber numberWithInt:which]];
2917}
2918
2919
2920static void
2921ns_destroy_fringe_bitmap (int which)
2922{
2923 [fringe_bmp removeObjectForKey:[NSNumber numberWithInt:which]];
2924}
2925
3095 2926
3096extern int max_used_fringe_bitmap;
3097static void 2927static void
3098ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, 2928ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3099 struct draw_fringe_bitmap_params *p) 2929 struct draw_fringe_bitmap_params *p)
@@ -3119,41 +2949,18 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3119 2949
3120 struct frame *f = XFRAME (WINDOW_FRAME (w)); 2950 struct frame *f = XFRAME (WINDOW_FRAME (w));
3121 struct face *face = p->face; 2951 struct face *face = p->face;
3122 static EmacsImage **bimgs = NULL;
3123 static int nBimgs = 0;
3124 NSRect clearRect = NSZeroRect; 2952 NSRect clearRect = NSZeroRect;
3125 NSRect imageRect = NSZeroRect;
3126 NSRect rowRect = ns_row_rect (w, row, ANY_AREA); 2953 NSRect rowRect = ns_row_rect (w, row, ANY_AREA);
3127 2954
3128 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap"); 2955 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
3129 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d", 2956 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
3130 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh); 2957 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
3131 2958
3132 /* grow bimgs if needed */ 2959 /* Work out the rectangle we will need to clear. */
3133 if (nBimgs < max_used_fringe_bitmap) 2960 clearRect = NSMakeRect (p->x, p->y, p->wd, p->h);
3134 {
3135 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
3136 memset (bimgs + nBimgs, 0,
3137 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
3138 nBimgs = max_used_fringe_bitmap;
3139 }
3140
3141 /* Work out the rectangle we will composite into. */
3142 if (p->which)
3143 imageRect = NSMakeRect (p->x, p->y, p->wd, p->h);
3144 2961
3145 /* Work out the rectangle we will need to clear. Because we're
3146 compositing rather than blitting, we need to clear the area under
3147 the image regardless of anything else. */
3148 if (p->bx >= 0 && !p->overlay_p) 2962 if (p->bx >= 0 && !p->overlay_p)
3149 { 2963 clearRect = NSUnionRect (clearRect, NSMakeRect (p->bx, p->by, p->nx, p->ny));
3150 clearRect = NSMakeRect (p->bx, p->by, p->nx, p->ny);
3151 clearRect = NSUnionRect (clearRect, imageRect);
3152 }
3153 else
3154 {
3155 clearRect = imageRect;
3156 }
3157 2964
3158 /* Handle partially visible rows. */ 2965 /* Handle partially visible rows. */
3159 clearRect = NSIntersectionRect (clearRect, rowRect); 2966 clearRect = NSIntersectionRect (clearRect, rowRect);
@@ -3169,53 +2976,29 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3169 NSRectFill (clearRect); 2976 NSRectFill (clearRect);
3170 } 2977 }
3171 2978
3172 if (p->which) 2979 NSBezierPath *bmp = [fringe_bmp objectForKey:[NSNumber numberWithInt:p->which]];
2980 if (bmp)
3173 { 2981 {
3174 EmacsImage *img = bimgs[p->which - 1]; 2982 NSAffineTransform *transform = [NSAffineTransform transform];
2983 NSColor *bm_color;
3175 2984
3176 if (!img) 2985 /* Because the image is defined at (0, 0) we need to take a copy
3177 { 2986 and then transform that copy to the new origin. */
3178 // Note: For "periodic" images, allocate one EmacsImage for 2987 bmp = [bmp copy];
3179 // the base image, and use it for all dh:s. 2988 [transform translateXBy:p->x yBy:p->y - p->dh];
3180 unsigned short *bits = p->bits; 2989 [bmp transformUsingAffineTransform:transform];
3181 int full_height = p->h + p->dh;
3182 int i;
3183 unsigned char *cbits = xmalloc (full_height);
3184
3185 for (i = 0; i < full_height; i++)
3186 cbits[i] = bits[i];
3187 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
3188 height: full_height
3189 fg: 0 bg: 0
3190 reverseBytes: NO];
3191 bimgs[p->which - 1] = img;
3192 xfree (cbits);
3193 }
3194
3195
3196 {
3197 NSColor *bm_color;
3198 if (!p->cursor_p)
3199 bm_color = ns_lookup_indexed_color(face->foreground, f);
3200 else if (p->overlay_p)
3201 bm_color = ns_lookup_indexed_color(face->background, f);
3202 else
3203 bm_color = f->output_data.ns->cursor_color;
3204 [img setXBMColor: bm_color];
3205 }
3206 2990
3207 // Note: For periodic images, the full image height is "h + hd". 2991 if (!p->cursor_p)
3208 // By using the height h, a suitable part of the image is used. 2992 bm_color = ns_lookup_indexed_color(face->foreground, f);
3209 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h); 2993 else if (p->overlay_p)
2994 bm_color = ns_lookup_indexed_color(face->background, f);
2995 else
2996 bm_color = f->output_data.ns->cursor_color;
3210 2997
3211 NSTRACE_RECT ("fromRect", fromRect); 2998 [bm_color set];
2999 [bmp fill];
3212 3000
3213 [img drawInRect: imageRect 3001 [bmp release];
3214 fromRect: fromRect
3215 operation: NSCompositingOperationSourceOver
3216 fraction: 1.0
3217 respectFlipped: YES
3218 hints: nil];
3219 } 3002 }
3220 ns_unfocus (f); 3003 ns_unfocus (f);
3221} 3004}
@@ -3235,14 +3018,13 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3235 struct frame *f = WINDOW_XFRAME (w); 3018 struct frame *f = WINDOW_XFRAME (w);
3236 struct glyph *phys_cursor_glyph; 3019 struct glyph *phys_cursor_glyph;
3237 struct glyph *cursor_glyph; 3020 struct glyph *cursor_glyph;
3238 struct face *face;
3239 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3240 3021
3241 /* If cursor is out of bounds, don't draw garbage. This can happen 3022 /* If cursor is out of bounds, don't draw garbage. This can happen
3242 in mini-buffer windows when switching between echo area glyphs 3023 in mini-buffer windows when switching between echo area glyphs
3243 and mini-buffer. */ 3024 and mini-buffer. */
3244 3025
3245 NSTRACE ("ns_draw_window_cursor"); 3026 NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)",
3027 on_p, cursor_type);
3246 3028
3247 if (!on_p) 3029 if (!on_p)
3248 return; 3030 return;
@@ -3258,6 +3040,8 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3258 3040
3259 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) 3041 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3260 { 3042 {
3043 NSTRACE_MSG ("No phys cursor glyph was found!");
3044
3261 if (glyph_row->exact_window_width_line_p 3045 if (glyph_row->exact_window_width_line_p
3262 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) 3046 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3263 { 3047 {
@@ -3267,10 +3051,6 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3267 return; 3051 return;
3268 } 3052 }
3269 3053
3270 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3271 (other terminals do it the other way round). We must set
3272 w->phys_cursor_width to the cursor width. For bar cursors, that
3273 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3274 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); 3054 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3275 3055
3276 /* The above get_phys_cursor_geometry call set w->phys_cursor_width 3056 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
@@ -3302,17 +3082,17 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3302 /* Prevent the cursor from being drawn outside the text area. */ 3082 /* Prevent the cursor from being drawn outside the text area. */
3303 r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); 3083 r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
3304 3084
3305 ns_focus (f, &r, 1); 3085 ns_focus (f, NULL, 0);
3306 3086
3307 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); 3087 NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
3308 if (face && NS_FACE_BACKGROUND (face) 3088 [ctx saveGraphicsState];
3309 == ns_index_color (FRAME_CURSOR_COLOR (f), f)) 3089#ifdef NS_IMPL_GNUSTEP
3310 { 3090 GSRectClipList (ctx, &r, 1);
3311 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; 3091#else
3312 hollow_color = FRAME_CURSOR_COLOR (f); 3092 NSRectClip (r);
3313 } 3093#endif
3314 else 3094
3315 [FRAME_CURSOR_COLOR (f) set]; 3095 [FRAME_CURSOR_COLOR (f) set];
3316 3096
3317 switch (cursor_type) 3097 switch (cursor_type)
3318 { 3098 {
@@ -3320,13 +3100,11 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3320 case NO_CURSOR: 3100 case NO_CURSOR:
3321 break; 3101 break;
3322 case FILLED_BOX_CURSOR: 3102 case FILLED_BOX_CURSOR:
3323 NSRectFill (r); 3103 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3324 break; 3104 break;
3325 case HOLLOW_BOX_CURSOR: 3105 case HOLLOW_BOX_CURSOR:
3326 NSRectFill (r); 3106 draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
3327 [hollow_color set]; 3107 [NSBezierPath strokeRect: r];
3328 NSRectFill (NSInsetRect (r, 1, 1));
3329 [FRAME_CURSOR_COLOR (f) set];
3330 break; 3108 break;
3331 case HBAR_CURSOR: 3109 case HBAR_CURSOR:
3332 NSRectFill (r); 3110 NSRectFill (r);
@@ -3342,12 +3120,9 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3342 NSRectFill (s); 3120 NSRectFill (s);
3343 break; 3121 break;
3344 } 3122 }
3345 ns_unfocus (f);
3346 3123
3347 /* Draw the character under the cursor. Other terms only draw 3124 [ctx restoreGraphicsState];
3348 the character on top of box cursors, so do the same here. */ 3125 ns_unfocus (f);
3349 if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
3350 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3351} 3126}
3352 3127
3353 3128
@@ -3527,16 +3302,18 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3527 if (s->for_overlaps) 3302 if (s->for_overlaps)
3528 return; 3303 return;
3529 3304
3305 if (s->hl == DRAW_CURSOR)
3306 [FRAME_BACKGROUND_COLOR (s->f) set];
3307 else if (face->underline_defaulted_p)
3308 [defaultCol set];
3309 else
3310 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3311
3530 /* Do underline. */ 3312 /* Do underline. */
3531 if (face->underline) 3313 if (face->underline)
3532 { 3314 {
3533 if (s->face->underline == FACE_UNDER_WAVE) 3315 if (s->face->underline == FACE_UNDER_WAVE)
3534 { 3316 {
3535 if (face->underline_defaulted_p)
3536 [defaultCol set];
3537 else
3538 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3539
3540 ns_draw_underwave (s, width, x); 3317 ns_draw_underwave (s, width, x);
3541 } 3318 }
3542 else if (s->face->underline == FACE_UNDER_LINE) 3319 else if (s->face->underline == FACE_UNDER_LINE)
@@ -3607,11 +3384,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3607 s->underline_position = position; 3384 s->underline_position = position;
3608 3385
3609 r = NSMakeRect (x, s->ybase + position, width, thickness); 3386 r = NSMakeRect (x, s->ybase + position, width, thickness);
3610
3611 if (face->underline_defaulted_p)
3612 [defaultCol set];
3613 else
3614 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3615 NSRectFill (r); 3387 NSRectFill (r);
3616 } 3388 }
3617 } 3389 }
@@ -3621,11 +3393,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3621 { 3393 {
3622 NSRect r; 3394 NSRect r;
3623 r = NSMakeRect (x, s->y, width, 1); 3395 r = NSMakeRect (x, s->y, width, 1);
3624
3625 if (face->overline_color_defaulted_p)
3626 [defaultCol set];
3627 else
3628 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3629 NSRectFill (r); 3396 NSRectFill (r);
3630 } 3397 }
3631 3398
@@ -3648,10 +3415,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3648 dy = lrint ((glyph_height - h) / 2); 3415 dy = lrint ((glyph_height - h) / 2);
3649 r = NSMakeRect (x, glyph_y + dy, width, 1); 3416 r = NSMakeRect (x, glyph_y + dy, width, 1);
3650 3417
3651 if (face->strike_through_color_defaulted_p)
3652 [defaultCol set];
3653 else
3654 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3655 NSRectFill (r); 3418 NSRectFill (r);
3656 } 3419 }
3657} 3420}
@@ -3690,7 +3453,7 @@ ns_draw_box (NSRect r, CGFloat hthickness, CGFloat vthickness,
3690 3453
3691 3454
3692static void 3455static void
3693ns_draw_relief (NSRect r, int hthickness, int vthickness, char raised_p, 3456ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p,
3694 char top_p, char bottom_p, char left_p, char right_p, 3457 char top_p, char bottom_p, char left_p, char right_p,
3695 struct glyph_string *s) 3458 struct glyph_string *s)
3696/* -------------------------------------------------------------------------- 3459/* --------------------------------------------------------------------------
@@ -3701,7 +3464,7 @@ ns_draw_relief (NSRect r, int hthickness, int vthickness, char raised_p,
3701{ 3464{
3702 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil; 3465 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3703 NSColor *newBaseCol = nil; 3466 NSColor *newBaseCol = nil;
3704 NSRect sr = r; 3467 NSRect inner;
3705 3468
3706 NSTRACE ("ns_draw_relief"); 3469 NSTRACE ("ns_draw_relief");
3707 3470
@@ -3735,33 +3498,55 @@ ns_draw_relief (NSRect r, int hthickness, int vthickness, char raised_p,
3735 darkCol = [[baseCol shadowWithLevel: 0.3] retain]; 3498 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3736 } 3499 }
3737 3500
3738 [(raised_p ? lightCol : darkCol) set]; 3501 /* Calculate the inner rectangle. */
3739 3502 inner = NSMakeRect (NSMinX (outer) + (left_p ? hthickness : 0),
3740 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */ 3503 NSMinY (outer) + (top_p ? vthickness : 0),
3504 NSWidth (outer) - (left_p ? hthickness : 0)
3505 - (right_p ? hthickness : 0),
3506 NSHeight (outer) - (top_p ? vthickness : 0)
3507 - (bottom_p ? vthickness : 0));
3741 3508
3742 /* top */ 3509 [(raised_p ? lightCol : darkCol) set];
3743 sr.size.height = hthickness;
3744 if (top_p) NSRectFill (sr);
3745 3510
3746 /* left */ 3511 if (top_p || left_p)
3747 sr.size.height = r.size.height; 3512 {
3748 sr.size.width = vthickness; 3513 NSBezierPath *p = [NSBezierPath bezierPath];
3749 if (left_p) NSRectFill (sr); 3514 [p moveToPoint:NSMakePoint (NSMinX (outer), NSMinY (outer))];
3515 if (top_p)
3516 {
3517 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))];
3518 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))];
3519 }
3520 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMinY (inner))];
3521 if (left_p)
3522 {
3523 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))];
3524 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))];
3525 }
3526 [p closePath];
3527 [p fill];
3528 }
3750 3529
3751 [(raised_p ? darkCol : lightCol) set]; 3530 [(raised_p ? darkCol : lightCol) set];
3752 3531
3753 /* bottom */ 3532 if (bottom_p || right_p)
3754 sr.size.width = r.size.width; 3533 {
3755 sr.size.height = hthickness; 3534 NSBezierPath *p = [NSBezierPath bezierPath];
3756 sr.origin.y += r.size.height - hthickness; 3535 [p moveToPoint:NSMakePoint (NSMaxX (outer), NSMaxY (outer))];
3757 if (bottom_p) NSRectFill (sr); 3536 if (right_p)
3758 3537 {
3759 /* right */ 3538 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))];
3760 sr.size.height = r.size.height; 3539 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))];
3761 sr.origin.y = r.origin.y; 3540 }
3762 sr.size.width = vthickness; 3541 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMaxY (inner))];
3763 sr.origin.x += r.size.width - vthickness; 3542 if (bottom_p)
3764 if (right_p) NSRectFill (sr); 3543 {
3544 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))];
3545 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))];
3546 }
3547 [p closePath];
3548 [p fill];
3549 }
3765} 3550}
3766 3551
3767 3552
@@ -3777,17 +3562,7 @@ ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3777 struct glyph *last_glyph; 3562 struct glyph *last_glyph;
3778 NSRect r; 3563 NSRect r;
3779 int hthickness, vthickness; 3564 int hthickness, vthickness;
3780 struct face *face; 3565 struct face *face = s->face;
3781
3782 if (s->hl == DRAW_MOUSE_FACE)
3783 {
3784 face = FACE_FROM_ID_OR_NULL (s->f,
3785 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3786 if (!face)
3787 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3788 }
3789 else
3790 face = s->face;
3791 3566
3792 vthickness = face->box_vertical_line_width; 3567 vthickness = face->box_vertical_line_width;
3793 hthickness = face->box_horizontal_line_width; 3568 hthickness = face->box_horizontal_line_width;
@@ -3861,34 +3636,26 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3861 || FONT_TOO_HIGH (s->font) 3636 || FONT_TOO_HIGH (s->font)
3862 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) 3637 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3863 { 3638 {
3864 struct face *face; 3639 struct face *face = s->face;
3865 if (s->hl == DRAW_MOUSE_FACE)
3866 {
3867 face
3868 = FACE_FROM_ID_OR_NULL (s->f,
3869 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3870 if (!face)
3871 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3872 }
3873 else
3874 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3875 if (!face->stipple) 3640 if (!face->stipple)
3876 [(NS_FACE_BACKGROUND (face) != 0 3641 {
3877 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) 3642 if (s->hl != DRAW_CURSOR)
3878 : FRAME_BACKGROUND_COLOR (s->f)) set]; 3643 [(NS_FACE_BACKGROUND (face) != 0
3644 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3645 : FRAME_BACKGROUND_COLOR (s->f)) set];
3646 else
3647 [FRAME_CURSOR_COLOR (s->f) set];
3648 }
3879 else 3649 else
3880 { 3650 {
3881 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); 3651 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3882 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; 3652 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3883 } 3653 }
3884 3654
3885 if (s->hl != DRAW_CURSOR) 3655 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3886 { 3656 s->background_width,
3887 NSRect r = NSMakeRect (s->x, s->y + box_line_width, 3657 s->height-2*box_line_width);
3888 s->background_width, 3658 NSRectFill (r);
3889 s->height-2*box_line_width);
3890 NSRectFill (r);
3891 }
3892 3659
3893 s->background_filled_p = 1; 3660 s->background_filled_p = 1;
3894 } 3661 }
@@ -3909,7 +3676,7 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3909 int th; 3676 int th;
3910 char raised_p; 3677 char raised_p;
3911 NSRect br; 3678 NSRect br;
3912 struct face *face; 3679 struct face *face = s->face;
3913 NSColor *tdCol; 3680 NSColor *tdCol;
3914 3681
3915 NSTRACE ("ns_dumpglyphs_image"); 3682 NSTRACE ("ns_dumpglyphs_image");
@@ -3930,15 +3697,6 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3930 /* Draw BG: if we need larger area than image itself cleared, do that, 3697 /* Draw BG: if we need larger area than image itself cleared, do that,
3931 otherwise, since we composite the image under NS (instead of mucking 3698 otherwise, since we composite the image under NS (instead of mucking
3932 with its background color), we must clear just the image area. */ 3699 with its background color), we must clear just the image area. */
3933 if (s->hl == DRAW_MOUSE_FACE)
3934 {
3935 face = FACE_FROM_ID_OR_NULL (s->f,
3936 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3937 if (!face)
3938 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3939 }
3940 else
3941 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3942 3700
3943 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; 3701 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3944 3702
@@ -4009,16 +3767,8 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
4009 3767
4010 if (s->hl == DRAW_CURSOR) 3768 if (s->hl == DRAW_CURSOR)
4011 { 3769 {
4012 [FRAME_CURSOR_COLOR (s->f) set]; 3770 [FRAME_CURSOR_COLOR (s->f) set];
4013 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4014 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); 3771 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
4015 else
4016 /* Currently on NS img->mask is always 0. Since
4017 get_window_cursor_type specifies a hollow box cursor when on
4018 a non-masked image we never reach this clause. But we put it
4019 in, in anticipation of better support for image masks on
4020 NS. */
4021 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
4022 } 3772 }
4023 else 3773 else
4024 { 3774 {
@@ -4070,66 +3820,35 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
4070static void 3820static void
4071ns_dumpglyphs_stretch (struct glyph_string *s) 3821ns_dumpglyphs_stretch (struct glyph_string *s)
4072{ 3822{
4073 NSRect r[2];
4074 NSRect glyphRect; 3823 NSRect glyphRect;
4075 int n; 3824 struct face *face = s->face;
4076 struct face *face;
4077 NSColor *fgCol, *bgCol; 3825 NSColor *fgCol, *bgCol;
4078 3826
4079 if (!s->background_filled_p) 3827 if (!s->background_filled_p)
4080 { 3828 {
4081 n = ns_get_glyph_string_clip_rect (s, r);
4082 ns_focus (s->f, r, n);
4083 3829
4084 if (s->hl == DRAW_MOUSE_FACE) 3830 face = s->face;
4085 {
4086 face = FACE_FROM_ID_OR_NULL (s->f,
4087 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
4088 if (!face)
4089 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
4090 }
4091 else
4092 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4093 3831
4094 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); 3832 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
4095 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); 3833 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
4096 3834
3835 if (s->hl == DRAW_CURSOR)
3836 {
3837 fgCol = bgCol;
3838 bgCol = FRAME_CURSOR_COLOR (s->f);
3839 }
3840
4097 glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); 3841 glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
4098 3842
4099 [bgCol set]; 3843 [bgCol set];
4100 3844
4101 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid 3845 NSRectFill (glyphRect);
4102 overwriting cursor (usually when cursor on a tab) */
4103 if (s->hl == DRAW_CURSOR)
4104 {
4105 CGFloat x, width;
4106
4107 /* FIXME: This looks like it will only work for left to
4108 right languages. */
4109 x = NSMinX (glyphRect);
4110 width = s->w->phys_cursor_width;
4111 glyphRect.size.width -= width;
4112 glyphRect.origin.x += width;
4113
4114 NSRectFill (glyphRect);
4115
4116 /* Draw overlining, etc. on the cursor. */
4117 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4118 ns_draw_text_decoration (s, face, bgCol, width, x);
4119 else
4120 ns_draw_text_decoration (s, face, fgCol, width, x);
4121 }
4122 else
4123 {
4124 NSRectFill (glyphRect);
4125 }
4126 3846
4127 /* Draw overlining, etc. on the stretch glyph (or the part 3847 /* Draw overlining, etc. on the stretch glyph (or the part
4128 of the stretch glyph after the cursor). */ 3848 of the stretch glyph after the cursor). */
4129 ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), 3849 ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
4130 NSMinX (glyphRect)); 3850 NSMinX (glyphRect));
4131 3851
4132 ns_unfocus (s->f);
4133 s->background_filled_p = 1; 3852 s->background_filled_p = 1;
4134 } 3853 }
4135} 3854}
@@ -4138,7 +3857,7 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
4138static void 3857static void
4139ns_draw_glyph_string_foreground (struct glyph_string *s) 3858ns_draw_glyph_string_foreground (struct glyph_string *s)
4140{ 3859{
4141 int x, flags; 3860 int x;
4142 struct font *font = s->font; 3861 struct font *font = s->font;
4143 3862
4144 /* If first glyph of S has a left box line, start drawing the text 3863 /* If first glyph of S has a left box line, start drawing the text
@@ -4149,15 +3868,9 @@ ns_draw_glyph_string_foreground (struct glyph_string *s)
4149 else 3868 else
4150 x = s->x; 3869 x = s->x;
4151 3870
4152 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
4153 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
4154 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
4155 NS_DUMPGLYPH_NORMAL));
4156
4157 font->driver->draw 3871 font->driver->draw
4158 (s, s->cmp_from, s->nchars, x, s->ybase, 3872 (s, s->cmp_from, s->nchars, x, s->ybase,
4159 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) 3873 !s->for_overlaps && !s->background_filled_p);
4160 || flags == NS_DUMPGLYPH_MOUSEFACE);
4161} 3874}
4162 3875
4163 3876
@@ -4264,9 +3977,9 @@ ns_draw_glyph_string (struct glyph_string *s)
4264 struct font *font = s->face->font; 3977 struct font *font = s->face->font;
4265 if (! font) font = FRAME_FONT (s->f); 3978 if (! font) font = FRAME_FONT (s->f);
4266 3979
4267 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); 3980 NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl);
4268 3981
4269 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) 3982 if (s->next && s->right_overhang && !s->for_overlaps)
4270 { 3983 {
4271 int width; 3984 int width;
4272 struct glyph_string *next; 3985 struct glyph_string *next;
@@ -4276,17 +3989,17 @@ ns_draw_glyph_string (struct glyph_string *s)
4276 width += next->width, next = next->next) 3989 width += next->width, next = next->next)
4277 if (next->first_glyph->type != IMAGE_GLYPH) 3990 if (next->first_glyph->type != IMAGE_GLYPH)
4278 { 3991 {
3992 n = ns_get_glyph_string_clip_rect (s->next, r);
3993 ns_focus (s->f, r, n);
4279 if (next->first_glyph->type != STRETCH_GLYPH) 3994 if (next->first_glyph->type != STRETCH_GLYPH)
4280 { 3995 {
4281 n = ns_get_glyph_string_clip_rect (s->next, r);
4282 ns_focus (s->f, r, n);
4283 ns_maybe_dumpglyphs_background (s->next, 1); 3996 ns_maybe_dumpglyphs_background (s->next, 1);
4284 ns_unfocus (s->f);
4285 } 3997 }
4286 else 3998 else
4287 { 3999 {
4288 ns_dumpglyphs_stretch (s->next); 4000 ns_dumpglyphs_stretch (s->next);
4289 } 4001 }
4002 ns_unfocus (s->f);
4290 next->num_clips = 0; 4003 next->num_clips = 0;
4291 } 4004 }
4292 } 4005 }
@@ -4303,14 +4016,21 @@ ns_draw_glyph_string (struct glyph_string *s)
4303 box_drawn_p = 1; 4016 box_drawn_p = 1;
4304 } 4017 }
4305 4018
4019 n = ns_get_glyph_string_clip_rect (s, r);
4020
4021 if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
4022 && !s->clip_tail
4023 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
4024 || (s->next && s->next->hl != s->hl && s->right_overhang)))
4025 r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height));
4026
4027 ns_focus (s->f, r, n);
4028
4306 switch (s->first_glyph->type) 4029 switch (s->first_glyph->type)
4307 { 4030 {
4308 4031
4309 case IMAGE_GLYPH: 4032 case IMAGE_GLYPH:
4310 n = ns_get_glyph_string_clip_rect (s, r);
4311 ns_focus (s->f, r, n);
4312 ns_dumpglyphs_image (s, r[0]); 4033 ns_dumpglyphs_image (s, r[0]);
4313 ns_unfocus (s->f);
4314 break; 4034 break;
4315 4035
4316 case XWIDGET_GLYPH: 4036 case XWIDGET_GLYPH:
@@ -4323,57 +4043,36 @@ ns_draw_glyph_string (struct glyph_string *s)
4323 4043
4324 case CHAR_GLYPH: 4044 case CHAR_GLYPH:
4325 case COMPOSITE_GLYPH: 4045 case COMPOSITE_GLYPH:
4326 n = ns_get_glyph_string_clip_rect (s, r);
4327 ns_focus (s->f, r, n);
4328
4329 if (s->for_overlaps || (s->cmp_from > 0
4330 && ! s->first_glyph->u.cmp.automatic))
4331 s->background_filled_p = 1;
4332 else
4333 ns_maybe_dumpglyphs_background
4334 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4335
4336 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4337 {
4338 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4339 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4340 NS_FACE_FOREGROUND (s->face) = tmp;
4341 }
4342
4343 { 4046 {
4344 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; 4047 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4048 if (s->for_overlaps || (isComposite
4049 && (s->cmp_from > 0
4050 && ! s->first_glyph->u.cmp.automatic)))
4051 s->background_filled_p = 1;
4052 else
4053 ns_maybe_dumpglyphs_background
4054 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4345 4055
4346 if (isComposite) 4056 if (isComposite)
4347 ns_draw_composite_glyph_string_foreground (s); 4057 ns_draw_composite_glyph_string_foreground (s);
4348 else 4058 else
4349 ns_draw_glyph_string_foreground (s); 4059 ns_draw_glyph_string_foreground (s);
4350 }
4351 4060
4352 { 4061 {
4353 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 4062 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4354 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), 4063 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4355 s->f) 4064 s->f)
4356 : FRAME_FOREGROUND_COLOR (s->f)); 4065 : FRAME_FOREGROUND_COLOR (s->f));
4357 [col set]; 4066 [col set];
4358 4067
4359 /* Draw underline, overline, strike-through. */ 4068 /* Draw underline, overline, strike-through. */
4360 ns_draw_text_decoration (s, s->face, col, s->width, s->x); 4069 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4070 }
4361 } 4071 }
4362 4072
4363 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4364 {
4365 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4366 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4367 NS_FACE_FOREGROUND (s->face) = tmp;
4368 }
4369
4370 ns_unfocus (s->f);
4371 break; 4073 break;
4372 4074
4373 case GLYPHLESS_GLYPH: 4075 case GLYPHLESS_GLYPH:
4374 n = ns_get_glyph_string_clip_rect (s, r);
4375 ns_focus (s->f, r, n);
4376
4377 if (s->for_overlaps || (s->cmp_from > 0 4076 if (s->for_overlaps || (s->cmp_from > 0
4378 && ! s->first_glyph->u.cmp.automatic)) 4077 && ! s->first_glyph->u.cmp.automatic))
4379 s->background_filled_p = 1; 4078 s->background_filled_p = 1;
@@ -4383,7 +4082,6 @@ ns_draw_glyph_string (struct glyph_string *s)
4383 /* ... */ 4082 /* ... */
4384 /* Not yet implemented. */ 4083 /* Not yet implemented. */
4385 /* ... */ 4084 /* ... */
4386 ns_unfocus (s->f);
4387 break; 4085 break;
4388 4086
4389 default: 4087 default:
@@ -4392,13 +4090,92 @@ ns_draw_glyph_string (struct glyph_string *s)
4392 4090
4393 /* Draw box if not done already. */ 4091 /* Draw box if not done already. */
4394 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) 4092 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4093 ns_dumpglyphs_box_or_relief (s);
4094
4095 ns_unfocus (s->f);
4096
4097 /* Draw surrounding overhangs. */
4098 if (s->prev)
4395 { 4099 {
4396 n = ns_get_glyph_string_clip_rect (s, r); 4100 ns_focus (s->f, NULL, 0);
4397 ns_focus (s->f, r, n); 4101 struct glyph_string *prev;
4398 ns_dumpglyphs_box_or_relief (s); 4102
4103 for (prev = s->prev; prev; prev = prev->prev)
4104 if (prev->hl != s->hl
4105 && prev->x + prev->width + prev->right_overhang > s->x)
4106 {
4107 /* As prev was drawn while clipped to its own area, we
4108 must draw the right_overhang part using s->hl now. */
4109 enum draw_glyphs_face save = prev->hl;
4110 struct face *save_face = prev->face;
4111
4112 prev->face = s->face;
4113 NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
4114 [[NSGraphicsContext currentContext] saveGraphicsState];
4115 NSRectClip (r);
4116#ifdef NS_IMPL_GNUSTEP
4117 DPSgsave ([NSGraphicsContext currentContext]);
4118 DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
4119 s->width, s->height);
4120#endif
4121 prev->num_clips = 1;
4122 prev->hl = s->hl;
4123 if (prev->first_glyph->type == CHAR_GLYPH)
4124 ns_draw_glyph_string_foreground (prev);
4125 else
4126 ns_draw_composite_glyph_string_foreground (prev);
4127#ifdef NS_IMPL_GNUSTEP
4128 DPSgrestore ([NSGraphicsContext currentContext]);
4129#endif
4130 [[NSGraphicsContext currentContext] restoreGraphicsState];
4131 prev->hl = save;
4132 prev->face = save_face;
4133 prev->num_clips = 0;
4134 }
4399 ns_unfocus (s->f); 4135 ns_unfocus (s->f);
4400 } 4136 }
4401 4137
4138 if (s->next)
4139 {
4140 ns_focus (s->f, NULL, 0);
4141 struct glyph_string *next;
4142
4143 for (next = s->next; next; next = next->next)
4144 if (next->hl != s->hl
4145 && next->x - next->left_overhang < s->x + s->width)
4146 {
4147 /* As next will be drawn while clipped to its own area,
4148 we must draw the left_overhang part using s->hl now. */
4149 enum draw_glyphs_face save = next->hl;
4150 struct face *save_face = next->face;
4151
4152 next->hl = s->hl;
4153 next->face = s->face;
4154 NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
4155 [[NSGraphicsContext currentContext] saveGraphicsState];
4156 NSRectClip (r);
4157#ifdef NS_IMPL_GNUSTEP
4158 DPSgsave ([NSGraphicsContext currentContext]);
4159 DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
4160 s->width, s->height);
4161#endif
4162 next->num_clips = 1;
4163 if (next->first_glyph->type == CHAR_GLYPH)
4164 ns_draw_glyph_string_foreground (next);
4165 else
4166 ns_draw_composite_glyph_string_foreground (next);
4167#ifdef NS_IMPL_GNUSTEP
4168 DPSgrestore ([NSGraphicsContext currentContext]);
4169#endif
4170 [[NSGraphicsContext currentContext] restoreGraphicsState];
4171 next->hl = save;
4172 next->num_clips = 0;
4173 next->face = save_face;
4174 next->clip_head = next;
4175 next->background_filled_p = 0;
4176 }
4177 ns_unfocus (s->f);
4178 }
4402 s->num_clips = 0; 4179 s->num_clips = 0;
4403} 4180}
4404 4181
@@ -5148,6 +4925,17 @@ ns_default_font_parameter (struct frame *f, Lisp_Object parms)
5148{ 4925{
5149} 4926}
5150 4927
4928#ifdef NS_IMPL_GNUSTEP
4929static void
4930ns_update_window_end (struct window *w, bool cursor_on_p,
4931 bool mouse_face_overwritten_p)
4932{
4933 NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p);
4934
4935 ns_redraw_scroll_bars (WINDOW_XFRAME (w));
4936}
4937#endif
4938
5151/* This and next define (many of the) public functions in this file. */ 4939/* This and next define (many of the) public functions in this file. */
5152/* gui_* are generic versions in xdisp.c that we, and other terms, get away 4940/* gui_* are generic versions in xdisp.c that we, and other terms, get away
5153 with using despite presence in the "system dependent" redisplay 4941 with using despite presence in the "system dependent" redisplay
@@ -5164,14 +4952,18 @@ static struct redisplay_interface ns_redisplay_interface =
5164 ns_scroll_run, 4952 ns_scroll_run,
5165 ns_after_update_window_line, 4953 ns_after_update_window_line,
5166 NULL, /* update_window_begin */ 4954 NULL, /* update_window_begin */
4955#ifndef NS_IMPL_GNUSTEP
5167 NULL, /* update_window_end */ 4956 NULL, /* update_window_end */
4957#else
4958 ns_update_window_end,
4959#endif
5168 0, /* flush_display */ 4960 0, /* flush_display */
5169 gui_clear_window_mouse_face, 4961 gui_clear_window_mouse_face,
5170 gui_get_glyph_overhangs, 4962 gui_get_glyph_overhangs,
5171 gui_fix_overlapping_area, 4963 gui_fix_overlapping_area,
5172 ns_draw_fringe_bitmap, 4964 ns_draw_fringe_bitmap,
5173 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */ 4965 ns_define_fringe_bitmap,
5174 0, /* destroy_fringe_bitmap */ 4966 ns_destroy_fringe_bitmap,
5175 ns_compute_glyph_string_overhangs, 4967 ns_compute_glyph_string_overhangs,
5176 ns_draw_glyph_string, 4968 ns_draw_glyph_string,
5177 ns_define_frame_cursor, 4969 ns_define_frame_cursor,
@@ -5209,6 +5001,12 @@ ns_delete_terminal (struct terminal *terminal)
5209 5001
5210 block_input (); 5002 block_input ();
5211 5003
5004#ifdef NS_IMPL_COCOA
5005 /* Rather than try to clean up the NS environment we can just
5006 disable the app and leave it waiting for any new frames. */
5007 [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
5008#endif
5009
5212 image_destroy_all_bitmaps (dpyinfo); 5010 image_destroy_all_bitmaps (dpyinfo);
5213 ns_delete_display (dpyinfo); 5011 ns_delete_display (dpyinfo);
5214 unblock_input (); 5012 unblock_input ();
@@ -5266,6 +5064,7 @@ ns_create_terminal (struct ns_display_info *dpyinfo)
5266 terminal->free_pixmap = ns_free_pixmap; 5064 terminal->free_pixmap = ns_free_pixmap;
5267 terminal->delete_frame_hook = ns_destroy_window; 5065 terminal->delete_frame_hook = ns_destroy_window;
5268 terminal->delete_terminal_hook = ns_delete_terminal; 5066 terminal->delete_terminal_hook = ns_delete_terminal;
5067 terminal->change_tab_bar_height_hook = ns_change_tab_bar_height;
5269 /* Other hooks are NULL by default. */ 5068 /* Other hooks are NULL by default. */
5270 5069
5271 return terminal; 5070 return terminal;
@@ -5357,6 +5156,8 @@ ns_term_init (Lisp_Object display_name)
5357 5156
5358 terminal->name = xlispstrdup (display_name); 5157 terminal->name = xlispstrdup (display_name);
5359 5158
5159 gui_init_fringe (terminal->rif);
5160
5360 unblock_input (); 5161 unblock_input ();
5361 5162
5362 if (!inhibit_x_resources) 5163 if (!inhibit_x_resources)
@@ -6198,11 +5999,6 @@ not_in_argv (NSString *arg)
6198 name:NSViewFrameDidChangeNotification 5999 name:NSViewFrameDidChangeNotification
6199 object:nil]; 6000 object:nil];
6200 6001
6201#ifdef NS_DRAW_TO_BUFFER
6202 [surface release];
6203#endif
6204
6205 [toolbar release];
6206 if (fs_state == FULLSCREEN_BOTH) 6002 if (fs_state == FULLSCREEN_BOTH)
6207 [nonfs_window release]; 6003 [nonfs_window release];
6208 [super dealloc]; 6004 [super dealloc];
@@ -6387,9 +6183,11 @@ not_in_argv (NSString *arg)
6387 Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; 6183 Lisp_Object kind = fnKeysym ? QCfunction : QCordinary;
6388 emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); 6184 emacs_event->modifiers = EV_MODIFIERS2 (flags, kind);
6389 6185
6186#ifndef NS_IMPL_GNUSTEP
6390 if (NS_KEYLOG) 6187 if (NS_KEYLOG)
6391 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", 6188 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6392 code, fnKeysym, flags, emacs_event->modifiers); 6189 code, fnKeysym, flags, emacs_event->modifiers);
6190#endif
6393 6191
6394 /* If it was a function key or had control-like modifiers, pass 6192 /* If it was a function key or had control-like modifiers, pass
6395 it directly to Emacs. */ 6193 it directly to Emacs. */
@@ -6878,10 +6676,35 @@ not_in_argv (NSString *arg)
6878 } 6676 }
6879 else 6677 else
6880 { 6678 {
6881 emacs_event->kind = MOUSE_CLICK_EVENT; 6679 Lisp_Object tab_bar_arg = Qnil;
6680 bool tab_bar_p = false;
6681
6682 if (WINDOWP (emacsframe->tab_bar_window)
6683 && WINDOW_TOTAL_LINES (XWINDOW (emacsframe->tab_bar_window)))
6684 {
6685 Lisp_Object window;
6686 int x = lrint (p.x);
6687 int y = lrint (p.y);
6688
6689 window = window_from_coordinates (emacsframe, x, y, 0, true, true);
6690 tab_bar_p = EQ (window, emacsframe->tab_bar_window);
6691
6692 if (tab_bar_p)
6693 tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, EV_UDMODIFIERS (theEvent) & down_modifier,
6694 EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent));
6695 }
6696
6697 if (!(tab_bar_p && NILP (tab_bar_arg)))
6698 emacs_event->kind = MOUSE_CLICK_EVENT;
6699 emacs_event->arg = tab_bar_arg;
6882 emacs_event->code = EV_BUTTON (theEvent); 6700 emacs_event->code = EV_BUTTON (theEvent);
6883 emacs_event->modifiers = EV_MODIFIERS (theEvent) 6701 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6884 | EV_UDMODIFIERS (theEvent); 6702 | EV_UDMODIFIERS (theEvent);
6703
6704 if (emacs_event->modifiers & down_modifier)
6705 FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent);
6706 else
6707 FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent));
6885 } 6708 }
6886 6709
6887 XSETINT (emacs_event->x, lrint (p.x)); 6710 XSETINT (emacs_event->x, lrint (p.x));
@@ -7148,43 +6971,6 @@ not_in_argv (NSString *arg)
7148} 6971}
7149 6972
7150 6973
7151- (void)windowDidResize: (NSNotification *)notification
7152{
7153 NSTRACE ("[EmacsView windowDidResize:]");
7154 if (!FRAME_LIVE_P (emacsframe))
7155 {
7156 NSTRACE_MSG ("Ignored (frame dead)");
7157 return;
7158 }
7159 if (emacsframe->output_data.ns->in_animation)
7160 {
7161 NSTRACE_MSG ("Ignored (in animation)");
7162 return;
7163 }
7164
7165 if (! [self fsIsNative])
7166 {
7167 NSWindow *theWindow = [notification object];
7168 /* We can get notification on the non-FS window when in
7169 fullscreen mode. */
7170 if ([self window] != theWindow) return;
7171 }
7172
7173 NSTRACE_RECT ("frame", [[notification object] frame]);
7174
7175#ifdef NS_IMPL_GNUSTEP
7176 NSWindow *theWindow = [notification object];
7177
7178 /* In GNUstep, at least currently, it's possible to get a didResize
7179 without getting a willResize, therefore we need to act as if we got
7180 the willResize now. */
7181 NSSize sz = [theWindow frame].size;
7182 sz = [self windowWillResize: theWindow toSize: sz];
7183#endif /* NS_IMPL_GNUSTEP */
7184
7185 ns_send_appdefined (-1);
7186}
7187
7188#ifdef NS_IMPL_COCOA 6974#ifdef NS_IMPL_COCOA
7189- (void)viewDidEndLiveResize 6975- (void)viewDidEndLiveResize
7190{ 6976{
@@ -7202,56 +6988,34 @@ not_in_argv (NSString *arg)
7202#endif /* NS_IMPL_COCOA */ 6988#endif /* NS_IMPL_COCOA */
7203 6989
7204 6990
7205- (void)viewDidResize:(NSNotification *)notification 6991- (void)resizeWithOldSuperviewSize: (NSSize)oldSize
7206{ 6992{
7207 NSRect frame = [self frame]; 6993 NSRect frame;
7208 int neww, newh, oldw, oldh; 6994 int width, height;
7209
7210 if (! FRAME_LIVE_P (emacsframe))
7211 return;
7212
7213 NSTRACE ("[EmacsView viewDidResize]");
7214 6995
7215#ifdef NS_DRAW_TO_BUFFER 6996 NSTRACE ("[EmacsView resizeWithOldSuperviewSize:]");
7216 /* If the buffer size doesn't match the view's backing size, destroy
7217 the buffer and let it be recreated at the correct size later. */
7218 if ([self wantsUpdateLayer] && surface)
7219 {
7220 NSRect surfaceRect = {{0, 0}, [surface getSize]};
7221 NSRect frameRect = [[self window] convertRectToBacking:frame];
7222 6997
7223 if (!NSEqualRects (frameRect, surfaceRect)) 6998 [super resizeWithOldSuperviewSize:oldSize];
7224 {
7225 [surface release];
7226 surface = nil;
7227 6999
7228 [self setNeedsDisplay:YES]; 7000 if (! FRAME_LIVE_P (emacsframe))
7229 } 7001 return;
7230 }
7231#endif
7232 7002
7233 neww = (int)NSWidth (frame); 7003 frame = [[self superview] bounds];
7234 newh = (int)NSHeight (frame); 7004 width = (int)NSWidth (frame);
7235 oldw = FRAME_PIXEL_WIDTH (emacsframe); 7005 height = (int)NSHeight (frame);
7236 oldh = FRAME_PIXEL_HEIGHT (emacsframe);
7237 7006
7238 /* Don't want to do anything when the view size hasn't changed. */ 7007 NSTRACE_SIZE ("New size", NSMakeSize (width, height));
7239 if (emacsframe->new_size_p
7240 ? (newh == emacsframe->new_height
7241 && neww == emacsframe->new_width)
7242 : (oldh == newh && oldw == neww))
7243 {
7244 NSTRACE_MSG ("No change");
7245 return;
7246 }
7247
7248 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
7249 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
7250 7008
7251 change_frame_size (emacsframe, neww, newh, false, YES, false); 7009 /* Reset the frame size to match the bounds of the superview (the
7010 NSWindow's contentView). We need to do this as sometimes the
7011 view's frame isn't resized correctly, or can end up with the
7012 wrong origin. */
7013 [self setFrame:frame];
7014 change_frame_size (emacsframe, width, height, false, YES, false);
7252 7015
7253 SET_FRAME_GARBAGED (emacsframe); 7016 SET_FRAME_GARBAGED (emacsframe);
7254 cancel_mouse_face (emacsframe); 7017 cancel_mouse_face (emacsframe);
7018 ns_send_appdefined (-1);
7255} 7019}
7256 7020
7257 7021
@@ -7309,6 +7073,7 @@ not_in_argv (NSString *arg)
7309 XSETFRAME (frame, emacsframe); 7073 XSETFRAME (frame, emacsframe);
7310 help_echo_string = Qnil; 7074 help_echo_string = Qnil;
7311 gen_help_event (Qnil, frame, Qnil, Qnil, 0); 7075 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7076 any_help_event_p = NO;
7312 } 7077 }
7313 7078
7314 if (emacs_event && is_focus_frame) 7079 if (emacs_event && is_focus_frame)
@@ -7346,42 +7111,8 @@ not_in_argv (NSString *arg)
7346} 7111}
7347 7112
7348 7113
7349- (void)createToolbar: (struct frame *)f
7350{
7351 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7352 NSWindow *window = [view window];
7353
7354 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7355 [NSString stringWithFormat: @"Emacs Frame %d",
7356 ns_window_num]];
7357 [toolbar setVisible: NO];
7358 [window setToolbar: toolbar];
7359
7360 /* Don't set frame garbaged until tool bar is up to date?
7361 This avoids an extra clear and redraw (flicker) at frame creation. */
7362 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7363 else wait_for_tool_bar = NO;
7364
7365
7366#ifdef NS_IMPL_COCOA
7367 {
7368 NSButton *toggleButton;
7369 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7370 [toggleButton setTarget: self];
7371 [toggleButton setAction: @selector (toggleToolbar: )];
7372 }
7373#endif
7374}
7375
7376
7377- (instancetype) initFrameFromEmacs: (struct frame *)f 7114- (instancetype) initFrameFromEmacs: (struct frame *)f
7378{ 7115{
7379 NSRect r, wr;
7380 Lisp_Object tem;
7381 EmacsWindow *win;
7382 NSColor *col;
7383 NSString *name;
7384
7385 NSTRACE ("[EmacsView initFrameFromEmacs:]"); 7116 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7386 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines); 7117 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7387 7118
@@ -7403,21 +7134,11 @@ not_in_argv (NSString *arg)
7403 nonfs_window = nil; 7134 nonfs_window = nil;
7404 7135
7405 ns_userRect = NSMakeRect (0, 0, 0, 0); 7136 ns_userRect = NSMakeRect (0, 0, 0, 0);
7406 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), 7137 [self initWithFrame:
7407 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines)); 7138 NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7408 [self initWithFrame: r]; 7139 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))];
7409 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; 7140 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7410 7141
7411#ifdef NS_DRAW_TO_BUFFER
7412 /* These settings mean AppKit will retain the contents of the frame
7413 on resize. Unfortunately it also means the frame will not be
7414 automatically marked for display, but we can do that ourselves in
7415 viewDidResize. */
7416 [self setLayerContentsRedrawPolicy:
7417 NSViewLayerContentsRedrawOnSetNeedsDisplay];
7418 [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft];
7419#endif
7420
7421 FRAME_NS_VIEW (f) = self; 7142 FRAME_NS_VIEW (f) = self;
7422 emacsframe = f; 7143 emacsframe = f;
7423#ifdef NS_IMPL_COCOA 7144#ifdef NS_IMPL_COCOA
@@ -7425,100 +7146,22 @@ not_in_argv (NSString *arg)
7425 maximizing_resize = NO; 7146 maximizing_resize = NO;
7426#endif 7147#endif
7427 7148
7428 win = [[EmacsWindow alloc] 7149 [[EmacsWindow alloc] initWithEmacsFrame:f];
7429 initWithContentRect: r
7430 styleMask: (FRAME_UNDECORATED (f)
7431 ? FRAME_UNDECORATED_FLAGS
7432 : FRAME_DECORATED_FLAGS)
7433 backing: NSBackingStoreBuffered
7434 defer: YES];
7435 7150
7436#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7151#ifdef NS_IMPL_COCOA
7437#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 7152 /* These settings mean AppKit will retain the contents of the frame
7438 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) 7153 on resize. Unfortunately it also means the frame will not be
7439#endif 7154 automatically marked for display, but we can do that ourselves in
7440 if (FRAME_PARENT_FRAME (f)) 7155 resizeWithOldSuperviewSize. */
7441 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; 7156 [self setWantsLayer:YES];
7442 else 7157 [self setLayerContentsRedrawPolicy:
7443 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; 7158 NSViewLayerContentsRedrawOnSetNeedsDisplay];
7444#endif 7159 [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft];
7445
7446 wr = [win frame];
7447 bwidth = f->border_width = wr.size.width - r.size.width;
7448
7449 [win setAcceptsMouseMovedEvents: YES];
7450 [win setDelegate: self];
7451#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7452#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7453 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7454#endif
7455 [win useOptimizedDrawing: YES];
7456#endif 7160#endif
7457 7161
7458 [[win contentView] addSubview: self];
7459
7460 if (ns_drag_types) 7162 if (ns_drag_types)
7461 [self registerForDraggedTypes: ns_drag_types]; 7163 [self registerForDraggedTypes: ns_drag_types];
7462 7164
7463 tem = f->name;
7464 name = NILP (tem) ? @"Emacs" : [NSString stringWithLispString:tem];
7465 [win setTitle: name];
7466
7467 /* toolbar support */
7468 if (! FRAME_UNDECORATED (f))
7469 [self createToolbar: f];
7470
7471
7472 [win setAppearance];
7473
7474#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7475 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7476 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7477#endif
7478
7479 tem = f->icon_name;
7480 if (!NILP (tem))
7481 [win setMiniwindowTitle:
7482 [NSString stringWithLispString:tem]];
7483
7484 if (FRAME_PARENT_FRAME (f) != NULL)
7485 {
7486 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7487 [parent addChildWindow: win
7488 ordered: NSWindowAbove];
7489 }
7490
7491 if (FRAME_Z_GROUP (f) != z_group_none)
7492 win.level = NSNormalWindowLevel
7493 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7494
7495 {
7496 NSScreen *screen = [win screen];
7497
7498 if (screen != 0)
7499 {
7500 NSPoint pt = NSMakePoint
7501 (IN_BOUND (-SCREENMAX, f->left_pos
7502 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7503 IN_BOUND (-SCREENMAX,
7504 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7505 SCREENMAX));
7506
7507 [win setFrameTopLeftPoint: pt];
7508
7509 NSTRACE_RECT ("new frame", [win frame]);
7510 }
7511 }
7512
7513 [win makeFirstResponder: self];
7514
7515 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7516 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7517 emacsframe);
7518 [win setBackgroundColor: col];
7519 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7520 [win setOpaque: NO];
7521
7522#if !defined (NS_IMPL_COCOA) \ 7165#if !defined (NS_IMPL_COCOA) \
7523 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 7166 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7524#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 7167#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
@@ -7529,21 +7172,6 @@ not_in_argv (NSString *arg)
7529 [NSApp registerServicesMenuSendTypes: ns_send_types 7172 [NSApp registerServicesMenuSendTypes: ns_send_types
7530 returnTypes: [NSArray array]]; 7173 returnTypes: [NSArray array]];
7531 7174
7532 /* Set up view resize notifications. */
7533 [self setPostsFrameChangedNotifications:YES];
7534 [[NSNotificationCenter defaultCenter]
7535 addObserver:self
7536 selector:@selector (viewDidResize:)
7537 name:NSViewFrameDidChangeNotification object:nil];
7538
7539 /* macOS Sierra automatically enables tabbed windows. We can't
7540 allow this to be enabled until it's available on a Free system.
7541 Currently it only happens by accident and is buggy anyway. */
7542#ifdef NS_IMPL_COCOA
7543 if ([win respondsToSelector: @selector(setTabbingMode:)])
7544 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7545#endif
7546
7547 ns_window_num++; 7175 ns_window_num++;
7548 return self; 7176 return self;
7549} 7177}
@@ -7795,7 +7423,6 @@ not_in_argv (NSString *arg)
7795 } 7423 }
7796 else 7424 else
7797 { 7425 {
7798 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7799#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \ 7426#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7800 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 7427 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7801 unsigned val = (unsigned)[NSApp presentationOptions]; 7428 unsigned val = (unsigned)[NSApp presentationOptions];
@@ -7813,7 +7440,6 @@ not_in_argv (NSString *arg)
7813 [NSApp setPresentationOptions: options]; 7440 [NSApp setPresentationOptions: options];
7814 } 7441 }
7815#endif 7442#endif
7816 [toolbar setVisible:tbar_visible];
7817 } 7443 }
7818} 7444}
7819 7445
@@ -7854,14 +7480,6 @@ not_in_argv (NSString *arg)
7854#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7480#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7855 [self updateCollectionBehavior]; 7481 [self updateCollectionBehavior];
7856#endif 7482#endif
7857 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7858 {
7859 [toolbar setVisible:YES];
7860 update_frame_tool_bar (emacsframe);
7861 [[self window] display];
7862 }
7863 else
7864 [toolbar setVisible:NO];
7865 7483
7866 if (next_maximized != -1) 7484 if (next_maximized != -1)
7867 [[self window] performZoom:self]; 7485 [[self window] performZoom:self];
@@ -7906,7 +7524,7 @@ not_in_argv (NSString *arg)
7906 NSWindowCollectionBehavior b = [win collectionBehavior]; 7524 NSWindowCollectionBehavior b = [win collectionBehavior];
7907 if (ns_use_native_fullscreen) 7525 if (ns_use_native_fullscreen)
7908 { 7526 {
7909 if ([win parentWindow]) 7527 if (FRAME_PARENT_FRAME (emacsframe))
7910 { 7528 {
7911 b &= ~NSWindowCollectionBehaviorFullScreenPrimary; 7529 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7912 b |= NSWindowCollectionBehaviorFullScreenAuxiliary; 7530 b |= NSWindowCollectionBehaviorFullScreenAuxiliary;
@@ -7933,7 +7551,7 @@ not_in_argv (NSString *arg)
7933 7551
7934- (void)toggleFullScreen: (id)sender 7552- (void)toggleFullScreen: (id)sender
7935{ 7553{
7936 NSWindow *w, *fw; 7554 EmacsWindow *w, *fw;
7937 BOOL onFirstScreen; 7555 BOOL onFirstScreen;
7938 struct frame *f; 7556 struct frame *f;
7939 NSRect r, wr; 7557 NSRect r, wr;
@@ -7952,7 +7570,7 @@ not_in_argv (NSString *arg)
7952 return; 7570 return;
7953 } 7571 }
7954 7572
7955 w = [self window]; 7573 w = (EmacsWindow *)[self window];
7956 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]]; 7574 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7957 f = emacsframe; 7575 f = emacsframe;
7958 wr = [w frame]; 7576 wr = [w frame];
@@ -7987,27 +7605,9 @@ not_in_argv (NSString *arg)
7987#endif 7605#endif
7988 } 7606 }
7989 7607
7990 fw = [[EmacsFSWindow alloc] 7608 fw = [[EmacsWindow alloc] initWithEmacsFrame:emacsframe
7991 initWithContentRect:[w contentRectForFrameRect:wr] 7609 fullscreen:YES
7992 styleMask:NSWindowStyleMaskBorderless 7610 screen:screen];
7993 backing:NSBackingStoreBuffered
7994 defer:YES
7995 screen:screen];
7996
7997 [fw setContentView:[w contentView]];
7998 [fw setTitle:[w title]];
7999 [fw setDelegate:self];
8000 [fw setAcceptsMouseMovedEvents: YES];
8001#if !defined (NS_IMPL_COCOA) \
8002 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
8003#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
8004 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
8005#endif
8006 [fw useOptimizedDrawing: YES];
8007#endif
8008 [fw setBackgroundColor: col];
8009 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
8010 [fw setOpaque: NO];
8011 7611
8012 f->border_width = 0; 7612 f->border_width = 0;
8013 7613
@@ -8015,7 +7615,6 @@ not_in_argv (NSString *arg)
8015 7615
8016 [self windowWillEnterFullScreen]; 7616 [self windowWillEnterFullScreen];
8017 [fw makeKeyAndOrderFront:NSApp]; 7617 [fw makeKeyAndOrderFront:NSApp];
8018 [fw makeFirstResponder:self];
8019 [w orderOut:self]; 7618 [w orderOut:self];
8020 r = [fw frameRectForContentRect:[screen frame]]; 7619 r = [fw frameRectForContentRect:[screen frame]];
8021 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation]; 7620 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
@@ -8042,7 +7641,7 @@ not_in_argv (NSString *arg)
8042 if ([col alphaComponent] != (EmacsCGFloat) 1.0) 7641 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
8043 [w setOpaque: NO]; 7642 [w setOpaque: NO];
8044 7643
8045 f->border_width = bwidth; 7644 f->border_width = [w borderWidth];
8046 7645
8047 // To do: consider using [NSNotificationCenter postNotificationName:] to 7646 // To do: consider using [NSNotificationCenter postNotificationName:] to
8048 // send notifications. 7647 // send notifications.
@@ -8179,12 +7778,6 @@ not_in_argv (NSString *arg)
8179} 7778}
8180 7779
8181 7780
8182- (EmacsToolbar *)toolbar
8183{
8184 return toolbar;
8185}
8186
8187
8188/* This gets called on toolbar button click. */ 7781/* This gets called on toolbar button click. */
8189- (instancetype)toolbarClicked: (id)item 7782- (instancetype)toolbarClicked: (id)item
8190{ 7783{
@@ -8221,44 +7814,54 @@ not_in_argv (NSString *arg)
8221} 7814}
8222 7815
8223 7816
8224#ifdef NS_DRAW_TO_BUFFER 7817#ifdef NS_IMPL_COCOA
8225- (void)focusOnDrawingBuffer 7818- (CALayer *)makeBackingLayer;
8226{ 7819{
8227 CGFloat scale = [[self window] backingScaleFactor]; 7820 EmacsLayer *l = [[EmacsLayer alloc]
8228 7821 initWithColorSpace:[[[self window] colorSpace] CGColorSpace]];
8229 NSTRACE ("[EmacsView focusOnDrawingBuffer]"); 7822 [l setDelegate:(id)self];
7823 [l setContentsScale:[[self window] backingScaleFactor]];
8230 7824
8231 if (! surface) 7825 return l;
8232 { 7826}
8233 NSRect frame = [self frame];
8234 NSSize s = NSMakeSize (NSWidth (frame) * scale, NSHeight (frame) * scale);
8235 7827
8236 surface = [[EmacsSurface alloc] initWithSize:s
8237 ColorSpace:[[[self window] colorSpace]
8238 CGColorSpace]
8239 Scale:scale];
8240 7828
8241 /* Since we're using NSViewLayerContentsRedrawOnSetNeedsDisplay 7829- (void)lockFocus
8242 the layer's scale factor is not set automatically, so do it 7830{
8243 now. */ 7831 NSTRACE ("[EmacsView lockFocus]");
8244 [[self layer] setContentsScale:scale];
8245 }
8246 7832
8247 CGContextRef context = [surface getContext]; 7833 if ([self wantsLayer])
7834 {
7835 CGContextRef context = [(EmacsLayer*)[self layer] getContext];
8248 7836
8249 [NSGraphicsContext 7837 [NSGraphicsContext
8250 setCurrentContext:[NSGraphicsContext 7838 setCurrentContext:[NSGraphicsContext
8251 graphicsContextWithCGContext:context 7839 graphicsContextWithCGContext:context
8252 flipped:YES]]; 7840 flipped:YES]];
7841 }
7842#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
7843 else
7844 [super lockFocus];
7845#endif
8253} 7846}
8254 7847
8255 7848
8256- (void)unfocusDrawingBuffer 7849- (void)unlockFocus
8257{ 7850{
8258 NSTRACE ("[EmacsView unfocusDrawingBuffer]"); 7851 NSTRACE ("[EmacsView unlockFocus]");
8259 7852
8260 [NSGraphicsContext setCurrentContext:nil]; 7853 if ([self wantsLayer])
8261 [self setNeedsDisplay:YES]; 7854 {
7855 [NSGraphicsContext setCurrentContext:nil];
7856 [self setNeedsDisplay:YES];
7857 }
7858#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
7859 else
7860 {
7861 [super unlockFocus];
7862 [super flushWindow];
7863 }
7864#endif
8262} 7865}
8263 7866
8264 7867
@@ -8267,33 +7870,54 @@ not_in_argv (NSString *arg)
8267{ 7870{
8268 NSTRACE ("EmacsView windowDidChangeBackingProperties:]"); 7871 NSTRACE ("EmacsView windowDidChangeBackingProperties:]");
8269 7872
8270 if ([self wantsUpdateLayer]) 7873 if ([self wantsLayer])
8271 { 7874 {
8272 NSRect frame = [self frame]; 7875 NSRect frame = [self frame];
7876 EmacsLayer *layer = (EmacsLayer *)[self layer];
8273 7877
8274 [surface release]; 7878 [layer setContentsScale:[[notification object] backingScaleFactor]];
8275 surface = nil; 7879 [layer setColorSpace:[[[notification object] colorSpace] CGColorSpace]];
8276 7880
8277 ns_clear_frame (emacsframe); 7881 ns_clear_frame (emacsframe);
8278 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); 7882 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
8279 } 7883 }
8280} 7884}
8281#endif /* NS_DRAW_TO_BUFFER */ 7885#endif /* NS_IMPL_COCOA */
8282 7886
8283 7887
8284- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect 7888- (void)copyRect:(NSRect)srcRect to:(NSPoint)dest
8285{ 7889{
8286 NSTRACE ("[EmacsView copyRect:To:]"); 7890 NSTRACE ("[EmacsView copyRect:To:]");
8287 NSTRACE_RECT ("Source", srcRect); 7891 NSTRACE_RECT ("Source", srcRect);
8288 NSTRACE_RECT ("Destination", dstRect); 7892 NSTRACE_POINT ("Destination", dest);
8289 7893
8290#ifdef NS_DRAW_TO_BUFFER 7894 NSRect dstRect = NSMakeRect (dest.x, dest.y, NSWidth (srcRect),
8291#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7895 NSHeight (srcRect));
8292 if ([self wantsUpdateLayer]) 7896 NSRect frame = [self frame];
7897
7898 /* TODO: This check is an attempt to debug a rare graphical glitch
7899 on macOS and should be removed before the Emacs 28 release. */
7900 if (!NSContainsRect (frame, srcRect)
7901 || !NSContainsRect (frame, dstRect))
7902 {
7903 NSLog (@"[EmacsView copyRect:to:] Attempting to copy to or "
7904 "from an area outside the graphics buffer.");
7905 NSLog (@" Frame: (%f, %f) %f×%f",
7906 NSMinX (frame), NSMinY (frame),
7907 NSWidth (frame), NSHeight (frame));
7908 NSLog (@" Source: (%f, %f) %f×%f",
7909 NSMinX (srcRect), NSMinY (srcRect),
7910 NSWidth (srcRect), NSHeight (srcRect));
7911 NSLog (@" Destination: (%f, %f) %f×%f",
7912 NSMinX (dstRect), NSMinY (dstRect),
7913 NSWidth (dstRect), NSHeight (dstRect));
7914 }
7915
7916#ifdef NS_IMPL_COCOA
7917 if ([self wantsLayer])
8293 { 7918 {
8294#endif
8295 double scale = [[self window] backingScaleFactor]; 7919 double scale = [[self window] backingScaleFactor];
8296 CGContextRef context = [[NSGraphicsContext currentContext] CGContext]; 7920 CGContextRef context = [(EmacsLayer *)[self layer] getContext];
8297 int bpp = CGBitmapContextGetBitsPerPixel (context) / 8; 7921 int bpp = CGBitmapContextGetBitsPerPixel (context) / 8;
8298 void *pixels = CGBitmapContextGetData (context); 7922 void *pixels = CGBitmapContextGetData (context);
8299 int rowSize = CGBitmapContextGetBytesPerRow (context); 7923 int rowSize = CGBitmapContextGetBytesPerRow (context);
@@ -8302,8 +7926,8 @@ not_in_argv (NSString *arg)
8302 + (int) (NSMinY (srcRect) * scale * rowSize 7926 + (int) (NSMinY (srcRect) * scale * rowSize
8303 + NSMinX (srcRect) * scale * bpp); 7927 + NSMinX (srcRect) * scale * bpp);
8304 void *dstPixels = (char *) pixels 7928 void *dstPixels = (char *) pixels
8305 + (int) (NSMinY (dstRect) * scale * rowSize 7929 + (int) (dest.y * scale * rowSize
8306 + NSMinX (dstRect) * scale * bpp); 7930 + dest.x * scale * bpp);
8307 7931
8308 if (NSIntersectsRect (srcRect, dstRect) 7932 if (NSIntersectsRect (srcRect, dstRect)
8309 && NSMinY (srcRect) < NSMinY (dstRect)) 7933 && NSMinY (srcRect) < NSMinY (dstRect))
@@ -8317,14 +7941,14 @@ not_in_argv (NSString *arg)
8317 (char *) srcPixels + y * rowSize, 7941 (char *) srcPixels + y * rowSize,
8318 srcRowSize); 7942 srcRowSize);
8319 7943
8320#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8321 } 7944 }
7945#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8322 else 7946 else
8323 { 7947 {
8324#endif 7948#endif
8325#endif /* NS_DRAW_TO_BUFFER */ 7949#endif /* NS_IMPL_COCOA */
8326 7950
8327#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7951#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8328 hide_bell(); // Ensure the bell image isn't scrolled. 7952 hide_bell(); // Ensure the bell image isn't scrolled.
8329 7953
8330 ns_focus (emacsframe, &dstRect, 1); 7954 ns_focus (emacsframe, &dstRect, 1);
@@ -8333,22 +7957,26 @@ not_in_argv (NSString *arg)
8333 dstRect.origin.y - srcRect.origin.y)]; 7957 dstRect.origin.y - srcRect.origin.y)];
8334 ns_unfocus (emacsframe); 7958 ns_unfocus (emacsframe);
8335#endif 7959#endif
8336#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7960#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8337 } 7961 }
8338#endif 7962#endif
8339} 7963}
8340 7964
8341 7965
8342#ifdef NS_DRAW_TO_BUFFER 7966#ifdef NS_IMPL_COCOA
8343/* If the frame has been garbaged but the toolkit wants to draw, for 7967/* If the frame has been garbaged but the toolkit wants to draw, for
8344 example when resizing the frame, we end up with a blank screen. 7968 example when resizing the frame, we end up with a blank screen.
8345 Sometimes this results in an unpleasant flicker, so try to 7969 Sometimes this results in an unpleasant flicker, so try to
8346 redisplay before drawing. */ 7970 redisplay before drawing.
8347- (void)viewWillDraw 7971
7972 This used to be done in viewWillDraw, but with the custom layer
7973 that method is not called. We cannot call redisplay directly from
7974 [NSView layout], because it may trigger another round of layout by
7975 changing the frame size and recursive layout calls are banned. It
7976 appears to be safe to call redisplay here. */
7977- (void)layoutSublayersOfLayer:(CALayer *)layer
8348{ 7978{
8349 if (FRAME_GARBAGED_P (emacsframe) 7979 if (!redisplaying_p && FRAME_GARBAGED_P (emacsframe))
8350 && !redisplaying_p
8351 && [self wantsUpdateLayer])
8352 { 7980 {
8353 /* If there is IO going on when redisplay is run here Emacs 7981 /* If there is IO going on when redisplay is run here Emacs
8354 crashes. I think it's because this code will always be run 7982 crashes. I think it's because this code will always be run
@@ -8365,45 +7993,8 @@ not_in_argv (NSString *arg)
8365 waiting_for_input = owfi; 7993 waiting_for_input = owfi;
8366 } 7994 }
8367} 7995}
8368
8369
8370- (BOOL)wantsUpdateLayer
8371{
8372#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8373 if (NSAppKitVersionNumber < 1671)
8374 return NO;
8375#endif
8376
8377 /* Running on macOS 10.14 or above. */
8378 return YES;
8379}
8380
8381
8382- (void)updateLayer
8383{
8384 NSTRACE ("[EmacsView updateLayer]");
8385
8386 /* We run redisplay on frames that are garbaged, but marked for
8387 display, before updateLayer is called so if the frame is still
8388 garbaged that means the last redisplay must have refused to
8389 update the frame. */
8390 if (FRAME_GARBAGED_P (emacsframe))
8391 return;
8392
8393 /* This can fail to update the screen if the same surface is
8394 provided twice in a row, even if its contents have changed.
8395 There's a private method, -[CALayer setContentsChanged], that we
8396 could use to force it, but we shouldn't often get the same
8397 surface twice in a row. */
8398 [surface releaseContext];
8399 [[self layer] setContents:(id)[surface getSurface]];
8400 [surface performSelectorOnMainThread:@selector (getContext)
8401 withObject:nil
8402 waitUntilDone:NO];
8403}
8404#endif 7996#endif
8405 7997
8406
8407- (void)drawRect: (NSRect)rect 7998- (void)drawRect: (NSRect)rect
8408{ 7999{
8409 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", 8000 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
@@ -8647,6 +8238,244 @@ not_in_argv (NSString *arg)
8647 8238
8648@implementation EmacsWindow 8239@implementation EmacsWindow
8649 8240
8241
8242- (instancetype) initWithEmacsFrame:(struct frame *)f
8243{
8244 return [self initWithEmacsFrame:f fullscreen:NO screen:nil];
8245}
8246
8247
8248- (instancetype) initWithEmacsFrame:(struct frame *)f
8249 fullscreen:(BOOL)fullscreen
8250 screen:(NSScreen *)screen
8251{
8252 NSWindowStyleMask styleMask;
8253
8254 NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]");
8255
8256 if (fullscreen)
8257 styleMask = NSWindowStyleMaskBorderless;
8258 else if (FRAME_UNDECORATED (f))
8259 styleMask = FRAME_UNDECORATED_FLAGS;
8260 else
8261 styleMask = FRAME_DECORATED_FLAGS;
8262
8263
8264 self = [super initWithContentRect:
8265 NSMakeRect (0, 0,
8266 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
8267 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))
8268 styleMask:styleMask
8269 backing:NSBackingStoreBuffered
8270 defer:YES
8271 screen:screen];
8272 if (self)
8273 {
8274 NSString *name;
8275 NSColor *col;
8276 NSScreen *screen = [self screen];
8277 EmacsView *view = FRAME_NS_VIEW (f);
8278
8279 [self setDelegate:view];
8280 [[self contentView] addSubview:view];
8281 [self makeFirstResponder:view];
8282
8283#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
8284#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
8285 if ([self respondsToSelector: @selector(useOptimizedDrawing:)])
8286#endif
8287 [self useOptimizedDrawing:YES];
8288#endif
8289
8290 [self setAcceptsMouseMovedEvents:YES];
8291
8292 name = NILP (f->name) ? @"Emacs" : [NSString stringWithLispString:f->name];
8293 [self setTitle:name];
8294
8295 if (!NILP (f->icon_name))
8296 [self setMiniwindowTitle:
8297 [NSString stringWithLispString:f->icon_name]];
8298
8299 [self setAppearance];
8300
8301#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
8302 if ([self respondsToSelector:@selector(titlebarAppearsTransparent)])
8303 [self setTitlebarAppearsTransparent:FRAME_NS_TRANSPARENT_TITLEBAR (f)];
8304#endif
8305
8306 [self setParentChildRelationships];
8307
8308 if (FRAME_Z_GROUP (f) != z_group_none)
8309 [self setLevel:NSNormalWindowLevel + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1)];
8310
8311 if (screen != 0)
8312 {
8313 NSPoint pt = NSMakePoint
8314 (IN_BOUND (-SCREENMAX, f->left_pos
8315 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
8316 IN_BOUND (-SCREENMAX,
8317 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
8318 SCREENMAX));
8319
8320 [self setFrameTopLeftPoint:pt];
8321
8322 NSTRACE_RECT ("new frame", [self frame]);
8323 }
8324
8325 f->border_width = [self borderWidth];
8326
8327 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
8328 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
8329 f);
8330 [self setBackgroundColor:col];
8331 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
8332 [self setOpaque:NO];
8333
8334 /* toolbar support */
8335 [self createToolbar:f];
8336
8337 /* macOS Sierra automatically enables tabbed windows. We can't
8338 allow this to be enabled until it's available on a Free system.
8339 Currently it only happens by accident and is buggy anyway. */
8340#ifdef NS_IMPL_COCOA
8341 if ([self respondsToSelector:@selector(setTabbingMode:)])
8342 [self setTabbingMode:NSWindowTabbingModeDisallowed];
8343#endif
8344 }
8345
8346 return self;
8347}
8348
8349
8350- (void)createToolbar: (struct frame *)f
8351{
8352 if (FRAME_UNDECORATED (f) || !FRAME_EXTERNAL_TOOL_BAR (f))
8353 return;
8354
8355 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
8356
8357 EmacsToolbar *toolbar = [[EmacsToolbar alloc]
8358 initForView:view
8359 withIdentifier:[NSString stringWithLispString:f->name]];
8360
8361 [self setToolbar:toolbar];
8362 update_frame_tool_bar_1 (f, toolbar);
8363
8364#ifdef NS_IMPL_COCOA
8365 {
8366 NSButton *toggleButton;
8367 toggleButton = [self standardWindowButton:NSWindowToolbarButton];
8368 [toggleButton setTarget:view];
8369 [toggleButton setAction:@selector (toggleToolbar:)];
8370 }
8371#endif
8372}
8373
8374- (void)dealloc
8375{
8376 NSTRACE ("[EmacsWindow dealloc]");
8377
8378 /* We need to release the toolbar ourselves. */
8379 [[self toolbar] release];
8380 [super dealloc];
8381}
8382
8383- (NSInteger) borderWidth
8384{
8385 return NSWidth ([self frame]) - NSWidth ([[self contentView] frame]);
8386}
8387
8388
8389- (void)setParentChildRelationships
8390 /* After certain operations, for example making a frame visible or
8391 resetting the NSWindow through modifying the undecorated status,
8392 the parent/child relationship may be broken. We can also use
8393 this method to set them, as long as the frame struct already has
8394 the correct relationship set. */
8395{
8396 NSTRACE ("[EmacsWindow setParentChildRelationships]");
8397
8398 Lisp_Object frame, tail;
8399 EmacsView *ourView = (EmacsView *)[self delegate];
8400 struct frame *ourFrame = ourView->emacsframe;
8401 struct frame *parentFrame = FRAME_PARENT_FRAME (ourFrame);
8402 EmacsWindow *oldParentWindow = (EmacsWindow *)[self parentWindow];
8403
8404
8405#ifdef NS_IMPL_COCOA
8406 /* We have to set the accessibility subroles and/or the collection
8407 behaviors early otherwise child windows may not go fullscreen as
8408 expected later. */
8409
8410#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
8411 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)])
8412#endif
8413 /* Set the accessibility subroles. */
8414 if (parentFrame)
8415 [self setAccessibilitySubrole:NSAccessibilityFloatingWindowSubrole];
8416 else
8417 [self setAccessibilitySubrole:NSAccessibilityStandardWindowSubrole];
8418
8419#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8420 [ourView updateCollectionBehavior];
8421#endif
8422#endif
8423
8424
8425 /* Check if we have an incorrectly set parent. */
8426 if ((! parentFrame && oldParentWindow)
8427 || (parentFrame && oldParentWindow
8428 && ((EmacsView *)[oldParentWindow delegate])->emacsframe != parentFrame))
8429 {
8430 [[self parentWindow] removeChildWindow:self];
8431
8432#ifdef NS_IMPL_COCOA
8433#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8434 if ([ourView respondsToSelector:@selector (toggleFullScreen)]
8435#endif
8436 /* If we are the descendent of a fullscreen window and we
8437 have no new parent, go fullscreen. */
8438 {
8439 NSWindow *parent = (NSWindow *)oldParentWindow;
8440 while (parent)
8441 {
8442 if (([parent styleMask] & NSWindowStyleMaskFullScreen) != 0)
8443 {
8444 [ourView toggleFullScreen:self];
8445 break;
8446 }
8447 parent = [parent parentWindow];
8448 }
8449 }
8450#endif
8451 }
8452
8453 if (parentFrame)
8454 {
8455 NSWindow *parentWindow = [FRAME_NS_VIEW (parentFrame) window];
8456
8457#ifdef NS_IMPL_COCOA
8458#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8459 if ([ourView respondsToSelector:@selector (toggleFullScreen)]
8460#endif
8461 /* Child frames must not be fullscreen. */
8462 if ([ourView fsIsNative] && [ourView isFullscreen])
8463 [ourView toggleFullScreen:self];
8464#endif
8465
8466 [parentWindow addChildWindow:self
8467 ordered:NSWindowAbove];
8468 }
8469
8470 /* Check our child windows are configured correctly. */
8471 FOR_EACH_FRAME (tail, frame)
8472 {
8473 if (FRAME_PARENT_FRAME (XFRAME (frame)) == ourFrame)
8474 [(EmacsWindow *)[FRAME_NS_VIEW (XFRAME (frame)) window] setParentChildRelationships];
8475 }
8476}
8477
8478
8650/* It seems the only way to reorder child frames is by removing them 8479/* It seems the only way to reorder child frames is by removing them
8651 from the parent and then reattaching them in the correct order. */ 8480 from the parent and then reattaching them in the correct order. */
8652 8481
@@ -9056,22 +8885,15 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9056{ 8885{
9057 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe); 8886 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
9058} 8887}
9059@end /* EmacsWindow */
9060
9061
9062@implementation EmacsFSWindow
9063
9064- (BOOL)canBecomeKeyWindow
9065{
9066 return YES;
9067}
9068 8888
9069- (BOOL)canBecomeMainWindow 8889- (BOOL)canBecomeMainWindow
8890 /* Required for fullscreen and undecorated windows. */
9070{ 8891{
9071 return YES; 8892 return YES;
9072} 8893}
9073 8894
9074@end 8895@end /* EmacsWindow */
8896
9075 8897
9076/* ========================================================================== 8898/* ==========================================================================
9077 8899
@@ -9570,7 +9392,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9570@end /* EmacsScroller */ 9392@end /* EmacsScroller */
9571 9393
9572 9394
9573#ifdef NS_DRAW_TO_BUFFER 9395#ifdef NS_IMPL_COCOA
9574 9396
9575/* ========================================================================== 9397/* ==========================================================================
9576 9398
@@ -9578,7 +9400,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9578 9400
9579 ========================================================================== */ 9401 ========================================================================== */
9580 9402
9581@implementation EmacsSurface 9403@implementation EmacsLayer
9582 9404
9583 9405
9584/* An IOSurface is a pixel buffer that is efficiently copied to VRAM 9406/* An IOSurface is a pixel buffer that is efficiently copied to VRAM
@@ -9591,80 +9413,109 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9591 ability to draw to the screen at any time, we need to keep a cache 9413 ability to draw to the screen at any time, we need to keep a cache
9592 of multiple surfaces that we can use at will. 9414 of multiple surfaces that we can use at will.
9593 9415
9594 The EmacsSurface class maintains this cache of surfaces, and 9416 The EmacsLayer class maintains this cache of surfaces, and
9595 handles the conversion to a CGGraphicsContext that AppKit can use 9417 handles the conversion to a CGGraphicsContext that AppKit can use
9596 to draw on. 9418 to draw on.
9597 9419
9598 The cache is simple: if a free surface is found it is removed from 9420 The cache is simple: if a free surface is found it is removed from
9599 the cache and set as the "current" surface. Once Emacs is done 9421 the cache and set as the "current" surface. Emacs draws to the
9600 with drawing to the current surface, the previous surface that was 9422 surface and when the layer wants to update the screen we set it's
9601 drawn to is added to the cache for reuse, and the current one is 9423 contents to the surface and then add it back on to the end of the
9602 set as the last surface. If no free surfaces are found in the 9424 cache. If no free surfaces are found in the cache then a new one
9603 cache then a new one is created. 9425 is created. */
9604
9605 When AppKit wants to update the screen, we provide it with the last
9606 surface, as that has the most recent data.
9607
9608 FIXME: It is possible for the cache to grow if Emacs draws faster
9609 than the surfaces can be drawn to the screen, so there should
9610 probably be some sort of pruning job that removes excess
9611 surfaces. */
9612 9426
9613#define CACHE_MAX_SIZE 2 9427#define CACHE_MAX_SIZE 2
9614 9428
9615- (id) initWithSize: (NSSize)s 9429- (id) initWithColorSpace: (CGColorSpaceRef)cs
9616 ColorSpace: (CGColorSpaceRef)cs
9617 Scale: (CGFloat)scl
9618{ 9430{
9619 NSTRACE ("[EmacsSurface initWithSize:ColorSpace:]"); 9431 NSTRACE ("[EmacsLayer initWithColorSpace:]");
9620
9621 [super init];
9622 9432
9623 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain]; 9433 self = [super init];
9624 size = s; 9434 if (self)
9625 colorSpace = cs; 9435 {
9626 scale = scl; 9436 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain];
9437 [self setColorSpace:cs];
9438 }
9439 else
9440 {
9441 return nil;
9442 }
9627 9443
9628 return self; 9444 return self;
9629} 9445}
9630 9446
9631 9447
9632- (void) dealloc 9448- (void) setColorSpace: (CGColorSpaceRef)cs
9633{ 9449{
9634 if (context) 9450 /* We don't need to clear the cache because the new colorspace will
9635 CGContextRelease (context); 9451 be used next time we create a new context. */
9636 9452 if (cs)
9637 if (currentSurface) 9453 colorSpace = cs;
9638 CFRelease (currentSurface); 9454 else
9455 colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
9456}
9639 9457
9640 for (id object in cache)
9641 CFRelease ((IOSurfaceRef)object);
9642 9458
9459- (void) dealloc
9460{
9461 [self releaseSurfaces];
9643 [cache release]; 9462 [cache release];
9644 9463
9645 [super dealloc]; 9464 [super dealloc];
9646} 9465}
9647 9466
9648 9467
9649/* Return the size values our cached data is using. */ 9468- (void) releaseSurfaces
9650- (NSSize) getSize
9651{ 9469{
9652 return size; 9470 [self setContents:nil];
9471 [self releaseContext];
9472
9473 if (currentSurface)
9474 {
9475 CFRelease (currentSurface);
9476 currentSurface = nil;
9477 }
9478
9479 if (cache)
9480 {
9481 for (id object in cache)
9482 CFRelease ((IOSurfaceRef)object);
9483
9484 [cache removeAllObjects];
9485 }
9653} 9486}
9654 9487
9655 9488
9656/* Return a CGContextRef that can be used for drawing to the screen. 9489/* Check whether the current bounds match the IOSurfaces we are using.
9657 This must ALWAYS be paired with a call to releaseContext, and the 9490 If they do return YES, otherwise NO. */
9658 calls cannot be nested. */ 9491- (BOOL) checkDimensions
9492{
9493 int width = NSWidth ([self bounds]) * [self contentsScale];
9494 int height = NSHeight ([self bounds]) * [self contentsScale];
9495 IOSurfaceRef s = currentSurface ? currentSurface
9496 : (IOSurfaceRef)[cache firstObject];
9497
9498 return !s || (IOSurfaceGetWidth (s) == width
9499 && IOSurfaceGetHeight (s) == height);
9500}
9501
9502
9503/* Return a CGContextRef that can be used for drawing to the screen. */
9659- (CGContextRef) getContext 9504- (CGContextRef) getContext
9660{ 9505{
9661 NSTRACE ("[EmacsSurface getContext]"); 9506 CGFloat scale = [self contentsScale];
9507
9508 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer getContext]");
9509 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (currentSurface ? 1 : 0));
9510
9511 if (![self checkDimensions])
9512 [self releaseSurfaces];
9662 9513
9663 if (!context) 9514 if (!context)
9664 { 9515 {
9665 IOSurfaceRef surface = NULL; 9516 IOSurfaceRef surface = NULL;
9666 9517 int width = NSWidth ([self bounds]) * scale;
9667 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0)); 9518 int height = NSHeight ([self bounds]) * scale;
9668 9519
9669 for (id object in cache) 9520 for (id object in cache)
9670 { 9521 {
@@ -9687,16 +9538,22 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9687 else if (!surface) 9538 else if (!surface)
9688 { 9539 {
9689 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow, 9540 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow,
9690 size.width * 4); 9541 width * 4);
9691 9542
9692 surface = IOSurfaceCreate 9543 surface = IOSurfaceCreate
9693 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:size.width], 9544 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:width],
9694 (id)kIOSurfaceHeight:[NSNumber numberWithInt:size.height], 9545 (id)kIOSurfaceHeight:[NSNumber numberWithInt:height],
9695 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow], 9546 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow],
9696 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4], 9547 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4],
9697 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']}); 9548 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']});
9698 } 9549 }
9699 9550
9551 if (!surface)
9552 {
9553 NSLog (@"Failed to create IOSurface for frame %@", [self delegate]);
9554 return nil;
9555 }
9556
9700 IOReturn lockStatus = IOSurfaceLock (surface, 0, nil); 9557 IOReturn lockStatus = IOSurfaceLock (surface, 0, nil);
9701 if (lockStatus != kIOReturnSuccess) 9558 if (lockStatus != kIOReturnSuccess)
9702 NSLog (@"Failed to lock surface: %x", lockStatus); 9559 NSLog (@"Failed to lock surface: %x", lockStatus);
@@ -9714,7 +9571,16 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9714 (kCGImageAlphaPremultipliedFirst 9571 (kCGImageAlphaPremultipliedFirst
9715 | kCGBitmapByteOrder32Host)); 9572 | kCGBitmapByteOrder32Host));
9716 9573
9717 CGContextTranslateCTM(context, 0, size.height); 9574 if (!context)
9575 {
9576 NSLog (@"Failed to create context for frame %@", [self delegate]);
9577 IOSurfaceUnlock (currentSurface, 0, nil);
9578 CFRelease (currentSurface);
9579 currentSurface = nil;
9580 return nil;
9581 }
9582
9583 CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface));
9718 CGContextScaleCTM(context, scale, -scale); 9584 CGContextScaleCTM(context, scale, -scale);
9719 } 9585 }
9720 9586
@@ -9726,7 +9592,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9726 IOSurface, so it will be sent to VRAM. */ 9592 IOSurface, so it will be sent to VRAM. */
9727- (void) releaseContext 9593- (void) releaseContext
9728{ 9594{
9729 NSTRACE ("[EmacsSurface releaseContextAndGetSurface]"); 9595 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer releaseContext]");
9730 9596
9731 if (!context) 9597 if (!context)
9732 return; 9598 return;
@@ -9737,19 +9603,34 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9737 IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil); 9603 IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil);
9738 if (lockStatus != kIOReturnSuccess) 9604 if (lockStatus != kIOReturnSuccess)
9739 NSLog (@"Failed to unlock surface: %x", lockStatus); 9605 NSLog (@"Failed to unlock surface: %x", lockStatus);
9740
9741 /* Put currentSurface back on the end of the cache. */
9742 [cache addObject:(id)currentSurface];
9743 lastSurface = currentSurface;
9744 currentSurface = NULL;
9745} 9606}
9746 9607
9747 9608
9748/* Get the IOSurface that we want to draw to the screen. */ 9609- (void) display
9749- (IOSurfaceRef) getSurface
9750{ 9610{
9751 /* lastSurface always contains the most up-to-date and complete data. */ 9611 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
9752 return lastSurface; 9612
9613 if (context)
9614 {
9615 [self releaseContext];
9616
9617#if CACHE_MAX_SIZE == 1
9618 /* This forces the layer to see the surface as updated. */
9619 [self setContents:nil];
9620#endif
9621
9622 [self setContents:(id)currentSurface];
9623
9624 /* Put currentSurface back on the end of the cache. */
9625 [cache addObject:(id)currentSurface];
9626 currentSurface = NULL;
9627
9628 /* Schedule a run of getContext so that if Emacs is idle it will
9629 perform the buffer copy, etc. */
9630 [self performSelectorOnMainThread:@selector (getContext)
9631 withObject:nil
9632 waitUntilDone:NO];
9633 }
9753} 9634}
9754 9635
9755 9636
@@ -9759,19 +9640,20 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9759- (void) copyContentsTo: (IOSurfaceRef) destination 9640- (void) copyContentsTo: (IOSurfaceRef) destination
9760{ 9641{
9761 IOReturn lockStatus; 9642 IOReturn lockStatus;
9643 IOSurfaceRef source = (IOSurfaceRef)[self contents];
9762 void *sourceData, *destinationData; 9644 void *sourceData, *destinationData;
9763 int numBytes = IOSurfaceGetAllocSize (destination); 9645 int numBytes = IOSurfaceGetAllocSize (destination);
9764 9646
9765 NSTRACE ("[EmacsSurface copyContentsTo:]"); 9647 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
9766 9648
9767 if (!lastSurface || lastSurface == destination) 9649 if (!source || source == destination)
9768 return; 9650 return;
9769 9651
9770 lockStatus = IOSurfaceLock (lastSurface, kIOSurfaceLockReadOnly, nil); 9652 lockStatus = IOSurfaceLock (source, kIOSurfaceLockReadOnly, nil);
9771 if (lockStatus != kIOReturnSuccess) 9653 if (lockStatus != kIOReturnSuccess)
9772 NSLog (@"Failed to lock source surface: %x", lockStatus); 9654 NSLog (@"Failed to lock source surface: %x", lockStatus);
9773 9655
9774 sourceData = IOSurfaceGetBaseAddress (lastSurface); 9656 sourceData = IOSurfaceGetBaseAddress (source);
9775 destinationData = IOSurfaceGetBaseAddress (destination); 9657 destinationData = IOSurfaceGetBaseAddress (destination);
9776 9658
9777 /* Since every IOSurface should have the exact same settings, a 9659 /* Since every IOSurface should have the exact same settings, a
@@ -9779,17 +9661,17 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9779 the other. */ 9661 the other. */
9780 memcpy (destinationData, sourceData, numBytes); 9662 memcpy (destinationData, sourceData, numBytes);
9781 9663
9782 lockStatus = IOSurfaceUnlock (lastSurface, kIOSurfaceLockReadOnly, nil); 9664 lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil);
9783 if (lockStatus != kIOReturnSuccess) 9665 if (lockStatus != kIOReturnSuccess)
9784 NSLog (@"Failed to unlock source surface: %x", lockStatus); 9666 NSLog (@"Failed to unlock source surface: %x", lockStatus);
9785} 9667}
9786 9668
9787#undef CACHE_MAX_SIZE 9669#undef CACHE_MAX_SIZE
9788 9670
9789@end /* EmacsSurface */ 9671@end /* EmacsLayer */
9790 9672
9791 9673
9792#endif 9674#endif /* NS_IMPL_COCOA */
9793 9675
9794 9676
9795#ifdef NS_IMPL_GNUSTEP 9677#ifdef NS_IMPL_GNUSTEP
diff --git a/src/pdumper.c b/src/pdumper.c
index 7730ea3d061..9eff5c48d09 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -312,14 +312,15 @@ dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset)
312 error ("dump relocation out of range"); 312 error ("dump relocation out of range");
313} 313}
314 314
315static void 315void
316dump_fingerprint (char const *label, 316dump_fingerprint (FILE *output, char const *label,
317 unsigned char const xfingerprint[sizeof fingerprint]) 317 unsigned char const xfingerprint[sizeof fingerprint])
318{ 318{
319 enum { hexbuf_size = 2 * sizeof fingerprint }; 319 enum { hexbuf_size = 2 * sizeof fingerprint };
320 char hexbuf[hexbuf_size]; 320 char hexbuf[hexbuf_size];
321 hexbuf_digest (hexbuf, xfingerprint, sizeof fingerprint); 321 hexbuf_digest (hexbuf, xfingerprint, sizeof fingerprint);
322 fprintf (stderr, "%s: %.*s\n", label, hexbuf_size, hexbuf); 322 fprintf (output, "%s%s%.*s\n", label, *label ? ": " : "",
323 hexbuf_size, hexbuf);
323} 324}
324 325
325/* To be used if some order in the relocation process has to be enforced. */ 326/* To be used if some order in the relocation process has to be enforced. */
@@ -799,7 +800,7 @@ dump_tailq_length (const struct dump_tailq *tailq)
799 return tailq->length; 800 return tailq->length;
800} 801}
801 802
802static void ATTRIBUTE_UNUSED 803static void
803dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value) 804dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value)
804{ 805{
805 Lisp_Object link = Fcons (value, tailq->head); 806 Lisp_Object link = Fcons (value, tailq->head);
@@ -809,24 +810,6 @@ dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value)
809 tailq->length += 1; 810 tailq->length += 1;
810} 811}
811 812
812static void ATTRIBUTE_UNUSED
813dump_tailq_append (struct dump_tailq *tailq, Lisp_Object value)
814{
815 Lisp_Object link = Fcons (value, Qnil);
816 if (NILP (tailq->head))
817 {
818 eassert (NILP (tailq->tail));
819 tailq->head = tailq->tail = link;
820 }
821 else
822 {
823 eassert (!NILP (tailq->tail));
824 XSETCDR (tailq->tail, link);
825 tailq->tail = link;
826 }
827 tailq->length += 1;
828}
829
830static bool 813static bool
831dump_tailq_empty_p (struct dump_tailq *tailq) 814dump_tailq_empty_p (struct dump_tailq *tailq)
832{ 815{
@@ -4145,7 +4128,7 @@ types. */)
4145 ctx->header.fingerprint[i] = fingerprint[i]; 4128 ctx->header.fingerprint[i] = fingerprint[i];
4146 4129
4147 const dump_off header_start = ctx->offset; 4130 const dump_off header_start = ctx->offset;
4148 dump_fingerprint ("Dumping fingerprint", ctx->header.fingerprint); 4131 dump_fingerprint (stderr, "Dumping fingerprint", ctx->header.fingerprint);
4149 dump_write (ctx, &ctx->header, sizeof (ctx->header)); 4132 dump_write (ctx, &ctx->header, sizeof (ctx->header));
4150 const dump_off header_end = ctx->offset; 4133 const dump_off header_end = ctx->offset;
4151 4134
@@ -4537,15 +4520,28 @@ dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
4537 uint32_t offset_low = (uint32_t) (full_offset & 0xffffffff); 4520 uint32_t offset_low = (uint32_t) (full_offset & 0xffffffff);
4538 4521
4539 int error; 4522 int error;
4523 DWORD protect;
4540 DWORD map_access; 4524 DWORD map_access;
4541 4525
4542 file = (HANDLE) _get_osfhandle (fd); 4526 file = (HANDLE) _get_osfhandle (fd);
4543 if (file == INVALID_HANDLE_VALUE) 4527 if (file == INVALID_HANDLE_VALUE)
4544 goto out; 4528 goto out;
4545 4529
4530 switch (protection)
4531 {
4532 case DUMP_MEMORY_ACCESS_READWRITE:
4533 protect = PAGE_WRITECOPY; /* for Windows 9X */
4534 break;
4535 default:
4536 case DUMP_MEMORY_ACCESS_NONE:
4537 case DUMP_MEMORY_ACCESS_READ:
4538 protect = PAGE_READONLY;
4539 break;
4540 }
4541
4546 section = CreateFileMapping (file, 4542 section = CreateFileMapping (file,
4547 /*lpAttributes=*/NULL, 4543 /*lpAttributes=*/NULL,
4548 PAGE_READONLY, 4544 protect,
4549 /*dwMaximumSizeHigh=*/0, 4545 /*dwMaximumSizeHigh=*/0,
4550 /*dwMaximumSizeLow=*/0, 4546 /*dwMaximumSizeLow=*/0,
4551 /*lpName=*/NULL); 4547 /*lpName=*/NULL);
@@ -5300,6 +5296,9 @@ dump_do_dump_relocation (const uintptr_t dump_base,
5300 error ("Trying to load incoherent dumped eln file %s", 5296 error ("Trying to load incoherent dumped eln file %s",
5301 SSDATA (comp_u->file)); 5297 SSDATA (comp_u->file));
5302 5298
5299 if (!CONSP (comp_u->file))
5300 error ("Incoherent compilation unit for dump was dumped");
5301
5303 /* emacs_execdir is always unibyte, but the file names in 5302 /* emacs_execdir is always unibyte, but the file names in
5304 comp_u->file could be multibyte, so we need to encode 5303 comp_u->file could be multibyte, so we need to encode
5305 them. */ 5304 them. */
@@ -5601,8 +5600,8 @@ pdumper_load (const char *dump_filename, char *argv0)
5601 desired[i] = fingerprint[i]; 5600 desired[i] = fingerprint[i];
5602 if (memcmp (header->fingerprint, desired, sizeof desired) != 0) 5601 if (memcmp (header->fingerprint, desired, sizeof desired) != 0)
5603 { 5602 {
5604 dump_fingerprint ("desired fingerprint", desired); 5603 dump_fingerprint (stderr, "desired fingerprint", desired);
5605 dump_fingerprint ("found fingerprint", header->fingerprint); 5604 dump_fingerprint (stderr, "found fingerprint", header->fingerprint);
5606 goto out; 5605 goto out;
5607 } 5606 }
5608 5607
@@ -5710,6 +5709,7 @@ pdumper_load (const char *dump_filename, char *argv0)
5710 dump_mmap_release (&sections[i]); 5709 dump_mmap_release (&sections[i]);
5711 if (dump_fd >= 0) 5710 if (dump_fd >= 0)
5712 emacs_close (dump_fd); 5711 emacs_close (dump_fd);
5712
5713 return err; 5713 return err;
5714} 5714}
5715 5715
@@ -5794,6 +5794,7 @@ syms_of_pdumper (void)
5794 DEFSYM (Qdumped_with_pdumper, "dumped-with-pdumper"); 5794 DEFSYM (Qdumped_with_pdumper, "dumped-with-pdumper");
5795 DEFSYM (Qload_time, "load-time"); 5795 DEFSYM (Qload_time, "load-time");
5796 DEFSYM (Qdump_file_name, "dump-file-name"); 5796 DEFSYM (Qdump_file_name, "dump-file-name");
5797 DEFSYM (Qafter_pdump_load_hook, "after-pdump-load-hook");
5797 defsubr (&Spdumper_stats); 5798 defsubr (&Spdumper_stats);
5798#endif /* HAVE_PDUMPER */ 5799#endif /* HAVE_PDUMPER */
5799} 5800}
diff --git a/src/pdumper.h b/src/pdumper.h
index deec9af046d..7f1f5e46ad9 100644
--- a/src/pdumper.h
+++ b/src/pdumper.h
@@ -20,6 +20,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20#ifndef EMACS_PDUMPER_H 20#ifndef EMACS_PDUMPER_H
21#define EMACS_PDUMPER_H 21#define EMACS_PDUMPER_H
22 22
23#include <stdio.h>
24#include "fingerprint.h"
23#include "lisp.h" 25#include "lisp.h"
24 26
25INLINE_HEADER_BEGIN 27INLINE_HEADER_BEGIN
@@ -50,6 +52,9 @@ enum { PDUMPER_NO_OBJECT = -1 };
50#define PDUMPER_REMEMBER_SCALAR(thing) \ 52#define PDUMPER_REMEMBER_SCALAR(thing) \
51 pdumper_remember_scalar (&(thing), sizeof (thing)) 53 pdumper_remember_scalar (&(thing), sizeof (thing))
52 54
55extern void dump_fingerprint (FILE *output, const char *label,
56 unsigned char const fingerp[sizeof fingerprint]);
57
53extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes); 58extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes);
54 59
55INLINE void 60INLINE void
diff --git a/src/print.c b/src/print.c
index d4301fd7b64..adadb289de0 100644
--- a/src/print.c
+++ b/src/print.c
@@ -564,7 +564,7 @@ temp_output_buffer_setup (const char *bufname)
564 564
565 Fset_buffer (Fget_buffer_create (build_string (bufname), Qnil)); 565 Fset_buffer (Fget_buffer_create (build_string (bufname), Qnil));
566 566
567 Fkill_all_local_variables (); 567 Fkill_all_local_variables (Qnil);
568 delete_all_overlays (current_buffer); 568 delete_all_overlays (current_buffer);
569 bset_directory (current_buffer, BVAR (old, directory)); 569 bset_directory (current_buffer, BVAR (old, directory));
570 bset_read_only (current_buffer, Qnil); 570 bset_read_only (current_buffer, Qnil);
@@ -941,7 +941,11 @@ print_error_message (Lisp_Object data, Lisp_Object stream, const char *context,
941 else 941 else
942 { 942 {
943 Lisp_Object error_conditions = Fget (errname, Qerror_conditions); 943 Lisp_Object error_conditions = Fget (errname, Qerror_conditions);
944 errmsg = call1 (Qsubstitute_command_keys, Fget (errname, Qerror_message)); 944 errmsg = Fget (errname, Qerror_message);
945 /* During loadup 'substitute-command-keys' might not be available. */
946 if (!NILP (Ffboundp (Qsubstitute_command_keys)))
947 errmsg = call1 (Qsubstitute_command_keys, errmsg);
948
945 file_error = Fmemq (Qfile_error, error_conditions); 949 file_error = Fmemq (Qfile_error, error_conditions);
946 } 950 }
947 951
@@ -1517,8 +1521,26 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
1517 printchar ('>', printcharfun); 1521 printchar ('>', printcharfun);
1518 break; 1522 break;
1519 1523
1520 case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: 1524 case PVEC_XWIDGET:
1521 print_c_string ("#<xwidget ", printcharfun); 1525#ifdef HAVE_XWIDGETS
1526 {
1527#ifdef USE_GTK
1528 int len = sprintf (buf, "#<xwidget %u %p>",
1529 XXWIDGET (obj)->xwidget_id,
1530 XXWIDGET (obj)->widget_osr);
1531#else
1532 int len = sprintf (buf, "#<xwidget %u %p>",
1533 XXWIDGET (obj)->xwidget_id,
1534 XXWIDGET (obj)->xwWidget);
1535#endif
1536 strout (buf, len, len, printcharfun);
1537 break;
1538 }
1539#else
1540 emacs_abort ();
1541#endif
1542 case PVEC_XWIDGET_VIEW:
1543 print_c_string ("#<xwidget view", printcharfun);
1522 printchar ('>', printcharfun); 1544 printchar ('>', printcharfun);
1523 break; 1545 break;
1524 1546
diff --git a/src/process.c b/src/process.c
index 13deddea82c..42743f6531a 100644
--- a/src/process.c
+++ b/src/process.c
@@ -90,6 +90,7 @@ static struct rlimit nofile_limit;
90 90
91#include <c-ctype.h> 91#include <c-ctype.h>
92#include <flexmember.h> 92#include <flexmember.h>
93#include <nproc.h>
93#include <sig2str.h> 94#include <sig2str.h>
94#include <verify.h> 95#include <verify.h>
95 96
@@ -682,6 +683,22 @@ clear_waiting_thread_info (void)
682 } 683 }
683} 684}
684 685
686/* Return TRUE if the keyboard descriptor is being monitored by the
687 current thread, FALSE otherwise. */
688static bool
689kbd_is_ours (void)
690{
691 for (int fd = 0; fd <= max_desc; ++fd)
692 {
693 if (fd_callback_info[fd].waiting_thread != current_thread)
694 continue;
695 if ((fd_callback_info[fd].flags & (FOR_READ | KEYBOARD_FD))
696 == (FOR_READ | KEYBOARD_FD))
697 return true;
698 }
699 return false;
700}
701
685 702
686/* Compute the Lisp form of the process status, p->status, from 703/* Compute the Lisp form of the process status, p->status, from
687 the numeric status that was returned by `wait'. */ 704 the numeric status that was returned by `wait'. */
@@ -1718,7 +1735,10 @@ to use a pty, or nil to use the default specified through
1718:stderr STDERR -- STDERR is either a buffer or a pipe process attached 1735:stderr STDERR -- STDERR is either a buffer or a pipe process attached
1719to the standard error of subprocess. Specifying this implies 1736to the standard error of subprocess. Specifying this implies
1720`:connection-type' is set to `pipe'. If STDERR is nil, standard error 1737`:connection-type' is set to `pipe'. If STDERR is nil, standard error
1721is mixed with standard output and sent to BUFFER or FILTER. 1738is mixed with standard output and sent to BUFFER or FILTER. (Note
1739that specifying :stderr will create a new, separate (but associated)
1740process, with its own filter and sentinel. See
1741Info node `(elisp) Asynchronous Processes' for more details.)
1722 1742
1723:file-handler FILE-HANDLER -- If FILE-HANDLER is non-nil, then look 1743:file-handler FILE-HANDLER -- If FILE-HANDLER is non-nil, then look
1724for a file name handler for the current buffer's `default-directory' 1744for a file name handler for the current buffer's `default-directory'
@@ -2147,7 +2167,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2147 p->pty_flag = pty_flag; 2167 p->pty_flag = pty_flag;
2148 pset_status (p, Qrun); 2168 pset_status (p, Qrun);
2149 2169
2150 if (!EQ (p->command, Qt)) 2170 if (!EQ (p->command, Qt)
2171 && !EQ (p->filter, Qt))
2151 add_process_read_fd (inchannel); 2172 add_process_read_fd (inchannel);
2152 2173
2153 ptrdiff_t count = SPECPDL_INDEX (); 2174 ptrdiff_t count = SPECPDL_INDEX ();
@@ -2265,7 +2286,8 @@ create_pty (Lisp_Object process)
2265 pset_status (p, Qrun); 2286 pset_status (p, Qrun);
2266 setup_process_coding_systems (process); 2287 setup_process_coding_systems (process);
2267 2288
2268 add_process_read_fd (pty_fd); 2289 if (!EQ (p->filter, Qt))
2290 add_process_read_fd (pty_fd);
2269 2291
2270 pset_tty_name (p, build_string (pty_name)); 2292 pset_tty_name (p, build_string (pty_name));
2271 } 2293 }
@@ -2374,7 +2396,8 @@ usage: (make-pipe-process &rest ARGS) */)
2374 pset_command (p, Qt); 2396 pset_command (p, Qt);
2375 eassert (! p->pty_flag); 2397 eassert (! p->pty_flag);
2376 2398
2377 if (!EQ (p->command, Qt)) 2399 if (!EQ (p->command, Qt)
2400 && !EQ (p->filter, Qt))
2378 add_process_read_fd (inchannel); 2401 add_process_read_fd (inchannel);
2379 p->adaptive_read_buffering 2402 p->adaptive_read_buffering
2380 = (NILP (Vprocess_adaptive_read_buffering) ? 0 2403 = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -3109,7 +3132,8 @@ usage: (make-serial-process &rest ARGS) */)
3109 pset_command (p, Qt); 3132 pset_command (p, Qt);
3110 eassert (! p->pty_flag); 3133 eassert (! p->pty_flag);
3111 3134
3112 if (!EQ (p->command, Qt)) 3135 if (!EQ (p->command, Qt)
3136 && !EQ (p->filter, Qt))
3113 add_process_read_fd (fd); 3137 add_process_read_fd (fd);
3114 3138
3115 update_process_mark (p); 3139 update_process_mark (p);
@@ -4001,7 +4025,7 @@ usage: (make-network-process &rest ARGS) */)
4001 4025
4002 if (!NILP (host)) 4026 if (!NILP (host))
4003 { 4027 {
4004 ptrdiff_t portstringlen ATTRIBUTE_UNUSED; 4028 MAYBE_UNUSED ptrdiff_t portstringlen;
4005 4029
4006 /* SERVICE can either be a string or int. 4030 /* SERVICE can either be a string or int.
4007 Convert to a C string for later use by getaddrinfo. */ 4031 Convert to a C string for later use by getaddrinfo. */
@@ -5308,13 +5332,13 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5308 wait_reading_process_output_1 (); 5332 wait_reading_process_output_1 ();
5309 } 5333 }
5310 5334
5311 /* Cause C-g and alarm signals to take immediate action, 5335 /* Cause C-g signals to take immediate action,
5312 and cause input available signals to zero out timeout. 5336 and cause input available signals to zero out timeout.
5313 5337
5314 It is important that we do this before checking for process 5338 It is important that we do this before checking for process
5315 activity. If we get a SIGCHLD after the explicit checks for 5339 activity. If we get a SIGCHLD after the explicit checks for
5316 process activity, timeout is the only way we will know. */ 5340 process activity, timeout is the only way we will know. */
5317 if (read_kbd < 0) 5341 if (read_kbd < 0 && kbd_is_ours ())
5318 set_waiting_for_input (&timeout); 5342 set_waiting_for_input (&timeout);
5319 5343
5320 /* If status of something has changed, and no input is 5344 /* If status of something has changed, and no input is
@@ -5444,7 +5468,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5444 { 5468 {
5445 clear_waiting_for_input (); 5469 clear_waiting_for_input ();
5446 redisplay_preserve_echo_area (11); 5470 redisplay_preserve_echo_area (11);
5447 if (read_kbd < 0) 5471 if (read_kbd < 0 && kbd_is_ours ())
5448 set_waiting_for_input (&timeout); 5472 set_waiting_for_input (&timeout);
5449 } 5473 }
5450 5474
@@ -6888,7 +6912,7 @@ If CURRENT-GROUP is `lambda', and if the shell owns the terminal,
6888don't send the signal. 6912don't send the signal.
6889 6913
6890This function calls the functions of `interrupt-process-functions' in 6914This function calls the functions of `interrupt-process-functions' in
6891the order of the list, until one of them returns non-`nil'. */) 6915the order of the list, until one of them returns non-nil. */)
6892 (Lisp_Object process, Lisp_Object current_group) 6916 (Lisp_Object process, Lisp_Object current_group)
6893{ 6917{
6894 return CALLN (Frun_hook_with_args_until_success, Qinterrupt_process_functions, 6918 return CALLN (Frun_hook_with_args_until_success, Qinterrupt_process_functions,
@@ -8213,6 +8237,20 @@ integer or floating point values.
8213 return system_process_attributes (pid); 8237 return system_process_attributes (pid);
8214} 8238}
8215 8239
8240DEFUN ("num-processors", Fnum_processors, Snum_processors, 0, 1, 0,
8241 doc: /* Return the number of processors, a positive integer.
8242Each usable thread execution unit counts as a processor.
8243By default, count the number of available processors,
8244overridable via the OMP_NUM_THREADS environment variable.
8245If optional argument QUERY is `current', ignore OMP_NUM_THREADS.
8246If QUERY is `all', also count processors not available. */)
8247 (Lisp_Object query)
8248{
8249 return make_uint (num_processors (EQ (query, Qall) ? NPROC_ALL
8250 : EQ (query, Qcurrent) ? NPROC_CURRENT
8251 : NPROC_CURRENT_OVERRIDABLE));
8252}
8253
8216#ifdef subprocesses 8254#ifdef subprocesses
8217/* Arrange to catch SIGCHLD if this hasn't already been arranged. 8255/* Arrange to catch SIGCHLD if this hasn't already been arranged.
8218 Invoke this after init_process_emacs, and after glib and/or GNUstep 8256 Invoke this after init_process_emacs, and after glib and/or GNUstep
@@ -8473,6 +8511,8 @@ syms_of_process (void)
8473 DEFSYM (Qpcpu, "pcpu"); 8511 DEFSYM (Qpcpu, "pcpu");
8474 DEFSYM (Qpmem, "pmem"); 8512 DEFSYM (Qpmem, "pmem");
8475 DEFSYM (Qargs, "args"); 8513 DEFSYM (Qargs, "args");
8514 DEFSYM (Qall, "all");
8515 DEFSYM (Qcurrent, "current");
8476 8516
8477 DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes, 8517 DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes,
8478 doc: /* Non-nil means delete processes immediately when they exit. 8518 doc: /* Non-nil means delete processes immediately when they exit.
@@ -8515,7 +8555,7 @@ thus favoring processes with lower descriptors. */);
8515 doc: /* List of functions to be called for `interrupt-process'. 8555 doc: /* List of functions to be called for `interrupt-process'.
8516The arguments of the functions are the same as for `interrupt-process'. 8556The arguments of the functions are the same as for `interrupt-process'.
8517These functions are called in the order of the list, until one of them 8557These functions are called in the order of the list, until one of them
8518returns non-`nil'. */); 8558returns non-nil. */);
8519 Vinterrupt_process_functions = list1 (Qinternal_default_interrupt_process); 8559 Vinterrupt_process_functions = list1 (Qinternal_default_interrupt_process);
8520 8560
8521 DEFVAR_LISP ("internal--daemon-sockname", Vinternal__daemon_sockname, 8561 DEFVAR_LISP ("internal--daemon-sockname", Vinternal__daemon_sockname,
@@ -8634,4 +8674,5 @@ amounts of data in one go. */);
8634 defsubr (&Sprocess_inherit_coding_system_flag); 8674 defsubr (&Sprocess_inherit_coding_system_flag);
8635 defsubr (&Slist_system_processes); 8675 defsubr (&Slist_system_processes);
8636 defsubr (&Sprocess_attributes); 8676 defsubr (&Sprocess_attributes);
8677 defsubr (&Snum_processors);
8637} 8678}
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 8350e54b54a..3224f65fa4c 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -2407,7 +2407,7 @@ regex_compile (re_char *pattern, ptrdiff_t size,
2407 2407
2408 if (lower_bound == 0) 2408 if (lower_bound == 0)
2409 { 2409 {
2410 /* A succeed_n that starts with 0 is really a 2410 /* A succeed_n that starts with 0 is really
2411 a simple on_failure_jump_loop. */ 2411 a simple on_failure_jump_loop. */
2412 INSERT_JUMP (on_failure_jump_loop, laststart, 2412 INSERT_JUMP (on_failure_jump_loop, laststart,
2413 b + 3 + nbytes); 2413 b + 3 + nbytes);
@@ -3828,7 +3828,7 @@ mutually_exclusive_p (struct re_pattern_buffer *bufp, re_char *p1,
3828/* Matching routines. */ 3828/* Matching routines. */
3829 3829
3830/* re_match_2 matches the compiled pattern in BUFP against the 3830/* re_match_2 matches the compiled pattern in BUFP against the
3831 the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 3831 (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
3832 and SIZE2, respectively). We start matching at POS, and stop 3832 and SIZE2, respectively). We start matching at POS, and stop
3833 matching at STOP. 3833 matching at STOP.
3834 3834
diff --git a/src/search.c b/src/search.c
index df384e1dcff..66e77d42b4a 100644
--- a/src/search.c
+++ b/src/search.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
30#include "blockinput.h" 30#include "blockinput.h"
31#include "intervals.h" 31#include "intervals.h"
32#include "pdumper.h" 32#include "pdumper.h"
33#include "composite.h"
33 34
34#include "regex-emacs.h" 35#include "regex-emacs.h"
35 36
@@ -259,7 +260,7 @@ compile_pattern (Lisp_Object pattern, struct re_registers *regp,
259 260
260 261
261static Lisp_Object 262static Lisp_Object
262looking_at_1 (Lisp_Object string, bool posix) 263looking_at_1 (Lisp_Object string, bool posix, bool modify_data)
263{ 264{
264 Lisp_Object val; 265 Lisp_Object val;
265 unsigned char *p1, *p2; 266 unsigned char *p1, *p2;
@@ -277,11 +278,11 @@ looking_at_1 (Lisp_Object string, bool posix)
277 CHECK_STRING (string); 278 CHECK_STRING (string);
278 279
279 /* Snapshot in case Lisp changes the value. */ 280 /* Snapshot in case Lisp changes the value. */
280 bool preserve_match_data = NILP (Vinhibit_changing_match_data); 281 bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
281 282
282 struct regexp_cache *cache_entry = compile_pattern ( 283 struct regexp_cache *cache_entry = compile_pattern (
283 string, 284 string,
284 preserve_match_data ? &search_regs : NULL, 285 modify_match_data ? &search_regs : NULL,
285 (!NILP (BVAR (current_buffer, case_fold_search)) 286 (!NILP (BVAR (current_buffer, case_fold_search))
286 ? BVAR (current_buffer, case_canon_table) : Qnil), 287 ? BVAR (current_buffer, case_canon_table) : Qnil),
287 posix, 288 posix,
@@ -315,7 +316,7 @@ looking_at_1 (Lisp_Object string, bool posix)
315 re_match_object = Qnil; 316 re_match_object = Qnil;
316 i = re_match_2 (&cache_entry->buf, (char *) p1, s1, (char *) p2, s2, 317 i = re_match_2 (&cache_entry->buf, (char *) p1, s1, (char *) p2, s2,
317 PT_BYTE - BEGV_BYTE, 318 PT_BYTE - BEGV_BYTE,
318 preserve_match_data ? &search_regs : NULL, 319 modify_match_data ? &search_regs : NULL,
319 ZV_BYTE - BEGV_BYTE); 320 ZV_BYTE - BEGV_BYTE);
320 321
321 if (i == -2) 322 if (i == -2)
@@ -325,7 +326,7 @@ looking_at_1 (Lisp_Object string, bool posix)
325 } 326 }
326 327
327 val = (i >= 0 ? Qt : Qnil); 328 val = (i >= 0 ? Qt : Qnil);
328 if (preserve_match_data && i >= 0) 329 if (modify_match_data && i >= 0)
329 { 330 {
330 for (i = 0; i < search_regs.num_regs; i++) 331 for (i = 0; i < search_regs.num_regs; i++)
331 if (search_regs.start[i] >= 0) 332 if (search_regs.start[i] >= 0)
@@ -342,35 +343,37 @@ looking_at_1 (Lisp_Object string, bool posix)
342 return unbind_to (count, val); 343 return unbind_to (count, val);
343} 344}
344 345
345DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0, 346DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 2, 0,
346 doc: /* Return t if text after point matches regular expression REGEXP. 347 doc: /* Return t if text after point matches regular expression REGEXP.
347This function modifies the match data that `match-beginning', 348By default, this function modifies the match data that
348`match-end' and `match-data' access; save and restore the match 349`match-beginning', `match-end' and `match-data' access. If
349data if you want to preserve them. */) 350INHIBIT-MODIFY is non-nil, don't modify the match data. */)
350 (Lisp_Object regexp) 351 (Lisp_Object regexp, Lisp_Object inhibit_modify)
351{ 352{
352 return looking_at_1 (regexp, 0); 353 return looking_at_1 (regexp, 0, NILP (inhibit_modify));
353} 354}
354 355
355DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 1, 0, 356DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 2, 0,
356 doc: /* Return t if text after point matches REGEXP according to Posix rules. 357 doc: /* Return t if text after point matches REGEXP according to Posix rules.
357Find the longest match, in accordance with Posix regular expression rules. 358Find the longest match, in accordance with Posix regular expression rules.
358This function modifies the match data that `match-beginning', 359
359`match-end' and `match-data' access; save and restore the match 360By default, this function modifies the match data that
360data if you want to preserve them. */) 361`match-beginning', `match-end' and `match-data' access. If
361 (Lisp_Object regexp) 362INHIBIT-MODIFY is non-nil, don't modify the match data. */)
363 (Lisp_Object regexp, Lisp_Object inhibit_modify)
362{ 364{
363 return looking_at_1 (regexp, 1); 365 return looking_at_1 (regexp, 1, NILP (inhibit_modify));
364} 366}
365 367
366static Lisp_Object 368static Lisp_Object
367string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start, 369string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
368 bool posix) 370 bool posix, bool modify_data)
369{ 371{
370 ptrdiff_t val; 372 ptrdiff_t val;
371 struct re_pattern_buffer *bufp; 373 struct re_pattern_buffer *bufp;
372 EMACS_INT pos; 374 EMACS_INT pos;
373 ptrdiff_t pos_byte, i; 375 ptrdiff_t pos_byte, i;
376 bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
374 377
375 if (running_asynch_code) 378 if (running_asynch_code)
376 save_search_regs (); 379 save_search_regs ();
@@ -399,8 +402,7 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
399 BVAR (current_buffer, case_eqv_table)); 402 BVAR (current_buffer, case_eqv_table));
400 403
401 bufp = &compile_pattern (regexp, 404 bufp = &compile_pattern (regexp,
402 (NILP (Vinhibit_changing_match_data) 405 (modify_match_data ? &search_regs : NULL),
403 ? &search_regs : NULL),
404 (!NILP (BVAR (current_buffer, case_fold_search)) 406 (!NILP (BVAR (current_buffer, case_fold_search))
405 ? BVAR (current_buffer, case_canon_table) : Qnil), 407 ? BVAR (current_buffer, case_canon_table) : Qnil),
406 posix, 408 posix,
@@ -409,18 +411,17 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
409 val = re_search (bufp, SSDATA (string), 411 val = re_search (bufp, SSDATA (string),
410 SBYTES (string), pos_byte, 412 SBYTES (string), pos_byte,
411 SBYTES (string) - pos_byte, 413 SBYTES (string) - pos_byte,
412 (NILP (Vinhibit_changing_match_data) 414 (modify_match_data ? &search_regs : NULL));
413 ? &search_regs : NULL));
414 415
415 /* Set last_thing_searched only when match data is changed. */ 416 /* Set last_thing_searched only when match data is changed. */
416 if (NILP (Vinhibit_changing_match_data)) 417 if (modify_match_data)
417 last_thing_searched = Qt; 418 last_thing_searched = Qt;
418 419
419 if (val == -2) 420 if (val == -2)
420 matcher_overflow (); 421 matcher_overflow ();
421 if (val < 0) return Qnil; 422 if (val < 0) return Qnil;
422 423
423 if (NILP (Vinhibit_changing_match_data)) 424 if (modify_match_data)
424 for (i = 0; i < search_regs.num_regs; i++) 425 for (i = 0; i < search_regs.num_regs; i++)
425 if (search_regs.start[i] >= 0) 426 if (search_regs.start[i] >= 0)
426 { 427 {
@@ -433,32 +434,42 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
433 return make_fixnum (string_byte_to_char (string, val)); 434 return make_fixnum (string_byte_to_char (string, val));
434} 435}
435 436
436DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0, 437DEFUN ("string-match", Fstring_match, Sstring_match, 2, 4, 0,
437 doc: /* Return index of start of first match for REGEXP in STRING, or nil. 438 doc: /* Return index of start of first match for REGEXP in STRING, or nil.
438Matching ignores case if `case-fold-search' is non-nil. 439Matching ignores case if `case-fold-search' is non-nil.
439If third arg START is non-nil, start search at that index in STRING. 440If third arg START is non-nil, start search at that index in STRING.
440For index of first char beyond the match, do (match-end 0).
441`match-end' and `match-beginning' also give indices of substrings
442matched by parenthesis constructs in the pattern.
443 441
444You can use the function `match-string' to extract the substrings 442If INHIBIT-MODIFY is non-nil, match data is not changed.
445matched by the parenthesis constructions in REGEXP. */) 443
446 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start) 444If INHIBIT-MODIFY is nil or missing, match data is changed, and
445`match-end' and `match-beginning' give indices of substrings matched
446by parenthesis constructs in the pattern. You can use the function
447`match-string' to extract the substrings matched by the parenthesis
448constructions in REGEXP. For index of first char beyond the match, do
449(match-end 0). */)
450 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
451 Lisp_Object inhibit_modify)
447{ 452{
448 return string_match_1 (regexp, string, start, 0); 453 return string_match_1 (regexp, string, start, 0, NILP (inhibit_modify));
449} 454}
450 455
451DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 3, 0, 456DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 4, 0,
452 doc: /* Return index of start of first match for Posix REGEXP in STRING, or nil. 457 doc: /* Return index of start of first match for Posix REGEXP in STRING, or nil.
453Find the longest match, in accord with Posix regular expression rules. 458Find the longest match, in accord with Posix regular expression rules.
454Case is ignored if `case-fold-search' is non-nil in the current buffer. 459Case is ignored if `case-fold-search' is non-nil in the current buffer.
455If third arg START is non-nil, start search at that index in STRING. 460
456For index of first char beyond the match, do (match-end 0). 461If INHIBIT-MODIFY is non-nil, match data is not changed.
457`match-end' and `match-beginning' also give indices of substrings 462
458matched by parenthesis constructs in the pattern. */) 463If INHIBIT-MODIFY is nil or missing, match data is changed, and
459 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start) 464`match-end' and `match-beginning' give indices of substrings matched
465by parenthesis constructs in the pattern. You can use the function
466`match-string' to extract the substrings matched by the parenthesis
467constructions in REGEXP. For index of first char beyond the match, do
468(match-end 0). */)
469 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
470 Lisp_Object inhibit_modify)
460{ 471{
461 return string_match_1 (regexp, string, start, 1); 472 return string_match_1 (regexp, string, start, 1, NILP (inhibit_modify));
462} 473}
463 474
464/* Match REGEXP against STRING using translation table TABLE, 475/* Match REGEXP against STRING using translation table TABLE,
@@ -2386,6 +2397,13 @@ since only regular expressions have distinguished subexpressions. */)
2386 if (! NILP (string)) 2397 if (! NILP (string))
2387 CHECK_STRING (string); 2398 CHECK_STRING (string);
2388 2399
2400 /* Most replacement texts don't contain any backslash directives in
2401 the replacements. Check whether that's the case, which will
2402 enable us to take the fast path later. */
2403 if (NILP (literal)
2404 && !memchr (SSDATA (newtext), '\\', SBYTES (newtext)))
2405 literal = Qt;
2406
2389 case_action = nochange; /* We tried an initialization */ 2407 case_action = nochange; /* We tried an initialization */
2390 /* but some C compilers blew it */ 2408 /* but some C compilers blew it */
2391 2409
@@ -2725,7 +2743,7 @@ since only regular expressions have distinguished subexpressions. */)
2725 newpoint = sub_start + SCHARS (newtext); 2743 newpoint = sub_start + SCHARS (newtext);
2726 2744
2727 /* Replace the old text with the new in the cleanest possible way. */ 2745 /* Replace the old text with the new in the cleanest possible way. */
2728 replace_range (sub_start, sub_end, newtext, 1, 0, 1, true); 2746 replace_range (sub_start, sub_end, newtext, 1, 0, 1, true, true);
2729 2747
2730 if (case_action == all_caps) 2748 if (case_action == all_caps)
2731 Fupcase_region (make_fixnum (search_regs.start[sub]), 2749 Fupcase_region (make_fixnum (search_regs.start[sub]),
@@ -2750,6 +2768,9 @@ since only regular expressions have distinguished subexpressions. */)
2750 /* Now move point "officially" to the end of the inserted replacement. */ 2768 /* Now move point "officially" to the end of the inserted replacement. */
2751 move_if_not_intangible (newpoint); 2769 move_if_not_intangible (newpoint);
2752 2770
2771 signal_after_change (sub_start, sub_end - sub_start, SCHARS (newtext));
2772 update_compositions (sub_start, newpoint, CHECK_BORDER);
2773
2753 return Qnil; 2774 return Qnil;
2754} 2775}
2755 2776
diff --git a/src/syntax.c b/src/syntax.c
index 7bba336744a..057a4c3b1f5 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -17,7 +17,6 @@ GNU General Public License for more details.
17You should have received a copy of the GNU General Public License 17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20
21#include <config.h> 20#include <config.h>
22 21
23#include "lisp.h" 22#include "lisp.h"
@@ -3547,8 +3546,10 @@ DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 6, 0,
3547 doc: /* Parse Lisp syntax starting at FROM until TO; return status of parse at TO. 3546 doc: /* Parse Lisp syntax starting at FROM until TO; return status of parse at TO.
3548Parsing stops at TO or when certain criteria are met; 3547Parsing stops at TO or when certain criteria are met;
3549 point is set to where parsing stops. 3548 point is set to where parsing stops.
3550If fifth arg OLDSTATE is omitted or nil, 3549
3551 parsing assumes that FROM is the beginning of a function. 3550If OLDSTATE is omitted or nil, parsing assumes that FROM is the
3551 beginning of a function. If not, OLDSTATE should be the state at
3552 FROM.
3552 3553
3553Value is a list of elements describing final state of parsing: 3554Value is a list of elements describing final state of parsing:
3554 0. depth in parens. 3555 0. depth in parens.
@@ -3594,6 +3595,9 @@ Sixth arg COMMENTSTOP non-nil means stop after the start of a comment.
3594 else 3595 else
3595 target = TYPE_MINIMUM (EMACS_INT); /* We won't reach this depth. */ 3596 target = TYPE_MINIMUM (EMACS_INT); /* We won't reach this depth. */
3596 3597
3598 if (fix_position (to) < fix_position (from))
3599 error ("End position is smaller than start position");
3600
3597 validate_region (&from, &to); 3601 validate_region (&from, &to);
3598 internalize_parse_state (oldstate, &state); 3602 internalize_parse_state (oldstate, &state);
3599 scan_sexps_forward (&state, XFIXNUM (from), CHAR_TO_BYTE (XFIXNUM (from)), 3603 scan_sexps_forward (&state, XFIXNUM (from), CHAR_TO_BYTE (XFIXNUM (from)),
diff --git a/src/sysstdio.h b/src/sysstdio.h
index d4df3d74567..d6ebfb455f5 100644
--- a/src/sysstdio.h
+++ b/src/sysstdio.h
@@ -26,7 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
26#include <stdio.h> 26#include <stdio.h>
27#include "unlocked-io.h" 27#include "unlocked-io.h"
28 28
29extern FILE *emacs_fopen (char const *, char const *); 29extern FILE *emacs_fopen (char const *, char const *) ATTRIBUTE_MALLOC;
30extern void errputc (int); 30extern void errputc (int);
31extern void errwrite (void const *, ptrdiff_t); 31extern void errwrite (void const *, ptrdiff_t);
32extern void close_output_streams (void); 32extern void close_output_streams (void);
diff --git a/src/systhread.h b/src/systhread.h
index 0f47d7c1a8a..601505f4f86 100644
--- a/src/systhread.h
+++ b/src/systhread.h
@@ -101,14 +101,11 @@ extern void sys_cond_signal (sys_cond_t *);
101extern void sys_cond_broadcast (sys_cond_t *); 101extern void sys_cond_broadcast (sys_cond_t *);
102extern void sys_cond_destroy (sys_cond_t *); 102extern void sys_cond_destroy (sys_cond_t *);
103 103
104extern sys_thread_t sys_thread_self (void) 104NODISCARD extern sys_thread_t sys_thread_self (void);
105 NODISCARD; 105NODISCARD extern bool sys_thread_equal (sys_thread_t, sys_thread_t);
106extern bool sys_thread_equal (sys_thread_t, sys_thread_t) 106
107 NODISCARD; 107NODISCARD extern bool sys_thread_create (sys_thread_t *,
108 108 thread_creation_function *, void *);
109extern bool sys_thread_create (sys_thread_t *, thread_creation_function *,
110 void *)
111 NODISCARD;
112 109
113extern void sys_thread_yield (void); 110extern void sys_thread_yield (void);
114extern void sys_thread_set_name (const char *); 111extern void sys_thread_set_name (const char *);
diff --git a/src/term.c b/src/term.c
index c995a4499cf..6f0b827cfc8 100644
--- a/src/term.c
+++ b/src/term.c
@@ -549,13 +549,14 @@ encode_terminal_code (struct glyph *src, int src_len,
549 { 549 {
550 if (src->type == COMPOSITE_GLYPH) 550 if (src->type == COMPOSITE_GLYPH)
551 { 551 {
552 struct composition *cmp UNINIT; 552 struct composition *cmp;
553 Lisp_Object gstring UNINIT; 553 Lisp_Object gstring UNINIT;
554 int i; 554 int i;
555 555
556 nbytes = buf - encode_terminal_src; 556 nbytes = buf - encode_terminal_src;
557 if (src->u.cmp.automatic) 557 if (src->u.cmp.automatic)
558 { 558 {
559 cmp = NULL;
559 gstring = composition_gstring_from_id (src->u.cmp.id); 560 gstring = composition_gstring_from_id (src->u.cmp.id);
560 required = src->slice.cmp.to - src->slice.cmp.from + 1; 561 required = src->slice.cmp.to - src->slice.cmp.from + 1;
561 } 562 }
@@ -575,7 +576,7 @@ encode_terminal_code (struct glyph *src, int src_len,
575 buf = encode_terminal_src + nbytes; 576 buf = encode_terminal_src + nbytes;
576 } 577 }
577 578
578 if (src->u.cmp.automatic) 579 if (!cmp)
579 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++) 580 for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
580 { 581 {
581 Lisp_Object g = LGSTRING_GLYPH (gstring, i); 582 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
@@ -2169,6 +2170,14 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f)
2169 2170
2170#endif /* !DOS_NT */ 2171#endif /* !DOS_NT */
2171 2172
2173char *
2174tty_type_name (Lisp_Object terminal)
2175{
2176 struct terminal *t = decode_tty_terminal (terminal);
2177
2178 return t? t->display_info.tty->type: NULL;
2179}
2180
2172DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0, 2181DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0,
2173 doc: /* Return the type of the tty device that TERMINAL uses. 2182 doc: /* Return the type of the tty device that TERMINAL uses.
2174Returns nil if TERMINAL is not on a tty device. 2183Returns nil if TERMINAL is not on a tty device.
@@ -2177,10 +2186,9 @@ TERMINAL can be a terminal object, a frame, or nil (meaning the
2177selected frame's terminal). */) 2186selected frame's terminal). */)
2178 (Lisp_Object terminal) 2187 (Lisp_Object terminal)
2179{ 2188{
2180 struct terminal *t = decode_tty_terminal (terminal); 2189 char *name = tty_type_name (terminal);
2181 2190
2182 return (t && t->display_info.tty->type 2191 return (name? build_string (name) : Qnil);
2183 ? build_string (t->display_info.tty->type) : Qnil);
2184} 2192}
2185 2193
2186DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0, 2194DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
@@ -2568,21 +2576,8 @@ handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
2568 { 2576 {
2569 f->mouse_moved = 0; 2577 f->mouse_moved = 0;
2570 term_mouse_click (&ie, event, f); 2578 term_mouse_click (&ie, event, f);
2571 /* eassert (ie.kind == MOUSE_CLICK_EVENT); */ 2579 ie.arg = tty_handle_tab_bar_click (f, event->x, event->y,
2572 if (tty_handle_tab_bar_click (f, event->x, event->y, 2580 (ie.modifiers & down_modifier) != 0, &ie);
2573 (ie.modifiers & down_modifier) != 0, &ie))
2574 {
2575 /* eassert (ie.kind == MOUSE_CLICK_EVENT
2576 * || ie.kind == TAB_BAR_EVENT); */
2577 /* tty_handle_tab_bar_click stores 2 events in the event
2578 queue, so we are done here. */
2579 /* FIXME: Actually, `tty_handle_tab_bar_click` returns true
2580 without storing any events, when
2581 (ie.modifiers & down_modifier) != 0 */
2582 count += 2;
2583 return count;
2584 }
2585 /* eassert (ie.kind == MOUSE_CLICK_EVENT); */
2586 kbd_buffer_store_event (&ie); 2581 kbd_buffer_store_event (&ie);
2587 count++; 2582 count++;
2588 } 2583 }
diff --git a/src/termchar.h b/src/termchar.h
index f50c1bfb6ea..7ab9337fbe7 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -234,7 +234,7 @@ extern struct tty_display_info *tty_list;
234#define CURTTY() FRAME_TTY (SELECTED_FRAME()) 234#define CURTTY() FRAME_TTY (SELECTED_FRAME())
235 235
236struct input_event; 236struct input_event;
237extern bool tty_handle_tab_bar_click (struct frame *, int, int, bool, 237extern Lisp_Object tty_handle_tab_bar_click (struct frame *, int, int, bool,
238 struct input_event *); 238 struct input_event *);
239 239
240#endif /* EMACS_TERMCHAR_H */ 240#endif /* EMACS_TERMCHAR_H */
diff --git a/src/termhooks.h b/src/termhooks.h
index 12f5d0cd6ec..7e8318c07af 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -256,6 +256,8 @@ enum event_kind
256#ifdef HAVE_XWIDGETS 256#ifdef HAVE_XWIDGETS
257 /* events generated by xwidgets*/ 257 /* events generated by xwidgets*/
258 , XWIDGET_EVENT 258 , XWIDGET_EVENT
259 /* Event generated when WebKit asks us to display another widget. */
260 , XWIDGET_DISPLAY_EVENT
259#endif 261#endif
260 262
261#ifdef USE_FILE_NOTIFY 263#ifdef USE_FILE_NOTIFY
diff --git a/src/timefns.c b/src/timefns.c
index f0e2e97f555..a9921cdc108 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -19,6 +19,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20#include <config.h> 20#include <config.h>
21 21
22/* Work around GCC bug 102671. */
23#if 10 <= __GNUC__
24# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
25#endif
26
22#include "systime.h" 27#include "systime.h"
23 28
24#include "blockinput.h" 29#include "blockinput.h"
diff --git a/src/unexcw.c b/src/unexcw.c
index 7a80b05963b..157e9f45607 100644
--- a/src/unexcw.c
+++ b/src/unexcw.c
@@ -48,7 +48,7 @@ static exe_header_t *
48read_exe_header (int fd, exe_header_t * exe_header_buffer) 48read_exe_header (int fd, exe_header_t * exe_header_buffer)
49{ 49{
50 int i; 50 int i;
51 int ret ATTRIBUTE_UNUSED; 51 MAYBE_UNUSED int ret;
52 52
53 assert (fd >= 0); 53 assert (fd >= 0);
54 assert (exe_header_buffer != 0); 54 assert (exe_header_buffer != 0);
@@ -111,7 +111,7 @@ fixup_executable (int fd)
111 exe_header_t exe_header_buffer; 111 exe_header_t exe_header_buffer;
112 exe_header_t *exe_header; 112 exe_header_t *exe_header;
113 int i; 113 int i;
114 int ret ATTRIBUTE_UNUSED; 114 MAYBE_UNUSED int ret;
115 int found_data = 0; 115 int found_data = 0;
116 int found_bss = 0; 116 int found_bss = 0;
117 117
@@ -269,7 +269,7 @@ unexec (const char *outfile, const char *infile)
269 int fd_in; 269 int fd_in;
270 int fd_out; 270 int fd_out;
271 int ret; 271 int ret;
272 int ret2 ATTRIBUTE_UNUSED; 272 MAYBE_UNUSED int ret2;
273 273
274 infile = add_exe_suffix_if_necessary (infile, infile_buffer); 274 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
275 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer); 275 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
diff --git a/src/verbose.mk.in b/src/verbose.mk.in
index 50d6ea32000..a5ff931ed09 100644
--- a/src/verbose.mk.in
+++ b/src/verbose.mk.in
@@ -25,6 +25,7 @@ AM_V_at =
25AM_V_CC = 25AM_V_CC =
26AM_V_CCLD = 26AM_V_CCLD =
27AM_V_ELC = 27AM_V_ELC =
28AM_V_ELN =
28AM_V_GEN = 29AM_V_GEN =
29AM_V_GLOBALS = 30AM_V_GLOBALS =
30AM_V_NO_PD = 31AM_V_NO_PD =
@@ -37,11 +38,14 @@ AM_V_CCLD = @echo " CCLD " $@;
37ifeq ($(HAVE_NATIVE_COMP),yes) 38ifeq ($(HAVE_NATIVE_COMP),yes)
38ifeq ($(NATIVE_DISABLED),1) 39ifeq ($(NATIVE_DISABLED),1)
39AM_V_ELC = @echo " ELC " $@; 40AM_V_ELC = @echo " ELC " $@;
41AM_V_ELN =
40else 42else
41AM_V_ELC = @echo " ELC+ELN " $@; 43AM_V_ELC = @echo " ELC+ELN " $@;
44AM_V_ELN = @echo " ELN " $@;
42endif 45endif
43else 46else
44AM_V_ELC = @echo " ELC " $@; 47AM_V_ELC = @echo " ELC " $@;
48AM_V_ELN =
45endif 49endif
46AM_V_GEN = @echo " GEN " $@; 50AM_V_GEN = @echo " GEN " $@;
47AM_V_GLOBALS = @echo " GEN " globals.h; 51AM_V_GLOBALS = @echo " GEN " globals.h;
diff --git a/src/vm-limit.c b/src/vm-limit.c
index b9058d04352..e0547651bb9 100644
--- a/src/vm-limit.c
+++ b/src/vm-limit.c
@@ -126,7 +126,7 @@ get_lim_data (void)
126 126
127 dos_memory_info (&totalram, &freeram, &totalswap, &freeswap); 127 dos_memory_info (&totalram, &freeram, &totalswap, &freeswap);
128 lim_data = freeram; 128 lim_data = freeram;
129 /* Don't believe they will give us more that 0.5 GB. */ 129 /* Don't believe they will give us more than 0.5 GB. */
130 if (lim_data > 512U * 1024U * 1024U) 130 if (lim_data > 512U * 1024U * 1024U)
131 lim_data = 512U * 1024U * 1024U; 131 lim_data = 512U * 1024U * 1024U;
132} 132}
diff --git a/src/w16select.c b/src/w16select.c
index 37239137cf0..bbd2ed4bb97 100644
--- a/src/w16select.c
+++ b/src/w16select.c
@@ -87,7 +87,7 @@ static size_t clipboard_storage_size;
87/* C functions to access the Windows 3.1x clipboard from DOS apps. 87/* C functions to access the Windows 3.1x clipboard from DOS apps.
88 88
89 The information was obtained from the Microsoft Knowledge Base, 89 The information was obtained from the Microsoft Knowledge Base,
90 article Q67675 and can be found at: 90 article Q67675 and can be found at: [broken link -- SK 2021-09-27]
91 http://www.microsoft.com/kb/developr/win_dk/q67675.htm */ 91 http://www.microsoft.com/kb/developr/win_dk/q67675.htm */
92 92
93/* See also Ralf Brown's Interrupt List. 93/* See also Ralf Brown's Interrupt List.
diff --git a/src/w32.c b/src/w32.c
index 968b4bbe489..e4b7ef3b95d 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -39,6 +39,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
39#include <sys/time.h> 39#include <sys/time.h>
40#include <sys/utime.h> 40#include <sys/utime.h>
41#include <math.h> 41#include <math.h>
42#include <nproc.h>
42 43
43/* Include (most) CRT headers *before* ms-w32.h. */ 44/* Include (most) CRT headers *before* ms-w32.h. */
44#include <ms-w32.h> 45#include <ms-w32.h>
@@ -1962,6 +1963,16 @@ w32_get_nproc (void)
1962 return num_of_processors; 1963 return num_of_processors;
1963} 1964}
1964 1965
1966/* Emulate Gnulib's 'num_processors'. We cannot use the Gnulib
1967 version because it unconditionally calls APIs that aren't available
1968 on old MS-Windows versions. */
1969unsigned long
1970num_processors (enum nproc_query query)
1971{
1972 /* We ignore QUERY. */
1973 return w32_get_nproc ();
1974}
1975
1965static void 1976static void
1966sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user) 1977sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1967{ 1978{
@@ -2389,8 +2400,13 @@ rand_as183 (void)
2389int 2400int
2390random (void) 2401random (void)
2391{ 2402{
2392 /* rand_as183 () gives us 15 random bits...hack together 30 bits. */ 2403 /* rand_as183 () gives us 15 random bits...hack together 30 bits for
2404 Emacs with 32-bit EMACS_INT, and at least 31 bit for wider EMACS_INT. */
2405#if EMACS_INT_MAX > INT_MAX
2406 return ((rand_as183 () << 30) | (rand_as183 () << 15) | rand_as183 ());
2407#else
2393 return ((rand_as183 () << 15) | rand_as183 ()); 2408 return ((rand_as183 () << 15) | rand_as183 ());
2409#endif
2394} 2410}
2395 2411
2396void 2412void
@@ -2804,53 +2820,6 @@ sys_putenv (char *str)
2804 2820
2805#define REG_ROOT "SOFTWARE\\GNU\\Emacs" 2821#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2806 2822
2807LPBYTE
2808w32_get_resource (const char *key, LPDWORD lpdwtype)
2809{
2810 LPBYTE lpvalue;
2811 HKEY hrootkey = NULL;
2812 DWORD cbData;
2813
2814 /* Check both the current user and the local machine to see if
2815 we have any resources. */
2816
2817 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2818 {
2819 lpvalue = NULL;
2820
2821 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2822 && (lpvalue = xmalloc (cbData)) != NULL
2823 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2824 {
2825 RegCloseKey (hrootkey);
2826 return (lpvalue);
2827 }
2828
2829 xfree (lpvalue);
2830
2831 RegCloseKey (hrootkey);
2832 }
2833
2834 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2835 {
2836 lpvalue = NULL;
2837
2838 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2839 && (lpvalue = xmalloc (cbData)) != NULL
2840 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2841 {
2842 RegCloseKey (hrootkey);
2843 return (lpvalue);
2844 }
2845
2846 xfree (lpvalue);
2847
2848 RegCloseKey (hrootkey);
2849 }
2850
2851 return (NULL);
2852}
2853
2854/* The argv[] array holds ANSI-encoded strings, and so this function 2823/* The argv[] array holds ANSI-encoded strings, and so this function
2855 works with ANS_encoded strings. */ 2824 works with ANS_encoded strings. */
2856void 2825void
@@ -3061,7 +3030,7 @@ init_environment (char ** argv)
3061 int dont_free = 0; 3030 int dont_free = 0;
3062 char bufc[SET_ENV_BUF_SIZE]; 3031 char bufc[SET_ENV_BUF_SIZE];
3063 3032
3064 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL 3033 if ((lpval = w32_get_resource (REG_ROOT, env_vars[i].name, &dwType)) == NULL
3065 /* Also ignore empty environment variables. */ 3034 /* Also ignore empty environment variables. */
3066 || *lpval == 0) 3035 || *lpval == 0)
3067 { 3036 {
@@ -8753,7 +8722,7 @@ int
8753_sys_read_ahead (int fd) 8722_sys_read_ahead (int fd)
8754{ 8723{
8755 child_process * cp; 8724 child_process * cp;
8756 int rc; 8725 int rc = 0;
8757 8726
8758 if (fd < 0 || fd >= MAXDESC) 8727 if (fd < 0 || fd >= MAXDESC)
8759 return STATUS_READ_ERROR; 8728 return STATUS_READ_ERROR;
diff --git a/src/w32.h b/src/w32.h
index ffa145b1484..b31d66646c9 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -155,14 +155,15 @@ extern unsigned int w32_get_short_filename (const char *, char *, int);
155 155
156/* Prepare our standard handles for proper inheritance by child processes. */ 156/* Prepare our standard handles for proper inheritance by child processes. */
157extern void prepare_standard_handles (int in, int out, 157extern void prepare_standard_handles (int in, int out,
158 int err, HANDLE handles[4]); 158 int err, HANDLE handles[3]);
159 159
160/* Reset our standard handles to their original state. */ 160/* Reset our standard handles to their original state. */
161extern void reset_standard_handles (int in, int out, 161extern void reset_standard_handles (int in, int out,
162 int err, HANDLE handles[4]); 162 int err, HANDLE handles[3]);
163 163
164/* Return the string resource associated with KEY of type TYPE. */ 164/* Query Windows Registry and return the resource associated
165extern LPBYTE w32_get_resource (const char * key, LPDWORD type); 165 associated with KEY and NAME of type TYPE. */
166extern LPBYTE w32_get_resource (const char * key, const char * name, LPDWORD type);
166 167
167extern void release_listen_threads (void); 168extern void release_listen_threads (void);
168extern void init_ntproc (int); 169extern void init_ntproc (int);
diff --git a/src/w32fns.c b/src/w32fns.c
index 14d1154a2bc..c1686beaaa9 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -73,6 +73,20 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
73#include <imm.h> 73#include <imm.h>
74#include <windowsx.h> 74#include <windowsx.h>
75 75
76/*
77 Internal/undocumented constants for Windows Dark mode.
78 See: https://github.com/microsoft/WindowsAppSDK/issues/41
79*/
80#define DARK_MODE_APP_NAME L"DarkMode_Explorer"
81/* For Windows 10 version 1809, 1903, 1909. */
82#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_OLD
83#define DWMWA_USE_IMMERSIVE_DARK_MODE_OLD 19
84#endif
85/* For Windows 10 version 2004 and higher, and Windows 11. */
86#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
87#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
88#endif
89
76#ifndef FOF_NO_CONNECTED_ELEMENTS 90#ifndef FOF_NO_CONNECTED_ELEMENTS
77#define FOF_NO_CONNECTED_ELEMENTS 0x2000 91#define FOF_NO_CONNECTED_ELEMENTS 0x2000
78#endif 92#endif
@@ -185,6 +199,11 @@ typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
185typedef HRESULT (WINAPI *SetThreadDescription_Proc) 199typedef HRESULT (WINAPI *SetThreadDescription_Proc)
186 (HANDLE hThread, PCWSTR lpThreadDescription); 200 (HANDLE hThread, PCWSTR lpThreadDescription);
187 201
202typedef HRESULT (WINAPI * SetWindowTheme_Proc)
203 (IN HWND hwnd, IN LPCWSTR pszSubAppName, IN LPCWSTR pszSubIdList);
204typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc)
205 (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute);
206
188TrackMouseEvent_Proc track_mouse_event_fn = NULL; 207TrackMouseEvent_Proc track_mouse_event_fn = NULL;
189ImmGetCompositionString_Proc get_composition_string_fn = NULL; 208ImmGetCompositionString_Proc get_composition_string_fn = NULL;
190ImmGetContext_Proc get_ime_context_fn = NULL; 209ImmGetContext_Proc get_ime_context_fn = NULL;
@@ -199,6 +218,8 @@ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
199GetTitleBarInfo_Proc get_title_bar_info_fn = NULL; 218GetTitleBarInfo_Proc get_title_bar_info_fn = NULL;
200IsDebuggerPresent_Proc is_debugger_present = NULL; 219IsDebuggerPresent_Proc is_debugger_present = NULL;
201SetThreadDescription_Proc set_thread_description = NULL; 220SetThreadDescription_Proc set_thread_description = NULL;
221SetWindowTheme_Proc SetWindowTheme_fn = NULL;
222DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL;
202 223
203extern AppendMenuW_Proc unicode_append_menu; 224extern AppendMenuW_Proc unicode_append_menu;
204 225
@@ -252,6 +273,9 @@ int w32_major_version;
252int w32_minor_version; 273int w32_minor_version;
253int w32_build_number; 274int w32_build_number;
254 275
276/* If the OS is set to use dark mode. */
277BOOL w32_darkmode = FALSE;
278
255/* Distinguish between Windows NT and Windows 95. */ 279/* Distinguish between Windows NT and Windows 95. */
256int os_subtype; 280int os_subtype;
257 281
@@ -2279,10 +2303,36 @@ w32_init_class (HINSTANCE hinst)
2279 } 2303 }
2280} 2304}
2281 2305
2306/* Applies the Windows system theme (light or dark) to the window
2307 handle HWND. */
2308static void
2309w32_applytheme (HWND hwnd)
2310{
2311 if (w32_darkmode)
2312 {
2313 /* Set window theme to that of a built-in Windows app (Explorer),
2314 because it has dark scroll bars and other UI elements. */
2315 if (SetWindowTheme_fn)
2316 SetWindowTheme_fn (hwnd, DARK_MODE_APP_NAME, NULL);
2317
2318 /* Set the titlebar to system dark mode. */
2319 if (DwmSetWindowAttribute_fn)
2320 {
2321 /* Windows 10 version 2004 and up, Windows 11. */
2322 DWORD attr = DWMWA_USE_IMMERSIVE_DARK_MODE;
2323 /* Windows 10 older than 2004. */
2324 if (w32_build_number < 19041)
2325 attr = DWMWA_USE_IMMERSIVE_DARK_MODE_OLD;
2326 DwmSetWindowAttribute_fn (hwnd, attr,
2327 &w32_darkmode, sizeof (w32_darkmode));
2328 }
2329 }
2330}
2331
2282static HWND 2332static HWND
2283w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) 2333w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
2284{ 2334{
2285 return CreateWindow ("SCROLLBAR", "", 2335 HWND hwnd = CreateWindow ("SCROLLBAR", "",
2286 /* Clip siblings so we don't draw over child 2336 /* Clip siblings so we don't draw over child
2287 frames. Apparently this is not always 2337 frames. Apparently this is not always
2288 sufficient so we also try to make bar windows 2338 sufficient so we also try to make bar windows
@@ -2291,12 +2341,15 @@ w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
2291 /* Position and size of scroll bar. */ 2341 /* Position and size of scroll bar. */
2292 bar->left, bar->top, bar->width, bar->height, 2342 bar->left, bar->top, bar->width, bar->height,
2293 FRAME_W32_WINDOW (f), NULL, hinst, NULL); 2343 FRAME_W32_WINDOW (f), NULL, hinst, NULL);
2344 if (hwnd)
2345 w32_applytheme (hwnd);
2346 return hwnd;
2294} 2347}
2295 2348
2296static HWND 2349static HWND
2297w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) 2350w32_createhscrollbar (struct frame *f, struct scroll_bar * bar)
2298{ 2351{
2299 return CreateWindow ("SCROLLBAR", "", 2352 HWND hwnd = CreateWindow ("SCROLLBAR", "",
2300 /* Clip siblings so we don't draw over child 2353 /* Clip siblings so we don't draw over child
2301 frames. Apparently this is not always 2354 frames. Apparently this is not always
2302 sufficient so we also try to make bar windows 2355 sufficient so we also try to make bar windows
@@ -2305,6 +2358,9 @@ w32_createhscrollbar (struct frame *f, struct scroll_bar * bar)
2305 /* Position and size of scroll bar. */ 2358 /* Position and size of scroll bar. */
2306 bar->left, bar->top, bar->width, bar->height, 2359 bar->left, bar->top, bar->width, bar->height,
2307 FRAME_W32_WINDOW (f), NULL, hinst, NULL); 2360 FRAME_W32_WINDOW (f), NULL, hinst, NULL);
2361 if (hwnd)
2362 w32_applytheme (hwnd);
2363 return hwnd;
2308} 2364}
2309 2365
2310static void 2366static void
@@ -2390,6 +2446,9 @@ w32_createwindow (struct frame *f, int *coords)
2390 /* Enable drag-n-drop. */ 2446 /* Enable drag-n-drop. */
2391 DragAcceptFiles (hwnd, TRUE); 2447 DragAcceptFiles (hwnd, TRUE);
2392 2448
2449 /* Enable system light/dark theme. */
2450 w32_applytheme (hwnd);
2451
2393 /* Do this to discard the default setting specified by our parent. */ 2452 /* Do this to discard the default setting specified by our parent. */
2394 ShowWindow (hwnd, SW_HIDE); 2453 ShowWindow (hwnd, SW_HIDE);
2395 2454
@@ -10257,6 +10316,60 @@ to be converted to forward slashes by the caller. */)
10257} 10316}
10258 10317
10259#endif /* WINDOWSNT */ 10318#endif /* WINDOWSNT */
10319
10320/* Query a value from the Windows Registry (under HKCU and HKLM),
10321 where `key` is the registry key, `name` is the name, and `lpdwtype`
10322 is a pointer to the return value's type. `lpwdtype` can be NULL if
10323 you do not care about the type.
10324
10325 Returns: pointer to the value, or null pointer if the key/name does
10326 not exist. */
10327LPBYTE
10328w32_get_resource (const char *key, const char *name, LPDWORD lpdwtype)
10329{
10330 LPBYTE lpvalue;
10331 HKEY hrootkey = NULL;
10332 DWORD cbData;
10333
10334 /* Check both the current user and the local machine to see if
10335 we have any resources. */
10336
10337 if (RegOpenKeyEx (HKEY_CURRENT_USER, key, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
10338 {
10339 lpvalue = NULL;
10340
10341 if (RegQueryValueEx (hrootkey, name, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
10342 && (lpvalue = xmalloc (cbData)) != NULL
10343 && RegQueryValueEx (hrootkey, name, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
10344 {
10345 RegCloseKey (hrootkey);
10346 return (lpvalue);
10347 }
10348
10349 xfree (lpvalue);
10350
10351 RegCloseKey (hrootkey);
10352 }
10353
10354 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
10355 {
10356 lpvalue = NULL;
10357
10358 if (RegQueryValueEx (hrootkey, name, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
10359 && (lpvalue = xmalloc (cbData)) != NULL
10360 && RegQueryValueEx (hrootkey, name, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
10361 {
10362 RegCloseKey (hrootkey);
10363 return (lpvalue);
10364 }
10365
10366 xfree (lpvalue);
10367
10368 RegCloseKey (hrootkey);
10369 }
10370
10371 return (NULL);
10372}
10260 10373
10261/*********************************************************************** 10374/***********************************************************************
10262 Initialization 10375 Initialization
@@ -11028,6 +11141,37 @@ globals_of_w32fns (void)
11028 set_thread_description = (SetThreadDescription_Proc) 11141 set_thread_description = (SetThreadDescription_Proc)
11029 get_proc_addr (hm_kernel32, "SetThreadDescription"); 11142 get_proc_addr (hm_kernel32, "SetThreadDescription");
11030 11143
11144 /* Support OS dark mode on Windows 10 version 1809 and higher.
11145 See `w32_applytheme` which uses appropriate APIs per version of Windows.
11146 For future wretches who may need to understand Windows build numbers:
11147 https://docs.microsoft.com/en-us/windows/release-health/release-information
11148 */
11149 if (os_subtype == OS_SUBTYPE_NT
11150 && w32_major_version >= 10 && w32_build_number >= 17763)
11151 {
11152 /* Load dwmapi.dll and uxtheme.dll, which will be needed to set
11153 window themes. */
11154 HMODULE dwmapi_lib = LoadLibrary("dwmapi.dll");
11155 DwmSetWindowAttribute_fn = (DwmSetWindowAttribute_Proc)
11156 get_proc_addr (dwmapi_lib, "DwmSetWindowAttribute");
11157 HMODULE uxtheme_lib = LoadLibrary("uxtheme.dll");
11158 SetWindowTheme_fn = (SetWindowTheme_Proc)
11159 get_proc_addr (uxtheme_lib, "SetWindowTheme");
11160
11161 /* Check Windows Registry for system theme and set w32_darkmode.
11162 TODO: "Nice to have" would be to create a lisp setting (which
11163 defaults to this Windows Registry value), then read that lisp
11164 value here instead. This would allow the user to forcibly
11165 override the system theme (which is also user-configurable in
11166 Windows settings; see MS-Windows section in Emacs manual). */
11167 LPBYTE val =
11168 w32_get_resource ("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
11169 "AppsUseLightTheme",
11170 NULL);
11171 if (val && *val == 0)
11172 w32_darkmode = TRUE;
11173 }
11174
11031 except_code = 0; 11175 except_code = 0;
11032 except_addr = 0; 11176 except_addr = 0;
11033#ifndef CYGWIN 11177#ifndef CYGWIN
diff --git a/src/w32font.c b/src/w32font.c
index 6b9ab0468cd..4ceb4302cee 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -2000,11 +2000,11 @@ w32_encode_weight (int n)
2000static Lisp_Object 2000static Lisp_Object
2001w32_to_fc_weight (int n) 2001w32_to_fc_weight (int n)
2002{ 2002{
2003 if (n >= FW_HEAVY) return intern ("black"); 2003 if (n >= FW_HEAVY) return Qblack;
2004 if (n >= FW_EXTRABOLD) return Qextra_bold; 2004 if (n >= FW_EXTRABOLD) return Qextra_bold;
2005 if (n >= FW_BOLD) return Qbold; 2005 if (n >= FW_BOLD) return Qbold;
2006 if (n >= FW_SEMIBOLD) return intern ("demibold"); 2006 if (n >= FW_SEMIBOLD) return intern ("demibold");
2007 if (n >= FW_NORMAL) return intern ("medium"); 2007 if (n >= FW_NORMAL) return Qmedium;
2008 if (n >= FW_LIGHT) return Qlight; 2008 if (n >= FW_LIGHT) return Qlight;
2009 if (n >= FW_EXTRALIGHT) return Qextra_light; 2009 if (n >= FW_EXTRALIGHT) return Qextra_light;
2010 return intern ("thin"); 2010 return intern ("thin");
diff --git a/src/w32heap.c b/src/w32heap.c
index 0f228bfb221..a0d4c070be3 100644
--- a/src/w32heap.c
+++ b/src/w32heap.c
@@ -189,6 +189,26 @@ malloc_fn the_malloc_fn;
189realloc_fn the_realloc_fn; 189realloc_fn the_realloc_fn;
190free_fn the_free_fn; 190free_fn the_free_fn;
191 191
192static void *
193heap_alloc (size_t size)
194{
195 void *p = size <= PTRDIFF_MAX ? HeapAlloc (heap, 0, size | !size) : NULL;
196 if (!p)
197 errno = ENOMEM;
198 return p;
199}
200
201static void *
202heap_realloc (void *ptr, size_t size)
203{
204 void *p = (size <= PTRDIFF_MAX
205 ? HeapReAlloc (heap, 0, ptr, size | !size)
206 : NULL);
207 if (!p)
208 errno = ENOMEM;
209 return p;
210}
211
192/* It doesn't seem to be useful to allocate from a file mapping. 212/* It doesn't seem to be useful to allocate from a file mapping.
193 It would be if the memory was shared. 213 It would be if the memory was shared.
194 https://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping */ 214 https://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping */
@@ -346,7 +366,7 @@ void *
346malloc_after_dump (size_t size) 366malloc_after_dump (size_t size)
347{ 367{
348 /* Use the new private heap. */ 368 /* Use the new private heap. */
349 void *p = HeapAlloc (heap, 0, size); 369 void *p = heap_alloc (size);
350 370
351 /* After dump, keep track of the "brk value" for sbrk(0). */ 371 /* After dump, keep track of the "brk value" for sbrk(0). */
352 if (p) 372 if (p)
@@ -356,8 +376,6 @@ malloc_after_dump (size_t size)
356 if (new_brk > data_region_end) 376 if (new_brk > data_region_end)
357 data_region_end = new_brk; 377 data_region_end = new_brk;
358 } 378 }
359 else
360 errno = ENOMEM;
361 return p; 379 return p;
362} 380}
363 381
@@ -373,9 +391,7 @@ malloc_before_dump (size_t size)
373 if (size < MaxBlockSize) 391 if (size < MaxBlockSize)
374 { 392 {
375 /* Use the private heap if possible. */ 393 /* Use the private heap if possible. */
376 p = HeapAlloc (heap, 0, size); 394 p = heap_alloc (size);
377 if (!p)
378 errno = ENOMEM;
379 } 395 }
380 else 396 else
381 { 397 {
@@ -433,18 +449,14 @@ realloc_after_dump (void *ptr, size_t size)
433 if (FREEABLE_P (ptr)) 449 if (FREEABLE_P (ptr))
434 { 450 {
435 /* Reallocate the block since it lies in the new heap. */ 451 /* Reallocate the block since it lies in the new heap. */
436 p = HeapReAlloc (heap, 0, ptr, size); 452 p = heap_realloc (ptr, size);
437 if (!p)
438 errno = ENOMEM;
439 } 453 }
440 else 454 else
441 { 455 {
442 /* If the block lies in the dumped data, do not free it. Only 456 /* If the block lies in the dumped data, do not free it. Only
443 allocate a new one. */ 457 allocate a new one. */
444 p = HeapAlloc (heap, 0, size); 458 p = heap_alloc (size);
445 if (!p) 459 if (p && ptr)
446 errno = ENOMEM;
447 else if (ptr)
448 CopyMemory (p, ptr, size); 460 CopyMemory (p, ptr, size);
449 } 461 }
450 /* After dump, keep track of the "brk value" for sbrk(0). */ 462 /* After dump, keep track of the "brk value" for sbrk(0). */
@@ -467,9 +479,7 @@ realloc_before_dump (void *ptr, size_t size)
467 if (dumped_data < (unsigned char *)ptr 479 if (dumped_data < (unsigned char *)ptr
468 && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize) 480 && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
469 { 481 {
470 p = HeapReAlloc (heap, 0, ptr, size); 482 p = heap_realloc (ptr, size);
471 if (!p)
472 errno = ENOMEM;
473 } 483 }
474 else 484 else
475 { 485 {
diff --git a/src/w32inevt.c b/src/w32inevt.c
index 1255072b7f3..9a69b32bcb0 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -586,9 +586,8 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
586 int x = event->dwMousePosition.X; 586 int x = event->dwMousePosition.X;
587 int y = event->dwMousePosition.Y; 587 int y = event->dwMousePosition.Y;
588 struct frame *f = get_frame (); 588 struct frame *f = get_frame ();
589 if (tty_handle_tab_bar_click (f, x, y, (button_state & mask) != 0, 589 emacs_ev->arg = tty_handle_tab_bar_click (f, x, y, (button_state & mask) != 0,
590 emacs_ev)) 590 emacs_ev);
591 return 0; /* tty_handle_tab_bar_click adds the event to queue */
592 591
593 emacs_ev->modifiers |= ((button_state & mask) 592 emacs_ev->modifiers |= ((button_state & mask)
594 ? down_modifier : up_modifier); 593 ? down_modifier : up_modifier);
@@ -597,7 +596,6 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
597 XSETFASTINT (emacs_ev->x, x); 596 XSETFASTINT (emacs_ev->x, x);
598 XSETFASTINT (emacs_ev->y, y); 597 XSETFASTINT (emacs_ev->y, y);
599 XSETFRAME (emacs_ev->frame_or_window, f); 598 XSETFRAME (emacs_ev->frame_or_window, f);
600 emacs_ev->arg = Qnil;
601 599
602 return 1; 600 return 1;
603 } 601 }
diff --git a/src/w32proc.c b/src/w32proc.c
index 702ea122e65..360f45e9e11 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -3878,14 +3878,6 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
3878 return val - 2; 3878 return val - 2;
3879} 3879}
3880 3880
3881DEFUN ("w32-get-nproc", Fw32_get_nproc,
3882 Sw32_get_nproc, 0, 0, 0,
3883 doc: /* Return the number of system's processor execution units. */)
3884 (void)
3885{
3886 return make_fixnum (w32_get_nproc ());
3887}
3888
3889 3881
3890void 3882void
3891syms_of_ntproc (void) 3883syms_of_ntproc (void)
@@ -3920,8 +3912,6 @@ syms_of_ntproc (void)
3920 defsubr (&Sw32_get_keyboard_layout); 3912 defsubr (&Sw32_get_keyboard_layout);
3921 defsubr (&Sw32_set_keyboard_layout); 3913 defsubr (&Sw32_set_keyboard_layout);
3922 3914
3923 defsubr (&Sw32_get_nproc);
3924
3925 DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args, 3915 DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args,
3926 doc: /* Non-nil enables quoting of process arguments to ensure correct parsing. 3916 doc: /* Non-nil enables quoting of process arguments to ensure correct parsing.
3927Because Windows does not directly pass argv arrays to child processes, 3917Because Windows does not directly pass argv arrays to child processes,
diff --git a/src/w32term.c b/src/w32term.c
index ad4d1a32829..07a5cd35649 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -168,8 +168,8 @@ int w32_keyboard_codepage;
168int w32_message_fd = -1; 168int w32_message_fd = -1;
169#endif /* CYGWIN */ 169#endif /* CYGWIN */
170 170
171static void w32_handle_tab_bar_click (struct frame *, 171static Lisp_Object w32_handle_tab_bar_click (struct frame *,
172 struct input_event *); 172 struct input_event *);
173static void w32_handle_tool_bar_click (struct frame *, 173static void w32_handle_tool_bar_click (struct frame *,
174 struct input_event *); 174 struct input_event *);
175static void w32_define_cursor (Window, Emacs_Cursor); 175static void w32_define_cursor (Window, Emacs_Cursor);
@@ -954,22 +954,6 @@ w32_set_cursor_gc (struct glyph_string *s)
954static void 954static void
955w32_set_mouse_face_gc (struct glyph_string *s) 955w32_set_mouse_face_gc (struct glyph_string *s)
956{ 956{
957 int face_id;
958 struct face *face;
959
960 /* What face has to be used last for the mouse face? */
961 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
962 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
963 if (face == NULL)
964 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
965
966 if (s->first_glyph->type == CHAR_GLYPH)
967 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
968 else
969 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
970 s->face = FACE_FROM_ID (s->f, face_id);
971 prepare_face_for_display (s->f, s->face);
972
973 /* If font in this face is same as S->font, use it. */ 957 /* If font in this face is same as S->font, use it. */
974 if (s->font == s->face->font) 958 if (s->font == s->face->font)
975 s->gc = s->face->gc; 959 s->gc = s->face->gc;
@@ -2031,11 +2015,14 @@ w32_draw_image_relief (struct glyph_string *s)
2031 if (s->hl == DRAW_IMAGE_SUNKEN 2015 if (s->hl == DRAW_IMAGE_SUNKEN
2032 || s->hl == DRAW_IMAGE_RAISED) 2016 || s->hl == DRAW_IMAGE_RAISED)
2033 { 2017 {
2034 thick = (tab_bar_button_relief < 0 2018 if (s->face->id == TAB_BAR_FACE_ID)
2035 ? DEFAULT_TAB_BAR_BUTTON_RELIEF 2019 thick = (tab_bar_button_relief < 0
2036 : (tool_bar_button_relief < 0 2020 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
2037 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF 2021 : min (tab_bar_button_relief, 1000000));
2038 : min (tool_bar_button_relief, 1000000))); 2022 else
2023 thick = (tool_bar_button_relief < 0
2024 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
2025 : min (tool_bar_button_relief, 1000000));
2039 raised_p = s->hl == DRAW_IMAGE_RAISED; 2026 raised_p = s->hl == DRAW_IMAGE_RAISED;
2040 } 2027 }
2041 else 2028 else
@@ -2054,11 +2041,11 @@ w32_draw_image_relief (struct glyph_string *s)
2054 && FIXNUMP (XCAR (Vtab_bar_button_margin)) 2041 && FIXNUMP (XCAR (Vtab_bar_button_margin))
2055 && FIXNUMP (XCDR (Vtab_bar_button_margin))) 2042 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
2056 { 2043 {
2057 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)); 2044 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
2058 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)); 2045 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
2059 } 2046 }
2060 else if (FIXNUMP (Vtab_bar_button_margin)) 2047 else if (FIXNUMP (Vtab_bar_button_margin))
2061 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin); 2048 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
2062 } 2049 }
2063 2050
2064 if (s->face->id == TOOL_BAR_FACE_ID) 2051 if (s->face->id == TOOL_BAR_FACE_ID)
@@ -2420,29 +2407,15 @@ w32_draw_stretch_glyph_string (struct glyph_string *s)
2420 else if (!s->background_filled_p) 2407 else if (!s->background_filled_p)
2421 { 2408 {
2422 int background_width = s->background_width; 2409 int background_width = s->background_width;
2423 int x = s->x, text_left_x = window_box_left_offset (s->w, TEXT_AREA); 2410 int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
2424 2411
2425 /* Don't draw into left fringe or scrollbar area except for 2412 /* Don't draw into left fringe or scrollbar area except for
2426 header line and mode line. */ 2413 header line and mode line. */
2427 if (x < text_left_x && !s->row->mode_line_p) 2414 if (s->area == TEXT_AREA
2415 && x < text_left_x && !s->row->mode_line_p)
2428 { 2416 {
2429 int left_x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w); 2417 background_width -= text_left_x - x;
2430 int right_x = text_left_x; 2418 x = text_left_x;
2431
2432 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w))
2433 left_x += WINDOW_LEFT_FRINGE_WIDTH (s->w);
2434 else
2435 right_x -= WINDOW_LEFT_FRINGE_WIDTH (s->w);
2436
2437 /* Adjust X and BACKGROUND_WIDTH to fit inside the space
2438 between LEFT_X and RIGHT_X. */
2439 if (x < left_x)
2440 {
2441 background_width -= left_x - x;
2442 x = left_x;
2443 }
2444 if (x + background_width > right_x)
2445 background_width = right_x - x;
2446 } 2419 }
2447 if (background_width > 0) 2420 if (background_width > 0)
2448 w32_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height); 2421 w32_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
@@ -3684,17 +3657,17 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
3684 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress 3657 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
3685 or ButtonRelease. */ 3658 or ButtonRelease. */
3686 3659
3687static void 3660static Lisp_Object
3688w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event) 3661w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event)
3689{ 3662{
3690 int x = XFIXNAT (button_event->x); 3663 int x = XFIXNAT (button_event->x);
3691 int y = XFIXNAT (button_event->y); 3664 int y = XFIXNAT (button_event->y);
3692 3665
3693 if (button_event->modifiers & down_modifier) 3666 if (button_event->modifiers & down_modifier)
3694 handle_tab_bar_click (f, x, y, 1, 0); 3667 return handle_tab_bar_click (f, x, y, 1, 0);
3695 else 3668 else
3696 handle_tab_bar_click (f, x, y, 0, 3669 return handle_tab_bar_click (f, x, y, 0,
3697 button_event->modifiers & ~up_modifier); 3670 button_event->modifiers & ~up_modifier);
3698} 3671}
3699 3672
3700 3673
@@ -5186,6 +5159,7 @@ w32_read_socket (struct terminal *terminal,
5186 { 5159 {
5187 /* If we decide we want to generate an event to be seen 5160 /* If we decide we want to generate an event to be seen
5188 by the rest of Emacs, we put it here. */ 5161 by the rest of Emacs, we put it here. */
5162 Lisp_Object tab_bar_arg = Qnil;
5189 bool tab_bar_p = 0; 5163 bool tab_bar_p = 0;
5190 bool tool_bar_p = 0; 5164 bool tool_bar_p = 0;
5191 int button = 0; 5165 int button = 0;
@@ -5208,12 +5182,12 @@ w32_read_socket (struct terminal *terminal,
5208 5182
5209 if (EQ (window, f->tab_bar_window)) 5183 if (EQ (window, f->tab_bar_window))
5210 { 5184 {
5211 w32_handle_tab_bar_click (f, &inev); 5185 tab_bar_arg = w32_handle_tab_bar_click (f, &inev);
5212 tab_bar_p = 1; 5186 tab_bar_p = 1;
5213 } 5187 }
5214 } 5188 }
5215 5189
5216 if (tab_bar_p 5190 if ((tab_bar_p && NILP (tab_bar_arg))
5217 || (dpyinfo->w32_focus_frame 5191 || (dpyinfo->w32_focus_frame
5218 && f != dpyinfo->w32_focus_frame 5192 && f != dpyinfo->w32_focus_frame
5219 /* This does not help when the click happens in 5193 /* This does not help when the click happens in
@@ -5221,6 +5195,9 @@ w32_read_socket (struct terminal *terminal,
5221 && !frame_ancestor_p (f, dpyinfo->w32_focus_frame))) 5195 && !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
5222 inev.kind = NO_EVENT; 5196 inev.kind = NO_EVENT;
5223 5197
5198 if (!NILP (tab_bar_arg))
5199 inev.arg = tab_bar_arg;
5200
5224 /* Is this in the tool-bar? */ 5201 /* Is this in the tool-bar? */
5225 if (WINDOWP (f->tool_bar_window) 5202 if (WINDOWP (f->tool_bar_window)
5226 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) 5203 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
diff --git a/src/window.c b/src/window.c
index a6e8ee0d534..e801ff821f1 100644
--- a/src/window.c
+++ b/src/window.c
@@ -20,6 +20,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20 20
21#include <config.h> 21#include <config.h>
22 22
23/* Work around GCC bug 102671. */
24#if 10 <= __GNUC__
25# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
26#endif
27
23#include "lisp.h" 28#include "lisp.h"
24#include "buffer.h" 29#include "buffer.h"
25#include "keyboard.h" 30#include "keyboard.h"
@@ -760,6 +765,19 @@ selected one. */)
760{ 765{
761 return make_fixnum (decode_live_window (window)->use_time); 766 return make_fixnum (decode_live_window (window)->use_time);
762} 767}
768
769DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
770 Swindow_bump_use_time, 0, 1, 0,
771 doc: /* Mark WINDOW as having been most recently used.
772WINDOW must be a live window and defaults to the selected one. */)
773 (Lisp_Object window)
774{
775 struct window *w = decode_live_window (window);
776
777 w->use_time = ++window_select_count;
778
779 return Qnil;
780}
763 781
764DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0, 782DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
765 doc: /* Return the width of window WINDOW in pixels. 783 doc: /* Return the width of window WINDOW in pixels.
@@ -3194,8 +3212,10 @@ function in a program gives strange scrolling, make sure the
3194window-start value is reasonable when this function is called. */) 3212window-start value is reasonable when this function is called. */)
3195 (Lisp_Object window, Lisp_Object root) 3213 (Lisp_Object window, Lisp_Object root)
3196{ 3214{
3197 struct window *w, *r, *s; 3215 struct window *w = decode_valid_window (window);
3198 struct frame *f; 3216 struct window *r, *s;
3217 Lisp_Object frame = w->frame;
3218 struct frame *f = XFRAME (frame);
3199 Lisp_Object sibling, pwindow, delta; 3219 Lisp_Object sibling, pwindow, delta;
3200 Lisp_Object swindow UNINIT; 3220 Lisp_Object swindow UNINIT;
3201 ptrdiff_t startpos UNINIT, startbyte UNINIT; 3221 ptrdiff_t startpos UNINIT, startbyte UNINIT;
@@ -3203,9 +3223,7 @@ window-start value is reasonable when this function is called. */)
3203 int new_top; 3223 int new_top;
3204 bool resize_failed = false; 3224 bool resize_failed = false;
3205 3225
3206 w = decode_valid_window (window);
3207 XSETWINDOW (window, w); 3226 XSETWINDOW (window, w);
3208 f = XFRAME (w->frame);
3209 3227
3210 if (NILP (root)) 3228 if (NILP (root))
3211 /* ROOT is the frame's root window. */ 3229 /* ROOT is the frame's root window. */
@@ -3245,7 +3263,7 @@ window-start value is reasonable when this function is called. */)
3245 /* Make sure WINDOW is the frame's selected window. */ 3263 /* Make sure WINDOW is the frame's selected window. */
3246 if (!EQ (window, FRAME_SELECTED_WINDOW (f))) 3264 if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
3247 { 3265 {
3248 if (EQ (selected_frame, w->frame)) 3266 if (EQ (selected_frame, frame))
3249 Fselect_window (window, Qnil); 3267 Fselect_window (window, Qnil);
3250 else 3268 else
3251 /* Do not clear f->select_mini_window_flag here. If the 3269 /* Do not clear f->select_mini_window_flag here. If the
@@ -3278,7 +3296,7 @@ window-start value is reasonable when this function is called. */)
3278 3296
3279 if (!EQ (swindow, FRAME_SELECTED_WINDOW (f))) 3297 if (!EQ (swindow, FRAME_SELECTED_WINDOW (f)))
3280 { 3298 {
3281 if (EQ (selected_frame, w->frame)) 3299 if (EQ (selected_frame, frame))
3282 Fselect_window (swindow, Qnil); 3300 Fselect_window (swindow, Qnil);
3283 else 3301 else
3284 fset_selected_window (f, swindow); 3302 fset_selected_window (f, swindow);
@@ -3313,18 +3331,12 @@ window-start value is reasonable when this function is called. */)
3313 w->top_line = r->top_line; 3331 w->top_line = r->top_line;
3314 resize_root_window (window, delta, Qnil, Qnil, Qt); 3332 resize_root_window (window, delta, Qnil, Qnil, Qt);
3315 if (window_resize_check (w, false)) 3333 if (window_resize_check (w, false))
3316 { 3334 window_resize_apply (w, false);
3317 window_resize_apply (w, false);
3318 window_pixel_to_total (w->frame, Qnil);
3319 }
3320 else 3335 else
3321 { 3336 {
3322 resize_root_window (window, delta, Qnil, Qt, Qt); 3337 resize_root_window (window, delta, Qnil, Qt, Qt);
3323 if (window_resize_check (w, false)) 3338 if (window_resize_check (w, false))
3324 { 3339 window_resize_apply (w, false);
3325 window_resize_apply (w, false);
3326 window_pixel_to_total (w->frame, Qnil);
3327 }
3328 else 3340 else
3329 resize_failed = true; 3341 resize_failed = true;
3330 } 3342 }
@@ -3337,18 +3349,12 @@ window-start value is reasonable when this function is called. */)
3337 XSETINT (delta, r->pixel_width - w->pixel_width); 3349 XSETINT (delta, r->pixel_width - w->pixel_width);
3338 resize_root_window (window, delta, Qt, Qnil, Qt); 3350 resize_root_window (window, delta, Qt, Qnil, Qt);
3339 if (window_resize_check (w, true)) 3351 if (window_resize_check (w, true))
3340 { 3352 window_resize_apply (w, true);
3341 window_resize_apply (w, true);
3342 window_pixel_to_total (w->frame, Qt);
3343 }
3344 else 3353 else
3345 { 3354 {
3346 resize_root_window (window, delta, Qt, Qt, Qt); 3355 resize_root_window (window, delta, Qt, Qt, Qt);
3347 if (window_resize_check (w, true)) 3356 if (window_resize_check (w, true))
3348 { 3357 window_resize_apply (w, true);
3349 window_resize_apply (w, true);
3350 window_pixel_to_total (w->frame, Qt);
3351 }
3352 else 3358 else
3353 resize_failed = true; 3359 resize_failed = true;
3354 } 3360 }
@@ -3390,6 +3396,12 @@ window-start value is reasonable when this function is called. */)
3390 } 3396 }
3391 3397
3392 replace_window (root, window, true); 3398 replace_window (root, window, true);
3399 /* Assign new total sizes to all windows on FRAME. We can't do that
3400 _before_ WINDOW replaces ROOT since 'window--pixel-to-total' works
3401 on the whole frame and thus would work on the frame's old window
3402 configuration (Bug#51007). */
3403 window_pixel_to_total (frame, Qnil);
3404 window_pixel_to_total (frame, Qt);
3393 3405
3394 /* This must become SWINDOW anyway ....... */ 3406 /* This must become SWINDOW anyway ....... */
3395 if (BUFFERP (w->contents) && !resize_failed) 3407 if (BUFFERP (w->contents) && !resize_failed)
@@ -8123,18 +8135,6 @@ and scrolling positions. */)
8123 return Qt; 8135 return Qt;
8124 return Qnil; 8136 return Qnil;
8125} 8137}
8126
8127DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
8128 Swindow_bump_use_time, 1, 1, 0,
8129 doc: /* Mark WINDOW as having been recently used. */)
8130 (Lisp_Object window)
8131{
8132 struct window *w = decode_valid_window (window);
8133
8134 w->use_time = ++window_select_count;
8135 return Qnil;
8136}
8137
8138 8138
8139 8139
8140static void init_window_once_for_pdumper (void); 8140static void init_window_once_for_pdumper (void);
diff --git a/src/xdisp.c b/src/xdisp.c
index b81b27469d0..1ecc6aa9cfd 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1179,7 +1179,13 @@ static void append_stretch_glyph (struct it *, Lisp_Object,
1179static Lisp_Object get_it_property (struct it *, Lisp_Object); 1179static Lisp_Object get_it_property (struct it *, Lisp_Object);
1180static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, 1180static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
1181 struct font *, int, bool); 1181 struct font *, int, bool);
1182 1182static int adjust_glyph_width_for_mouse_face (struct glyph *,
1183 struct glyph_row *,
1184 struct window *, struct face *,
1185 struct face *);
1186static void get_cursor_offset_for_mouse_face (struct window *w,
1187 struct glyph_row *row,
1188 int *offset);
1183#endif /* HAVE_WINDOW_SYSTEM */ 1189#endif /* HAVE_WINDOW_SYSTEM */
1184 1190
1185static void produce_special_glyphs (struct it *, enum display_element_type); 1191static void produce_special_glyphs (struct it *, enum display_element_type);
@@ -4288,12 +4294,17 @@ handle_fontified_prop (struct it *it)
4288 struct buffer *obuf = current_buffer; 4294 struct buffer *obuf = current_buffer;
4289 ptrdiff_t begv = BEGV, zv = ZV; 4295 ptrdiff_t begv = BEGV, zv = ZV;
4290 bool old_clip_changed = current_buffer->clip_changed; 4296 bool old_clip_changed = current_buffer->clip_changed;
4297 bool saved_inhibit_flag = it->f->inhibit_clear_image_cache;
4291 4298
4292 val = Vfontification_functions; 4299 val = Vfontification_functions;
4293 specbind (Qfontification_functions, Qnil); 4300 specbind (Qfontification_functions, Qnil);
4294 4301
4295 eassert (it->end_charpos == ZV); 4302 eassert (it->end_charpos == ZV);
4296 4303
4304 /* Don't allow Lisp that runs from 'fontification-functions'
4305 clear our face and image caches behind our back. */
4306 it->f->inhibit_clear_image_cache = true;
4307
4297 if (!CONSP (val) || EQ (XCAR (val), Qlambda)) 4308 if (!CONSP (val) || EQ (XCAR (val), Qlambda))
4298 safe_call1 (val, pos); 4309 safe_call1 (val, pos);
4299 else 4310 else
@@ -4327,6 +4338,7 @@ handle_fontified_prop (struct it *it)
4327 } 4338 }
4328 } 4339 }
4329 4340
4341 it->f->inhibit_clear_image_cache = saved_inhibit_flag;
4330 unbind_to (count, Qnil); 4342 unbind_to (count, Qnil);
4331 4343
4332 /* Fontification functions routinely call `save-restriction'. 4344 /* Fontification functions routinely call `save-restriction'.
@@ -4472,7 +4484,13 @@ face_at_pos (const struct it *it, enum lface_attribute_index attr_filter)
4472static enum prop_handled 4484static enum prop_handled
4473handle_face_prop (struct it *it) 4485handle_face_prop (struct it *it)
4474{ 4486{
4487 ptrdiff_t count = SPECPDL_INDEX ();
4488 /* Don't allow the user to quit out of face-merging code, in case
4489 this is called when redisplaying a non-selected window, with
4490 point temporarily moved to window-point. */
4491 specbind (Qinhibit_quit, Qt);
4475 const int new_face_id = face_at_pos (it, 0); 4492 const int new_face_id = face_at_pos (it, 0);
4493 unbind_to (count, Qnil);
4476 4494
4477 4495
4478 /* Is this a start of a run of characters with box face? 4496 /* Is this a start of a run of characters with box face?
@@ -4595,6 +4613,7 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
4595 SAVE_IT (it_copy, *it, it_copy_data); 4613 SAVE_IT (it_copy, *it, it_copy_data);
4596 IT_STRING_CHARPOS (it_copy) = 0; 4614 IT_STRING_CHARPOS (it_copy) = 0;
4597 bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it); 4615 bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
4616 it_copy.bidi_it.scan_dir = 0;
4598 4617
4599 do 4618 do
4600 { 4619 {
@@ -5781,8 +5800,15 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
5781#ifdef HAVE_WINDOW_SYSTEM 5800#ifdef HAVE_WINDOW_SYSTEM
5782 else 5801 else
5783 { 5802 {
5803 ptrdiff_t count = SPECPDL_INDEX ();
5804
5784 it->what = IT_IMAGE; 5805 it->what = IT_IMAGE;
5806 /* Don't allow quitting from lookup_image, for when we are
5807 displaying a non-selected window, and the buffer's point
5808 was temporarily moved to the window-point. */
5809 specbind (Qinhibit_quit, Qt);
5785 it->image_id = lookup_image (it->f, value, it->face_id); 5810 it->image_id = lookup_image (it->f, value, it->face_id);
5811 unbind_to (count, Qnil);
5786 it->position = start_pos; 5812 it->position = start_pos;
5787 it->object = NILP (object) ? it->w->contents : object; 5813 it->object = NILP (object) ? it->w->contents : object;
5788 it->method = GET_FROM_IMAGE; 5814 it->method = GET_FROM_IMAGE;
@@ -7648,7 +7674,8 @@ get_next_display_element (struct it *it)
7648 /* Merge `nobreak-space' into the current face. */ 7674 /* Merge `nobreak-space' into the current face. */
7649 face_id = merge_faces (it->w, Qnobreak_space, 0, 7675 face_id = merge_faces (it->w, Qnobreak_space, 0,
7650 it->face_id); 7676 it->face_id);
7651 XSETINT (it->ctl_chars[0], it->c); 7677 XSETINT (it->ctl_chars[0],
7678 nobreak_char_ascii_display ? ' ' : it->c);
7652 ctl_len = 1; 7679 ctl_len = 1;
7653 goto display_control; 7680 goto display_control;
7654 } 7681 }
@@ -7661,7 +7688,8 @@ get_next_display_element (struct it *it)
7661 /* Merge `nobreak-space' into the current face. */ 7688 /* Merge `nobreak-space' into the current face. */
7662 face_id = merge_faces (it->w, Qnobreak_hyphen, 0, 7689 face_id = merge_faces (it->w, Qnobreak_hyphen, 0,
7663 it->face_id); 7690 it->face_id);
7664 XSETINT (it->ctl_chars[0], it->c); 7691 XSETINT (it->ctl_chars[0],
7692 nobreak_char_ascii_display ? '-' : it->c);
7665 ctl_len = 1; 7693 ctl_len = 1;
7666 goto display_control; 7694 goto display_control;
7667 } 7695 }
@@ -10051,6 +10079,8 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
10051 10079
10052 case MOVE_NEWLINE_OR_CR: 10080 case MOVE_NEWLINE_OR_CR:
10053 max_current_x = max (it->current_x, max_current_x); 10081 max_current_x = max (it->current_x, max_current_x);
10082 if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
10083 it->override_ascent = -1;
10054 set_iterator_to_next (it, true); 10084 set_iterator_to_next (it, true);
10055 it->continuation_lines_width = 0; 10085 it->continuation_lines_width = 0;
10056 break; 10086 break;
@@ -10598,10 +10628,12 @@ in_display_vector_p (struct it *it)
10598 10628
10599DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0, 10629DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0,
10600 doc: /* Return the size of the text of WINDOW's buffer in pixels. 10630 doc: /* Return the size of the text of WINDOW's buffer in pixels.
10601WINDOW must be a live window and defaults to the selected one. The 10631WINDOW can be any live window and defaults to the selected one. The
10602return value is a cons of the maximum pixel-width of any text line 10632return value is a cons of the maximum pixel-width of any text line
10603and the pixel-height of all the text lines in the accessible portion 10633and the pixel-height of all the text lines in the accessible portion
10604of buffer text. 10634of buffer text.
10635WINDOW can also be a buffer, in which case the selected window is used,
10636and the function behaves as if that window was displaying this buffer.
10605 10637
10606This function exists to allow Lisp programs to adjust the dimensions 10638This function exists to allow Lisp programs to adjust the dimensions
10607of WINDOW to the buffer text it needs to display. 10639of WINDOW to the buffer text it needs to display.
@@ -10637,16 +10669,17 @@ position specified by TO. Since calculating the text height of a
10637large buffer can take some time, it makes sense to specify this 10669large buffer can take some time, it makes sense to specify this
10638argument if the size of the buffer is large or unknown. 10670argument if the size of the buffer is large or unknown.
10639 10671
10640Optional argument MODE-AND-HEADER-LINE nil or omitted means do not 10672Optional argument MODE-LINES nil or omitted means do not include the
10641include the height of the mode- or header-line of WINDOW in the return 10673height of the mode-, tab- or header-line of WINDOW in the return value.
10642value. If it is either the symbol `mode-line' or `header-line', include 10674If it is the symbol `mode-line', 'tab-line' or `header-line', include
10643only the height of that line, if present, in the return value. If t, 10675only the height of that line, if present, in the return value. If t,
10644include the height of both, if present, in the return value. */) 10676include the height of any of these, if present, in the return value. */)
10645 (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, 10677 (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit,
10646 Lisp_Object y_limit, Lisp_Object mode_and_header_line) 10678 Lisp_Object y_limit, Lisp_Object mode_lines)
10647{ 10679{
10648 struct window *w = decode_live_window (window); 10680 struct window *w = BUFFERP (window) ? XWINDOW (selected_window)
10649 Lisp_Object buffer = w->contents; 10681 : decode_live_window (window);
10682 Lisp_Object buffer = BUFFERP (window) ? window : w->contents;
10650 struct buffer *b; 10683 struct buffer *b;
10651 struct it it; 10684 struct it it;
10652 struct buffer *old_b = NULL; 10685 struct buffer *old_b = NULL;
@@ -10817,20 +10850,42 @@ include the height of both, if present, in the return value. */)
10817 if (y > max_y) 10850 if (y > max_y)
10818 y = max_y; 10851 y = max_y;
10819 10852
10820 if (EQ (mode_and_header_line, Qtab_line) 10853 if ((EQ (mode_lines, Qtab_line) || EQ (mode_lines, Qt))
10821 || EQ (mode_and_header_line, Qt)) 10854 && window_wants_tab_line (w))
10822 /* Re-add height of tab-line as requested. */ 10855 /* Add height of tab-line as requested. */
10823 y = y + WINDOW_TAB_LINE_HEIGHT (w); 10856 {
10857 Lisp_Object window_tab_line_format
10858 = window_parameter (w, Qtab_line_format);
10824 10859
10825 if (EQ (mode_and_header_line, Qheader_line) 10860 y = y + display_mode_line (w, TAB_LINE_FACE_ID,
10826 || EQ (mode_and_header_line, Qt)) 10861 NILP (window_tab_line_format)
10827 /* Re-add height of header-line as requested. */ 10862 ? BVAR (current_buffer, tab_line_format)
10828 y = y + WINDOW_HEADER_LINE_HEIGHT (w); 10863 : window_tab_line_format);
10864 }
10865
10866 if ((EQ (mode_lines, Qheader_line) || EQ (mode_lines, Qt))
10867 && window_wants_header_line (w))
10868 {
10869 Lisp_Object window_header_line_format
10870 = window_parameter (w, Qheader_line_format);
10871
10872 y = y + display_mode_line (w, HEADER_LINE_FACE_ID,
10873 NILP (window_header_line_format)
10874 ? BVAR (current_buffer, header_line_format)
10875 : window_header_line_format);
10876 }
10877
10878 if ((EQ (mode_lines, Qmode_line) || EQ (mode_lines, Qt))
10879 && window_wants_mode_line (w))
10880 {
10881 Lisp_Object window_mode_line_format
10882 = window_parameter (w, Qmode_line_format);
10829 10883
10830 if (EQ (mode_and_header_line, Qmode_line) 10884 y = y + display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
10831 || EQ (mode_and_header_line, Qt)) 10885 NILP (window_mode_line_format)
10832 /* Add height of mode-line as requested. */ 10886 ? BVAR (current_buffer, mode_line_format)
10833 y = y + WINDOW_MODE_LINE_HEIGHT (w); 10887 : window_mode_line_format);
10888 }
10834 10889
10835 bidi_unshelve_cache (itdata, false); 10890 bidi_unshelve_cache (itdata, false);
10836 10891
@@ -11757,7 +11812,7 @@ display_echo_area (struct window *w)
11757 /* If there is no message, we must call display_echo_area_1 11812 /* If there is no message, we must call display_echo_area_1
11758 nevertheless because it resizes the window. But we will have to 11813 nevertheless because it resizes the window. But we will have to
11759 reset the echo_area_buffer in question to nil at the end because 11814 reset the echo_area_buffer in question to nil at the end because
11760 with_echo_area_buffer will sets it to an empty buffer. */ 11815 with_echo_area_buffer will set it to an empty buffer. */
11761 bool i = display_last_displayed_message_p; 11816 bool i = display_last_displayed_message_p;
11762 /* According to the C99, C11 and C++11 standards, the integral value 11817 /* According to the C99, C11 and C++11 standards, the integral value
11763 of a "bool" is always 0 or 1, so this array access is safe here, 11818 of a "bool" is always 0 or 1, so this array access is safe here,
@@ -13745,7 +13800,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
13745 false for button release. MODIFIERS is event modifiers for button 13800 false for button release. MODIFIERS is event modifiers for button
13746 release. */ 13801 release. */
13747 13802
13748void 13803Lisp_Object
13749handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, 13804handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13750 int modifiers) 13805 int modifiers)
13751{ 13806{
@@ -13759,16 +13814,13 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13759 13814
13760 frame_to_window_pixel_xy (w, &x, &y); 13815 frame_to_window_pixel_xy (w, &x, &y);
13761 ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p); 13816 ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
13762 if (ts == -1 13817 if (ts == -1)
13763 /* If the button is released on a tab other than the one where 13818 return Fcons (Qtab_bar, Qnil);
13764 it was pressed, don't generate the tab-bar button click event. */
13765 || (ts != 0 && !down_p))
13766 return;
13767 13819
13768 /* If item is disabled, do nothing. */ 13820 /* If item is disabled, do nothing. */
13769 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); 13821 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
13770 if (NILP (enabled_p)) 13822 if (NILP (enabled_p))
13771 return; 13823 return Qnil;
13772 13824
13773 if (down_p) 13825 if (down_p)
13774 { 13826 {
@@ -13779,24 +13831,24 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13779 } 13831 }
13780 else 13832 else
13781 { 13833 {
13782 Lisp_Object key, frame;
13783 struct input_event event;
13784 EVENT_INIT (event);
13785
13786 /* Show item in released state. */ 13834 /* Show item in released state. */
13787 if (!NILP (Vmouse_highlight)) 13835 if (!NILP (Vmouse_highlight))
13788 show_mouse_face (hlinfo, DRAW_IMAGE_RAISED); 13836 show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
13789
13790 key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY);
13791
13792 XSETFRAME (frame, f);
13793 event.kind = TAB_BAR_EVENT;
13794 event.frame_or_window = frame;
13795 event.arg = key;
13796 event.modifiers = close_p ? ctrl_modifier | modifiers : modifiers;
13797 kbd_buffer_store_event (&event);
13798 f->last_tab_bar_item = -1; 13837 f->last_tab_bar_item = -1;
13799 } 13838 }
13839
13840 Lisp_Object caption =
13841 Fcopy_sequence (AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION));
13842
13843 AUTO_LIST2 (props, Qmenu_item,
13844 list3 (AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY),
13845 AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_BINDING),
13846 close_p ? Qt : Qnil));
13847
13848 Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)),
13849 props, caption);
13850
13851 return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
13800} 13852}
13801 13853
13802 13854
@@ -13842,15 +13894,18 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
13842 clear_mouse_face (hlinfo); 13894 clear_mouse_face (hlinfo);
13843 13895
13844 bool mouse_down_p = false; 13896 bool mouse_down_p = false;
13845#ifndef HAVE_NS 13897 /* Mouse is down, but on different tab-bar item? Or alternatively,
13846 /* Mouse is down, but on different tab-bar item? */ 13898 the mouse might've been pressed somewhere we don't know about,
13899 and then have moved onto the tab bar. In this case,
13900 last_tab_bar_item is -1, so we DTRT and behave like other
13901 programs by displaying the item as sunken. */
13847 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); 13902 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
13848 mouse_down_p = (gui_mouse_grabbed (dpyinfo) 13903 mouse_down_p = (gui_mouse_grabbed (dpyinfo)
13849 && f == dpyinfo->last_mouse_frame); 13904 && f == dpyinfo->last_mouse_frame);
13850 13905
13851 if (mouse_down_p && f->last_tab_bar_item != prop_idx) 13906 if (mouse_down_p && f->last_tab_bar_item != prop_idx
13907 && f->last_tab_bar_item != -1)
13852 return; 13908 return;
13853#endif
13854 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; 13909 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
13855 13910
13856 /* If tab-bar item is not enabled, don't highlight it. */ 13911 /* If tab-bar item is not enabled, don't highlight it. */
@@ -13894,7 +13949,7 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
13894 13949
13895/* Find the tab-bar item at X coordinate and return its information. */ 13950/* Find the tab-bar item at X coordinate and return its information. */
13896static Lisp_Object 13951static Lisp_Object
13897tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end) 13952tty_get_tab_bar_item (struct frame *f, int x, int *prop_idx, bool *close_p)
13898{ 13953{
13899 ptrdiff_t clen = 0; 13954 ptrdiff_t clen = 0;
13900 13955
@@ -13907,8 +13962,11 @@ tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end)
13907 clen += SCHARS (caption); 13962 clen += SCHARS (caption);
13908 if (x < clen) 13963 if (x < clen)
13909 { 13964 {
13910 *idx = i; 13965 *prop_idx = i;
13911 *end = clen; 13966 *close_p = !NILP (Fget_text_property (make_fixnum (SCHARS (caption)
13967 - (clen - x)),
13968 Qclose_tab,
13969 caption));
13912 return caption; 13970 return caption;
13913 } 13971 }
13914 } 13972 }
@@ -13920,61 +13978,45 @@ tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end)
13920 structure, store it in keyboard queue, and return true; otherwise 13978 structure, store it in keyboard queue, and return true; otherwise
13921 return false. MODIFIERS are event modifiers for generating the tab 13979 return false. MODIFIERS are event modifiers for generating the tab
13922 release event. */ 13980 release event. */
13923bool 13981Lisp_Object
13924tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, 13982tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
13925 struct input_event *event) 13983 struct input_event *event)
13926{ 13984{
13927 /* Did they click on the tab bar? */ 13985 /* Did they click on the tab bar? */
13928 if (y < FRAME_MENU_BAR_LINES (f) 13986 if (y < FRAME_MENU_BAR_LINES (f)
13929 || y >= FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f)) 13987 || y >= FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))
13930 return false; 13988 return Qnil;
13931 13989
13932 /* Find the tab-bar item where the X,Y coordinates belong. */ 13990 /* Find the tab-bar item where the X,Y coordinates belong. */
13933 int prop_idx; 13991 int prop_idx;
13934 ptrdiff_t clen; 13992 bool close_p;
13935 Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &clen); 13993 Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &close_p);
13936 13994
13937 if (NILP (caption)) 13995 if (NILP (caption))
13938 return false; 13996 return Qnil;
13939 13997
13940 if (NILP (AREF (f->tab_bar_items, 13998 if (NILP (AREF (f->tab_bar_items,
13941 prop_idx * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_ENABLED_P))) 13999 prop_idx * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_ENABLED_P)))
13942 return false; 14000 return Qnil;
13943 14001
13944 if (down_p) 14002 if (down_p)
13945 f->last_tab_bar_item = prop_idx; 14003 f->last_tab_bar_item = prop_idx;
13946 else 14004 else
13947 { 14005 f->last_tab_bar_item = -1;
13948 /* Force reset of up_modifier bit from the event modifiers. */
13949 if (event->modifiers & up_modifier)
13950 event->modifiers &= ~up_modifier;
13951
13952 /* Generate a TAB_BAR_EVENT event. */
13953 Lisp_Object frame;
13954 Lisp_Object key = AREF (f->tab_bar_items,
13955 prop_idx * TAB_BAR_ITEM_NSLOTS
13956 + TAB_BAR_ITEM_KEY);
13957 /* Kludge alert: we assume the last two characters of a tab
13958 label are " x", and treat clicks on those 2 characters as a
13959 Close Tab command. */
13960 eassert (STRINGP (caption));
13961 int lastc = SSDATA (caption)[SCHARS (caption) - 1];
13962 bool close_p = false;
13963 if ((x == clen - 1 || (clen > 1 && x == clen - 2)) && lastc == 'x')
13964 close_p = true;
13965
13966 event->code = 0;
13967 XSETFRAME (frame, f);
13968 event->kind = TAB_BAR_EVENT;
13969 event->frame_or_window = frame;
13970 event->arg = key;
13971 if (close_p)
13972 event->modifiers |= ctrl_modifier;
13973 kbd_buffer_store_event (event);
13974 f->last_tab_bar_item = -1;
13975 }
13976 14006
13977 return true; 14007 caption = Fcopy_sequence (caption);
14008
14009 AUTO_LIST2 (props, Qmenu_item,
14010 list3 (AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS
14011 + TAB_BAR_ITEM_KEY),
14012 AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS
14013 + TAB_BAR_ITEM_BINDING),
14014 close_p ? Qt : Qnil));
14015
14016 Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)),
14017 props, caption);
14018
14019 return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
13978} 14020}
13979 14021
13980 14022
@@ -14884,7 +14926,15 @@ hscroll_window_tree (Lisp_Object window)
14884 14926
14885 if (WINDOWP (w->contents)) 14927 if (WINDOWP (w->contents))
14886 hscrolled_p |= hscroll_window_tree (w->contents); 14928 hscrolled_p |= hscroll_window_tree (w->contents);
14887 else if (w->cursor.vpos >= 0) 14929 else if (w->cursor.vpos >= 0
14930 /* Don't allow hscroll in mini-windows that display
14931 echo-area messages. This is because desired_matrix
14932 of such windows was prepared while momentarily
14933 switched to an echo-area buffer, which is different
14934 from w->contents, and we simply cannot hscroll such
14935 windows safely. */
14936 && !(w == XWINDOW (echo_area_window)
14937 && !NILP (echo_area_buffer[0])))
14888 { 14938 {
14889 int h_margin; 14939 int h_margin;
14890 int text_area_width; 14940 int text_area_width;
@@ -15082,11 +15132,12 @@ hscroll_window_tree (Lisp_Object window)
15082 else 15132 else
15083 { 15133 {
15084 if (hscroll_relative_p) 15134 if (hscroll_relative_p)
15085 wanted_x = text_area_width * hscroll_step_rel 15135 wanted_x =
15086 + h_margin; 15136 text_area_width * hscroll_step_rel + h_margin + x_offset;
15087 else 15137 else
15088 wanted_x = hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f) 15138 wanted_x =
15089 + h_margin; 15139 hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
15140 + h_margin + x_offset;
15090 hscroll 15141 hscroll
15091 = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (it.f); 15142 = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (it.f);
15092 } 15143 }
@@ -16054,12 +16105,13 @@ redisplay_internal (void)
16054 if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) 16105 if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
16055 { 16106 {
16056 16107
16057 /* Don't allow freeing images for this frame as long 16108 /* Don't allow freeing images and faces for this
16058 as the frame's update wasn't completed. This 16109 frame as long as the frame's update wasn't
16059 prevents crashes when some Lisp that runs from 16110 completed. This prevents crashes when some Lisp
16060 the various hooks or font-lock decides to clear 16111 that runs from the various hooks or font-lock
16061 the frame's image cache, when the images in that 16112 decides to clear the frame's image cache and face
16062 cache are referenced by the desired matrix. */ 16113 cache, when the images and faces in those caches
16114 are referenced by the desired matrix. */
16063 f->inhibit_clear_image_cache = true; 16115 f->inhibit_clear_image_cache = true;
16064 redisplay_windows (FRAME_ROOT_WINDOW (f)); 16116 redisplay_windows (FRAME_ROOT_WINDOW (f));
16065 } 16117 }
@@ -17274,8 +17326,11 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
17274 17326
17275 if (!NILP (Vwindow_scroll_functions)) 17327 if (!NILP (Vwindow_scroll_functions))
17276 { 17328 {
17329 ptrdiff_t count = SPECPDL_INDEX ();
17330 specbind (Qinhibit_quit, Qt);
17277 run_hook_with_args_2 (Qwindow_scroll_functions, window, 17331 run_hook_with_args_2 (Qwindow_scroll_functions, window,
17278 make_fixnum (CHARPOS (startp))); 17332 make_fixnum (CHARPOS (startp)));
17333 unbind_to (count, Qnil);
17279 SET_TEXT_POS_FROM_MARKER (startp, w->start); 17334 SET_TEXT_POS_FROM_MARKER (startp, w->start);
17280 /* In case the hook functions switch buffers. */ 17335 /* In case the hook functions switch buffers. */
17281 set_buffer_internal (XBUFFER (w->contents)); 17336 set_buffer_internal (XBUFFER (w->contents));
@@ -19268,7 +19323,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19268 w->start_at_line_beg = (CHARPOS (startp) == BEGV 19323 w->start_at_line_beg = (CHARPOS (startp) == BEGV
19269 || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n'); 19324 || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
19270 19325
19271 /* Display the mode line, if we must. */ 19326 /* Display the mode line, header line, and tab-line, if we must. */
19272 if ((update_mode_line 19327 if ((update_mode_line
19273 /* If window not full width, must redo its mode line 19328 /* If window not full width, must redo its mode line
19274 if (a) the window to its side is being redone and 19329 if (a) the window to its side is being redone and
@@ -19287,8 +19342,11 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19287 || window_wants_header_line (w) 19342 || window_wants_header_line (w)
19288 || window_wants_tab_line (w))) 19343 || window_wants_tab_line (w)))
19289 { 19344 {
19345 ptrdiff_t count1 = SPECPDL_INDEX ();
19290 19346
19347 specbind (Qinhibit_quit, Qt);
19291 display_mode_lines (w); 19348 display_mode_lines (w);
19349 unbind_to (count1, Qnil);
19292 19350
19293 /* If mode line height has changed, arrange for a thorough 19351 /* If mode line height has changed, arrange for a thorough
19294 immediate redisplay using the correct mode line height. */ 19352 immediate redisplay using the correct mode line height. */
@@ -19336,7 +19394,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19336 finish_menu_bars: 19394 finish_menu_bars:
19337 19395
19338 /* When we reach a frame's selected window, redo the frame's menu 19396 /* When we reach a frame's selected window, redo the frame's menu
19339 bar and the frame's title. */ 19397 bar, tool bar, tab-bar, and the frame's title. */
19340 if (update_mode_line 19398 if (update_mode_line
19341 && EQ (FRAME_SELECTED_WINDOW (f), window)) 19399 && EQ (FRAME_SELECTED_WINDOW (f), window))
19342 { 19400 {
@@ -22104,10 +22162,17 @@ extend_face_to_end_of_line (struct it *it)
22104 || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) 22162 || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0))
22105 return; 22163 return;
22106 22164
22165 ptrdiff_t count = SPECPDL_INDEX ();
22166
22167 /* Don't allow the user to quit out of face-merging code, in case
22168 this is called when redisplaying a non-selected window, with
22169 point temporarily moved to window-point. */
22170 specbind (Qinhibit_quit, Qt);
22107 const int extend_face_id = (it->face_id == DEFAULT_FACE_ID 22171 const int extend_face_id = (it->face_id == DEFAULT_FACE_ID
22108 || it->s != NULL) 22172 || it->s != NULL)
22109 ? DEFAULT_FACE_ID 22173 ? DEFAULT_FACE_ID
22110 : face_at_pos (it, LFACE_EXTEND_INDEX); 22174 : face_at_pos (it, LFACE_EXTEND_INDEX);
22175 unbind_to (count, Qnil);
22111 22176
22112 /* Face extension extends the background and box of IT->extend_face_id 22177 /* Face extension extends the background and box of IT->extend_face_id
22113 to the end of the line. If the background equals the background 22178 to the end of the line. If the background equals the background
@@ -24444,7 +24509,7 @@ See also `bidi-paragraph-direction'. */)
24444 24509
24445DEFUN ("bidi-find-overridden-directionality", 24510DEFUN ("bidi-find-overridden-directionality",
24446 Fbidi_find_overridden_directionality, 24511 Fbidi_find_overridden_directionality,
24447 Sbidi_find_overridden_directionality, 2, 3, 0, 24512 Sbidi_find_overridden_directionality, 3, 4, 0,
24448 doc: /* Return position between FROM and TO where directionality was overridden. 24513 doc: /* Return position between FROM and TO where directionality was overridden.
24449 24514
24450This function returns the first character position in the specified 24515This function returns the first character position in the specified
@@ -24463,12 +24528,18 @@ a buffer is preferable when the buffer is displayed in some window,
24463because this function will then be able to correctly account for 24528because this function will then be able to correctly account for
24464window-specific overlays, which can affect the results. 24529window-specific overlays, which can affect the results.
24465 24530
24531Optional argument BASE-DIR specifies the base paragraph directory
24532of the text. It should be a symbol, either `left-to-right'
24533or `right-to-left', and defaults to `left-to-right'.
24534
24466Strong directional characters `L', `R', and `AL' can have their 24535Strong directional characters `L', `R', and `AL' can have their
24467intrinsic directionality overridden by directional override 24536intrinsic directionality overridden by directional override
24468control characters RLO (u+202e) and LRO (u+202d). See the 24537control characters RLO (u+202E) and LRO (u+202D). They can also
24469function `get-char-code-property' for a way to inquire about 24538have their directionality affected by other formatting control
24539characters: LRE (u+202A), RLE (u+202B), LRI (u+2066), and RLI (u+2067).
24540See the function `get-char-code-property' for a way to inquire about
24470the `bidi-class' property of a character. */) 24541the `bidi-class' property of a character. */)
24471 (Lisp_Object from, Lisp_Object to, Lisp_Object object) 24542 (Lisp_Object from, Lisp_Object to, Lisp_Object object, Lisp_Object base_dir)
24472{ 24543{
24473 struct buffer *buf = current_buffer; 24544 struct buffer *buf = current_buffer;
24474 struct buffer *old = buf; 24545 struct buffer *old = buf;
@@ -24565,10 +24636,9 @@ the `bidi-class' property of a character. */)
24565 } 24636 }
24566 24637
24567 ptrdiff_t found; 24638 ptrdiff_t found;
24639 bidi_dir_t bdir = EQ (base_dir, Qright_to_left) ? R2L : L2R;
24568 do { 24640 do {
24569 /* For the purposes of this function, the actual base direction of 24641 bidi_paragraph_init (bdir, &itb, false);
24570 the paragraph doesn't matter, so just set it to L2R. */
24571 bidi_paragraph_init (L2R, &itb, false);
24572 while ((found = bidi_find_first_overridden (&itb)) < from_pos) 24642 while ((found = bidi_find_first_overridden (&itb)) < from_pos)
24573 ; 24643 ;
24574 } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos); 24644 } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos);
@@ -25432,8 +25502,9 @@ redisplay_mode_lines (Lisp_Object window, bool force)
25432} 25502}
25433 25503
25434 25504
25435/* Display the mode and/or header line of window W. Value is the 25505/* Display the mode line, the header line, and the tab-line of window
25436 sum number of mode lines and header lines displayed. */ 25506 W. Value is the sum number of mode lines, header lines, and tab
25507 lines actually displayed. */
25437 25508
25438static int 25509static int
25439display_mode_lines (struct window *w) 25510display_mode_lines (struct window *w)
@@ -25563,7 +25634,8 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
25563 push_kboard (FRAME_KBOARD (it.f)); 25634 push_kboard (FRAME_KBOARD (it.f));
25564 record_unwind_save_match_data (); 25635 record_unwind_save_match_data ();
25565 25636
25566 if (NILP (Vmode_line_compact)) 25637 if (NILP (Vmode_line_compact)
25638 || face_id == HEADER_LINE_FACE_ID || face_id == TAB_LINE_FACE_ID)
25567 { 25639 {
25568 mode_line_target = MODE_LINE_DISPLAY; 25640 mode_line_target = MODE_LINE_DISPLAY;
25569 display_mode_element (&it, 0, 0, 0, format, Qnil, false); 25641 display_mode_element (&it, 0, 0, 0, format, Qnil, false);
@@ -27013,7 +27085,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
27013 Lisp_Object val = Qnil; 27085 Lisp_Object val = Qnil;
27014 27086
27015 if (STRINGP (curdir)) 27087 if (STRINGP (curdir))
27016 val = call1 (intern ("file-remote-p"), curdir); 27088 val = safe_call1 (intern ("file-remote-p"), curdir);
27017 27089
27018 val = unbind_to (count, val); 27090 val = unbind_to (count, val);
27019 27091
@@ -28099,6 +28171,19 @@ fill_composite_glyph_string (struct glyph_string *s, struct face *base_face,
28099 s->font = s->face->font; 28171 s->font = s->face->font;
28100 } 28172 }
28101 28173
28174 if (s->hl == DRAW_MOUSE_FACE
28175 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28176 {
28177 int c = COMPOSITION_GLYPH (s->cmp, 0);
28178 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28179 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28180 if (!s->face)
28181 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28182
28183 s->face = FACE_FROM_ID (s->f, FACE_FOR_CHAR (s->f, s->face, c, -1, Qnil));
28184 prepare_face_for_display (s->f, s->face);
28185 }
28186
28102 /* All glyph strings for the same composition has the same width, 28187 /* All glyph strings for the same composition has the same width,
28103 i.e. the width set for the first component of the composition. */ 28188 i.e. the width set for the first component of the composition. */
28104 s->width = s->first_glyph->pixel_width; 28189 s->width = s->first_glyph->pixel_width;
@@ -28135,7 +28220,17 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
28135 s->cmp_id = glyph->u.cmp.id; 28220 s->cmp_id = glyph->u.cmp.id;
28136 s->cmp_from = glyph->slice.cmp.from; 28221 s->cmp_from = glyph->slice.cmp.from;
28137 s->cmp_to = glyph->slice.cmp.to + 1; 28222 s->cmp_to = glyph->slice.cmp.to + 1;
28138 s->face = FACE_FROM_ID (s->f, face_id); 28223 if (s->hl == DRAW_MOUSE_FACE
28224 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28225 {
28226 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28227 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28228 if (!s->face)
28229 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28230 prepare_face_for_display (s->f, s->face);
28231 }
28232 else
28233 s->face = FACE_FROM_ID (s->f, face_id);
28139 lgstring = composition_gstring_from_id (s->cmp_id); 28234 lgstring = composition_gstring_from_id (s->cmp_id);
28140 s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring)); 28235 s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
28141 /* The width of a composition glyph string is the sum of the 28236 /* The width of a composition glyph string is the sum of the
@@ -28191,6 +28286,15 @@ fill_glyphless_glyph_string (struct glyph_string *s, int face_id,
28191 voffset = glyph->voffset; 28286 voffset = glyph->voffset;
28192 s->face = FACE_FROM_ID (s->f, face_id); 28287 s->face = FACE_FROM_ID (s->f, face_id);
28193 s->font = s->face->font ? s->face->font : FRAME_FONT (s->f); 28288 s->font = s->face->font ? s->face->font : FRAME_FONT (s->f);
28289 if (s->hl == DRAW_MOUSE_FACE
28290 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28291 {
28292 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28293 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28294 if (!s->face)
28295 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28296 prepare_face_for_display (s->f, s->face);
28297 }
28194 s->nchars = 1; 28298 s->nchars = 1;
28195 s->width = glyph->pixel_width; 28299 s->width = glyph->pixel_width;
28196 glyph++; 28300 glyph++;
@@ -28254,6 +28358,19 @@ fill_glyph_string (struct glyph_string *s, int face_id,
28254 28358
28255 s->font = s->face->font; 28359 s->font = s->face->font;
28256 28360
28361 if (s->hl == DRAW_MOUSE_FACE
28362 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28363 {
28364 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28365 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28366 if (!s->face)
28367 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28368 s->face
28369 = FACE_FROM_ID (s->f, FACE_FOR_CHAR (s->f, s->face,
28370 s->first_glyph->u.ch, -1, Qnil));
28371 prepare_face_for_display (s->f, s->face);
28372 }
28373
28257 /* If the specified font could not be loaded, use the frame's font, 28374 /* If the specified font could not be loaded, use the frame's font,
28258 but record the fact that we couldn't load it in 28375 but record the fact that we couldn't load it in
28259 S->font_not_found_p so that we can draw rectangles for the 28376 S->font_not_found_p so that we can draw rectangles for the
@@ -28283,6 +28400,15 @@ fill_image_glyph_string (struct glyph_string *s)
28283 s->slice = s->first_glyph->slice.img; 28400 s->slice = s->first_glyph->slice.img;
28284 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); 28401 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
28285 s->font = s->face->font; 28402 s->font = s->face->font;
28403 if (s->hl == DRAW_MOUSE_FACE
28404 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28405 {
28406 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28407 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28408 if (!s->face)
28409 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28410 prepare_face_for_display (s->f, s->face);
28411 }
28286 s->width = s->first_glyph->pixel_width; 28412 s->width = s->first_glyph->pixel_width;
28287 28413
28288 /* Adjust base line for subscript/superscript text. */ 28414 /* Adjust base line for subscript/superscript text. */
@@ -28297,9 +28423,18 @@ fill_xwidget_glyph_string (struct glyph_string *s)
28297 eassert (s->first_glyph->type == XWIDGET_GLYPH); 28423 eassert (s->first_glyph->type == XWIDGET_GLYPH);
28298 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); 28424 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
28299 s->font = s->face->font; 28425 s->font = s->face->font;
28426 if (s->hl == DRAW_MOUSE_FACE
28427 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28428 {
28429 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28430 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28431 if (!s->face)
28432 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28433 prepare_face_for_display (s->f, s->face);
28434 }
28300 s->width = s->first_glyph->pixel_width; 28435 s->width = s->first_glyph->pixel_width;
28301 s->ybase += s->first_glyph->voffset; 28436 s->ybase += s->first_glyph->voffset;
28302 s->xwidget = s->first_glyph->u.xwidget; 28437 s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget);
28303} 28438}
28304#endif 28439#endif
28305/* Fill glyph string S from a sequence of stretch glyphs. 28440/* Fill glyph string S from a sequence of stretch glyphs.
@@ -28322,6 +28457,15 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end)
28322 face_id = glyph->face_id; 28457 face_id = glyph->face_id;
28323 s->face = FACE_FROM_ID (s->f, face_id); 28458 s->face = FACE_FROM_ID (s->f, face_id);
28324 s->font = s->face->font; 28459 s->font = s->face->font;
28460 if (s->hl == DRAW_MOUSE_FACE
28461 || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
28462 {
28463 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
28464 s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
28465 if (!s->face)
28466 s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
28467 prepare_face_for_display (s->f, s->face);
28468 }
28325 s->width = glyph->pixel_width; 28469 s->width = glyph->pixel_width;
28326 s->nchars = 1; 28470 s->nchars = 1;
28327 voffset = glyph->voffset; 28471 voffset = glyph->voffset;
@@ -28569,7 +28713,12 @@ right_overwriting (struct glyph_string *s)
28569 28713
28570/* Set background width of glyph string S. START is the index of the 28714/* Set background width of glyph string S. START is the index of the
28571 first glyph following S. LAST_X is the right-most x-position + 1 28715 first glyph following S. LAST_X is the right-most x-position + 1
28572 in the drawing area. */ 28716 in the drawing area.
28717
28718 If S->hl is DRAW_CURSOR, S->f is a window system frame, and the
28719 cursor in S's window is currently inside mouse face, also update
28720 S->width to take into account potentially differing :box
28721 properties between the original face and the mouse face. */
28573 28722
28574static void 28723static void
28575set_glyph_string_background_width (struct glyph_string *s, int start, int last_x) 28724set_glyph_string_background_width (struct glyph_string *s, int start, int last_x)
@@ -28591,7 +28740,27 @@ set_glyph_string_background_width (struct glyph_string *s, int start, int last_x
28591 if (s->extends_to_end_of_line_p) 28740 if (s->extends_to_end_of_line_p)
28592 s->background_width = last_x - s->x + 1; 28741 s->background_width = last_x - s->x + 1;
28593 else 28742 else
28594 s->background_width = s->width; 28743 {
28744 s->background_width = s->width;
28745#ifdef HAVE_WINDOW_SYSTEM
28746 if (FRAME_WINDOW_P (s->f)
28747 && s->hl == DRAW_CURSOR
28748 && cursor_in_mouse_face_p (s->w))
28749 {
28750 /* Adjust the background width of the glyph string, because
28751 if the glyph's face has the :box attribute, its
28752 pixel_width might be different when it's displayed in the
28753 mouse-face, if that also has the :box attribute. */
28754 struct glyph *g = s->first_glyph;
28755 struct face *regular_face = FACE_FROM_ID (s->f, g->face_id);
28756 s->background_width +=
28757 adjust_glyph_width_for_mouse_face (g, s->row, s->w,
28758 regular_face, s->face);
28759 /* S->width is probably worth adjusting here as well. */
28760 s->width = s->background_width;
28761 }
28762#endif
28763 }
28595} 28764}
28596 28765
28597 28766
@@ -29140,7 +29309,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
29140 for (s = head; s; s = s->next) 29309 for (s = head; s; s = s->next)
29141 FRAME_RIF (f)->draw_glyph_string (s); 29310 FRAME_RIF (f)->draw_glyph_string (s);
29142 29311
29143#ifndef HAVE_NS
29144 /* When focus a sole frame and move horizontally, this clears on_p 29312 /* When focus a sole frame and move horizontally, this clears on_p
29145 causing a failure to erase prev cursor position. */ 29313 causing a failure to erase prev cursor position. */
29146 if (area == TEXT_AREA 29314 if (area == TEXT_AREA
@@ -29159,7 +29327,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
29159 notice_overwritten_cursor (w, TEXT_AREA, x0, x1, 29327 notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
29160 row->y, MATRIX_ROW_BOTTOM_Y (row)); 29328 row->y, MATRIX_ROW_BOTTOM_Y (row));
29161 } 29329 }
29162#endif
29163 29330
29164 /* Value is the x-position up to which drawn, relative to AREA of W. 29331 /* Value is the x-position up to which drawn, relative to AREA of W.
29165 This doesn't include parts drawn because of overhangs. */ 29332 This doesn't include parts drawn because of overhangs. */
@@ -29502,6 +29669,8 @@ produce_image_glyph (struct it *it)
29502 29669
29503 if (face->box != FACE_NO_BOX) 29670 if (face->box != FACE_NO_BOX)
29504 { 29671 {
29672 /* If you change the logic here, please change it in
29673 get_cursor_offset_for_mouse_face as well. */
29505 if (face->box_horizontal_line_width > 0) 29674 if (face->box_horizontal_line_width > 0)
29506 { 29675 {
29507 if (slice.y == 0) 29676 if (slice.y == 0)
@@ -29678,7 +29847,7 @@ produce_xwidget_glyph (struct it *it)
29678 glyph->padding_p = 0; 29847 glyph->padding_p = 0;
29679 glyph->glyph_not_available_p = 0; 29848 glyph->glyph_not_available_p = 0;
29680 glyph->face_id = it->face_id; 29849 glyph->face_id = it->face_id;
29681 glyph->u.xwidget = it->xwidget; 29850 glyph->u.xwidget = it->xwidget->xwidget_id;
29682 glyph->font_type = FONT_TYPE_UNKNOWN; 29851 glyph->font_type = FONT_TYPE_UNKNOWN;
29683 if (it->bidi_p) 29852 if (it->bidi_p)
29684 { 29853 {
@@ -31803,6 +31972,20 @@ erase_phys_cursor (struct window *w)
31803 && cursor_row->used[TEXT_AREA] > hpos && hpos >= 0) 31972 && cursor_row->used[TEXT_AREA] > hpos && hpos >= 0)
31804 mouse_face_here_p = true; 31973 mouse_face_here_p = true;
31805 31974
31975#ifdef HAVE_WINDOW_SYSTEM
31976 /* Since erasing the phys cursor will probably lead to corruption of
31977 the mouse face display if the glyph's pixel_width is not kept up
31978 to date with the :box property of the mouse face, just redraw the
31979 mouse face. */
31980 if (FRAME_WINDOW_P (WINDOW_XFRAME (w)) && mouse_face_here_p)
31981 {
31982 w->phys_cursor_on_p = false;
31983 w->phys_cursor_type = NO_CURSOR;
31984 show_mouse_face (MOUSE_HL_INFO (WINDOW_XFRAME (w)), DRAW_MOUSE_FACE);
31985 return;
31986 }
31987#endif
31988
31806 /* Maybe clear the display under the cursor. */ 31989 /* Maybe clear the display under the cursor. */
31807 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) 31990 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
31808 { 31991 {
@@ -32074,6 +32257,9 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
32074 && hlinfo->mouse_face_end_row < w->current_matrix->nrows) 32257 && hlinfo->mouse_face_end_row < w->current_matrix->nrows)
32075 { 32258 {
32076 bool phys_cursor_on_p = w->phys_cursor_on_p; 32259 bool phys_cursor_on_p = w->phys_cursor_on_p;
32260#ifdef HAVE_WINDOW_SYSTEM
32261 int mouse_off = 0;
32262#endif
32077 struct glyph_row *row, *first, *last; 32263 struct glyph_row *row, *first, *last;
32078 32264
32079 first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row); 32265 first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
@@ -32147,6 +32333,15 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
32147 row->mouse_face_p 32333 row->mouse_face_p
32148 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED; 32334 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
32149 } 32335 }
32336#ifdef HAVE_WINDOW_SYSTEM
32337 /* Compute the cursor offset due to mouse-highlight. */
32338 if ((MATRIX_ROW_VPOS (row, w->current_matrix) == w->phys_cursor.vpos)
32339 /* But not when highlighting a pseudo window, such as
32340 the toolbar, which can't have a cursor anyway. */
32341 && !w->pseudo_window_p
32342 && draw == DRAW_MOUSE_FACE)
32343 get_cursor_offset_for_mouse_face (w, row, &mouse_off);
32344#endif
32150 } 32345 }
32151 32346
32152 /* When we've written over the cursor, arrange for it to 32347 /* When we've written over the cursor, arrange for it to
@@ -32156,6 +32351,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
32156 { 32351 {
32157#ifdef HAVE_WINDOW_SYSTEM 32352#ifdef HAVE_WINDOW_SYSTEM
32158 int hpos = w->phys_cursor.hpos; 32353 int hpos = w->phys_cursor.hpos;
32354 int old_phys_cursor_x = w->phys_cursor.x;
32159 32355
32160 /* When the window is hscrolled, cursor hpos can legitimately be 32356 /* When the window is hscrolled, cursor hpos can legitimately be
32161 out of bounds, but we draw the cursor at the corresponding 32357 out of bounds, but we draw the cursor at the corresponding
@@ -32167,7 +32363,11 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
32167 32363
32168 block_input (); 32364 block_input ();
32169 display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos, 32365 display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos,
32170 w->phys_cursor.x, w->phys_cursor.y); 32366 w->phys_cursor.x + mouse_off,
32367 w->phys_cursor.y);
32368 /* Restore the original cursor coordinates, perhaps modified
32369 to account for mouse-highlight. */
32370 w->phys_cursor.x = old_phys_cursor_x;
32171 unblock_input (); 32371 unblock_input ();
32172#endif /* HAVE_WINDOW_SYSTEM */ 32372#endif /* HAVE_WINDOW_SYSTEM */
32173 } 32373 }
@@ -33547,7 +33747,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
33547 && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))) 33747 && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f)))
33548 { 33748 {
33549 int prop_idx; 33749 int prop_idx;
33550 ptrdiff_t ignore; 33750 bool ignore;
33551 Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore); 33751 Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore);
33552 33752
33553 if (!NILP (caption)) 33753 if (!NILP (caption))
@@ -33630,7 +33830,21 @@ note_mouse_highlight (struct frame *f, int x, int y)
33630 if (EQ (window, f->tab_bar_window)) 33830 if (EQ (window, f->tab_bar_window))
33631 { 33831 {
33632 note_tab_bar_highlight (f, x, y); 33832 note_tab_bar_highlight (f, x, y);
33633 return; 33833 if (tab_bar__dragging_in_progress)
33834 {
33835 cursor = FRAME_OUTPUT_DATA (f)->hand_cursor;
33836 goto set_cursor;
33837 }
33838 else
33839 return;
33840 }
33841 else
33842 {
33843 /* The mouse might have pressed into the tab bar, but might
33844 also have been released outside the tab bar, so
33845 f->last_tab_bar_item must be reset, in order to make sure the
33846 item can be still highlighted again in the future. */
33847 f->last_tab_bar_item = -1;
33634 } 33848 }
33635#endif 33849#endif
33636 33850
@@ -35021,6 +35235,26 @@ glyph followed by an ordinary space or hyphen.
35021A value of nil means no special handling of these characters. */); 35235A value of nil means no special handling of these characters. */);
35022 Vnobreak_char_display = Qt; 35236 Vnobreak_char_display = Qt;
35023 35237
35238 DEFVAR_BOOL ("nobreak-char-ascii-display", nobreak_char_ascii_display,
35239 doc: /* Control display of non-ASCII space and hyphen chars.
35240If the value of this variable is nil, the default, Emacs displays
35241non-ASCII chars which have the same appearance as an ASCII space
35242or hyphen as themselves, with the `nobreak-space' or `nobreak-hyphen'
35243face, respectively.
35244
35245If the value is t, these characters are displayed as their ASCII
35246counterparts: whitespace characters as ASCII space, hyphen characters
35247as ASCII hyphen (a.k.a. \"dash\"), using the `nobreak-space' or
35248the `nobreak-hyphen' face.
35249
35250This variable has effect only if `nobreak-char-display' is t;
35251otherwise it is ignored.
35252
35253All of the non-ASCII characters in the Unicode horizontal whitespace
35254character class, as well as U+00AD (soft hyphen), U+2010 (hyphen), and
35255U+2011 (non-breaking hyphen) are affected. */);
35256 nobreak_char_ascii_display = false;
35257
35024 DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer, 35258 DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer,
35025 doc: /* The pointer shape to show in void text areas. 35259 doc: /* The pointer shape to show in void text areas.
35026A value of nil means to show the text pointer. Other options are 35260A value of nil means to show the text pointer. Other options are
@@ -35114,7 +35348,10 @@ not span the full frame width.
35114 35348
35115A value of nil means to respect the value of `truncate-lines'. 35349A value of nil means to respect the value of `truncate-lines'.
35116 35350
35117If `word-wrap' is enabled, you might want to reduce this. */); 35351If `word-wrap' is enabled, you might want to reduce the value of this.
35352
35353Don't set this to a non-nil value when `visual-line-mode' is
35354turned on, as it could produce confusing results. */);
35118 Vtruncate_partial_width_windows = make_fixnum (50); 35355 Vtruncate_partial_width_windows = make_fixnum (50);
35119 35356
35120 DEFVAR_BOOL("word-wrap-by-category", word_wrap_by_category, doc: /* 35357 DEFVAR_BOOL("word-wrap-by-category", word_wrap_by_category, doc: /*
@@ -35423,7 +35660,7 @@ and `scroll-right' overrides this variable's effect. */);
35423 Vhscroll_step = make_fixnum (0); 35660 Vhscroll_step = make_fixnum (0);
35424 35661
35425 DEFVAR_BOOL ("message-truncate-lines", message_truncate_lines, 35662 DEFVAR_BOOL ("message-truncate-lines", message_truncate_lines,
35426 doc: /* If non-nil, messages are truncated instead of resizing the echo area. 35663 doc: /* If non-nil, messages are truncated when displaying the echo area.
35427Bind this around calls to `message' to let it take effect. */); 35664Bind this around calls to `message' to let it take effect. */);
35428 message_truncate_lines = false; 35665 message_truncate_lines = false;
35429 35666
@@ -35737,6 +35974,10 @@ When nil, mouse-movement events will not be generated as long as the
35737mouse stays within the extent of a single glyph (except for images). */); 35974mouse stays within the extent of a single glyph (except for images). */);
35738 mouse_fine_grained_tracking = false; 35975 mouse_fine_grained_tracking = false;
35739 35976
35977 DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,
35978 doc: /* Non-nil when maybe dragging tab bar item. */);
35979 tab_bar__dragging_in_progress = false;
35980
35740 DEFVAR_BOOL ("redisplay-skip-initial-frame", redisplay_skip_initial_frame, 35981 DEFVAR_BOOL ("redisplay-skip-initial-frame", redisplay_skip_initial_frame,
35741 doc: /* Non-nil to skip redisplay in initial frame. 35982 doc: /* Non-nil to skip redisplay in initial frame.
35742The initial frame is not displayed anywhere, so skipping it is 35983The initial frame is not displayed anywhere, so skipping it is
@@ -35916,4 +36157,121 @@ cancel_hourglass (void)
35916 } 36157 }
35917} 36158}
35918 36159
36160/* Return a correction to be applied to G->pixel_width when it is
36161 displayed in MOUSE_FACE. This is needed for the first and the last
36162 glyphs of text inside a face with :box when it is displayed with
36163 MOUSE_FACE that has a different or no :box attribute.
36164 ORIGINAL_FACE is the face G was originally drawn in, and MOUSE_FACE
36165 is the face it will be drawn in now. ROW is the G's glyph row and
36166 W is its window. */
36167static int
36168adjust_glyph_width_for_mouse_face (struct glyph *g, struct glyph_row *row,
36169 struct window *w,
36170 struct face *original_face,
36171 struct face *mouse_face)
36172{
36173 int sum = 0;
36174
36175 bool do_left_box_p = g->left_box_line_p;
36176 bool do_right_box_p = g->right_box_line_p;
36177
36178 /* This is required because we test some parameters of the image
36179 slice before applying the box in produce_image_glyph. */
36180 if (g->type == IMAGE_GLYPH)
36181 {
36182 if (!row->reversed_p)
36183 {
36184 struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
36185 g->u.img_id);
36186 do_left_box_p = g->left_box_line_p &&
36187 g->slice.img.x == 0;
36188 do_right_box_p = g->right_box_line_p &&
36189 g->slice.img.x + g->slice.img.width == img->width;
36190 }
36191 else
36192 {
36193 struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
36194 g->u.img_id);
36195 do_left_box_p = g->left_box_line_p &&
36196 g->slice.img.x + g->slice.img.width == img->width;
36197 do_right_box_p = g->right_box_line_p &&
36198 g->slice.img.x == 0;
36199 }
36200 }
36201
36202 /* If the glyph has a left box line, subtract it from the offset. */
36203 if (do_left_box_p)
36204 sum -= max (0, original_face->box_vertical_line_width);
36205 /* Likewise with the right box line, as there may be a
36206 box there as well. */
36207 if (do_right_box_p)
36208 sum -= max (0, original_face->box_vertical_line_width);
36209 /* Now add the line widths from the new face. */
36210 if (g->left_box_line_p)
36211 sum += max (0, mouse_face->box_vertical_line_width);
36212 if (g->right_box_line_p)
36213 sum += max (0, mouse_face->box_vertical_line_width);
36214
36215 return sum;
36216}
36217
36218/* Get the offset due to mouse-highlight to apply before drawing
36219 phys_cursor, and return it in OFFSET. ROW should be the row that
36220 is under mouse face and contains the phys cursor.
36221
36222 This is required because the produce_XXX_glyph series of functions
36223 add the width of the various vertical box lines to the total width
36224 of the glyphs, but that must be updated when the row is put under
36225 mouse face, which can have different box dimensions. */
36226static void
36227get_cursor_offset_for_mouse_face (struct window *w, struct glyph_row *row,
36228 int *offset)
36229{
36230 int sum = 0;
36231 /* Return because the mode line can't possibly have a cursor. */
36232 if (row->mode_line_p)
36233 return;
36234
36235 block_input ();
36236
36237 struct frame *f = WINDOW_XFRAME (w);
36238 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
36239 struct glyph *start, *end;
36240 struct face *mouse_face = FACE_FROM_ID (f, hlinfo->mouse_face_face_id);
36241 int hpos = w->phys_cursor.hpos;
36242 end = &row->glyphs[TEXT_AREA][hpos];
36243
36244 if (!row->reversed_p)
36245 {
36246 if (MATRIX_ROW_VPOS (row, w->current_matrix) ==
36247 hlinfo->mouse_face_beg_row)
36248 start = &row->glyphs[TEXT_AREA][hlinfo->mouse_face_beg_col];
36249 else
36250 start = row->glyphs[TEXT_AREA];
36251 }
36252 else
36253 {
36254 if (MATRIX_ROW_VPOS (row, w->current_matrix) ==
36255 hlinfo->mouse_face_end_row)
36256 start = &row->glyphs[TEXT_AREA][hlinfo->mouse_face_end_col];
36257 else
36258 start = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
36259 }
36260
36261 /* Calculate the offset by which to correct phys_cursor x if we are
36262 drawing the cursor inside mouse-face highlighted text. */
36263
36264 for ( ; row->reversed_p ? start > end : start < end;
36265 row->reversed_p ? --start : ++start)
36266 sum += adjust_glyph_width_for_mouse_face (start, row, w,
36267 FACE_FROM_ID (f, start->face_id),
36268 mouse_face);
36269
36270 if (row->reversed_p)
36271 sum = -sum;
36272
36273 *offset = sum;
36274
36275 unblock_input ();
36276}
35919#endif /* HAVE_WINDOW_SYSTEM */ 36277#endif /* HAVE_WINDOW_SYSTEM */
diff --git a/src/xfaces.c b/src/xfaces.c
index 37ad11b713c..d4e6270e493 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -698,7 +698,8 @@ clear_face_cache (bool clear_fonts_p)
698 { 698 {
699 struct frame *f = XFRAME (frame); 699 struct frame *f = XFRAME (frame);
700 if (FRAME_WINDOW_P (f) 700 if (FRAME_WINDOW_P (f)
701 && FRAME_DISPLAY_INFO (f)->n_fonts > CLEAR_FONT_TABLE_NFONTS) 701 && FRAME_DISPLAY_INFO (f)->n_fonts > CLEAR_FONT_TABLE_NFONTS
702 && !f->inhibit_clear_image_cache)
702 { 703 {
703 clear_font_cache (f); 704 clear_font_cache (f);
704 free_all_realized_faces (frame); 705 free_all_realized_faces (frame);
@@ -2443,11 +2444,11 @@ evaluate_face_filter (Lisp_Object filter, struct window *w,
2443/* Determine whether FACE_REF is a "filter" face specification (case 2444/* Determine whether FACE_REF is a "filter" face specification (case
2444 #4 in merge_face_ref). If it is, evaluate the filter, and if the 2445 #4 in merge_face_ref). If it is, evaluate the filter, and if the
2445 filter matches, return the filtered face spec. If the filter does 2446 filter matches, return the filtered face spec. If the filter does
2446 not match, return `nil'. If FACE_REF is not a filtered face 2447 not match, return nil. If FACE_REF is not a filtered face
2447 specification, return FACE_REF. 2448 specification, return FACE_REF.
2448 2449
2449 On error, set *OK to false, having logged an error message if 2450 On error, set *OK to false, having logged an error message if
2450 ERR_MSGS is true, and return `nil'. Otherwise, *OK is not touched. 2451 ERR_MSGS is true, and return nil. Otherwise, *OK is not touched.
2451 2452
2452 W is either NULL or a window used to evaluate filters. If W is 2453 W is either NULL or a window used to evaluate filters. If W is
2453 NULL, no window-based face specification filter matches. 2454 NULL, no window-based face specification filter matches.
@@ -2732,7 +2733,7 @@ merge_face_ref (struct window *w,
2732 { 2733 {
2733 if (EQ (value, Qt)) 2734 if (EQ (value, Qt))
2734 value = make_fixnum (1); 2735 value = make_fixnum (1);
2735 if (FIXNUMP (value) 2736 if ((FIXNUMP (value) && XFIXNUM (value) != 0)
2736 || STRINGP (value) 2737 || STRINGP (value)
2737 || CONSP (value) 2738 || CONSP (value)
2738 || NILP (value)) 2739 || NILP (value))
@@ -5116,8 +5117,8 @@ gui_supports_face_attributes_p (struct frame *f,
5116{ 5117{
5117 Lisp_Object *def_attrs = def_face->lface; 5118 Lisp_Object *def_attrs = def_face->lface;
5118 5119
5119 /* Check that other specified attributes are different that the default 5120 /* Check that other specified attributes are different from the
5120 face. */ 5121 default face. */
5121 if ((!UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX]) 5122 if ((!UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX])
5122 && face_attr_equal_p (attrs[LFACE_UNDERLINE_INDEX], 5123 && face_attr_equal_p (attrs[LFACE_UNDERLINE_INDEX],
5123 def_attrs[LFACE_UNDERLINE_INDEX])) 5124 def_attrs[LFACE_UNDERLINE_INDEX]))
@@ -5396,6 +5397,10 @@ DEFUN ("display-supports-face-attributes-p",
5396The optional argument DISPLAY can be a display name, a frame, or 5397The optional argument DISPLAY can be a display name, a frame, or
5397nil (meaning the selected frame's display). 5398nil (meaning the selected frame's display).
5398 5399
5400For instance, to check whether the display supports underlining:
5401
5402 (display-supports-face-attributes-p \\='(:underline t))
5403
5399The definition of `supported' is somewhat heuristic, but basically means 5404The definition of `supported' is somewhat heuristic, but basically means
5400that a face containing all the attributes in ATTRIBUTES, when merged 5405that a face containing all the attributes in ATTRIBUTES, when merged
5401with the default face for display, can be represented in a way that's 5406with the default face for display, can be represented in a way that's
@@ -6956,13 +6961,20 @@ syms_of_xfaces (void)
6956 DEFSYM (Qpressed_button, "pressed-button"); 6961 DEFSYM (Qpressed_button, "pressed-button");
6957 DEFSYM (Qflat_button, "flat-button"); 6962 DEFSYM (Qflat_button, "flat-button");
6958 DEFSYM (Qnormal, "normal"); 6963 DEFSYM (Qnormal, "normal");
6964 DEFSYM (Qthin, "thin");
6959 DEFSYM (Qextra_light, "extra-light"); 6965 DEFSYM (Qextra_light, "extra-light");
6966 DEFSYM (Qultra_light, "ultra-light");
6960 DEFSYM (Qlight, "light"); 6967 DEFSYM (Qlight, "light");
6961 DEFSYM (Qsemi_light, "semi-light"); 6968 DEFSYM (Qsemi_light, "semi-light");
6969 DEFSYM (Qmedium, "medium");
6962 DEFSYM (Qsemi_bold, "semi-bold"); 6970 DEFSYM (Qsemi_bold, "semi-bold");
6971 DEFSYM (Qbook, "book");
6963 DEFSYM (Qbold, "bold"); 6972 DEFSYM (Qbold, "bold");
6964 DEFSYM (Qextra_bold, "extra-bold"); 6973 DEFSYM (Qextra_bold, "extra-bold");
6965 DEFSYM (Qultra_bold, "ultra-bold"); 6974 DEFSYM (Qultra_bold, "ultra-bold");
6975 DEFSYM (Qheavy, "heavy");
6976 DEFSYM (Qultra_heavy, "ultra-heavy");
6977 DEFSYM (Qblack, "black");
6966 DEFSYM (Qoblique, "oblique"); 6978 DEFSYM (Qoblique, "oblique");
6967 DEFSYM (Qitalic, "italic"); 6979 DEFSYM (Qitalic, "italic");
6968 6980
diff --git a/src/xfns.c b/src/xfns.c
index 81349d0b50d..785ae3baca5 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6222,7 +6222,7 @@ Otherwise, the return value is a vector with the following fields:
6222static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, 6222static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
6223 Lisp_Object, int, int, int *, int *); 6223 Lisp_Object, int, int, int *, int *);
6224 6224
6225/* The frame of the currently visible tooltip. */ 6225/* The frame of the currently visible tooltip, or nil if none. */
6226static Lisp_Object tip_frame; 6226static Lisp_Object tip_frame;
6227 6227
6228/* The window-system window corresponding to the frame of the 6228/* The window-system window corresponding to the frame of the
@@ -6710,7 +6710,7 @@ x_hide_tip (bool delete)
6710 if ((NILP (tip_last_frame) && NILP (tip_frame)) 6710 if ((NILP (tip_last_frame) && NILP (tip_frame))
6711 || (!x_gtk_use_system_tooltips 6711 || (!x_gtk_use_system_tooltips
6712 && !delete 6712 && !delete
6713 && FRAMEP (tip_frame) 6713 && !NILP (tip_frame)
6714 && FRAME_LIVE_P (XFRAME (tip_frame)) 6714 && FRAME_LIVE_P (XFRAME (tip_frame))
6715 && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) 6715 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
6716 /* Either there's no tooltip to hide or it's an already invisible 6716 /* Either there's no tooltip to hide or it's an already invisible
@@ -6727,7 +6727,7 @@ x_hide_tip (bool delete)
6727 specbind (Qinhibit_quit, Qt); 6727 specbind (Qinhibit_quit, Qt);
6728 6728
6729 /* Try to hide the GTK+ system tip first. */ 6729 /* Try to hide the GTK+ system tip first. */
6730 if (FRAMEP (tip_last_frame)) 6730 if (!NILP (tip_last_frame))
6731 { 6731 {
6732 struct frame *f = XFRAME (tip_last_frame); 6732 struct frame *f = XFRAME (tip_last_frame);
6733 6733
@@ -6745,7 +6745,7 @@ x_hide_tip (bool delete)
6745 tip_last_frame = Qnil; 6745 tip_last_frame = Qnil;
6746 6746
6747 /* Now look whether there's an Emacs tip around. */ 6747 /* Now look whether there's an Emacs tip around. */
6748 if (FRAMEP (tip_frame)) 6748 if (!NILP (tip_frame))
6749 { 6749 {
6750 struct frame *f = XFRAME (tip_frame); 6750 struct frame *f = XFRAME (tip_frame);
6751 6751
@@ -6775,7 +6775,7 @@ x_hide_tip (bool delete)
6775#else /* not USE_GTK */ 6775#else /* not USE_GTK */
6776 if (NILP (tip_frame) 6776 if (NILP (tip_frame)
6777 || (!delete 6777 || (!delete
6778 && FRAMEP (tip_frame) 6778 && !NILP (tip_frame)
6779 && FRAME_LIVE_P (XFRAME (tip_frame)) 6779 && FRAME_LIVE_P (XFRAME (tip_frame))
6780 && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) 6780 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
6781 return Qnil; 6781 return Qnil;
@@ -6788,7 +6788,7 @@ x_hide_tip (bool delete)
6788 specbind (Qinhibit_redisplay, Qt); 6788 specbind (Qinhibit_redisplay, Qt);
6789 specbind (Qinhibit_quit, Qt); 6789 specbind (Qinhibit_quit, Qt);
6790 6790
6791 if (FRAMEP (tip_frame)) 6791 if (!NILP (tip_frame))
6792 { 6792 {
6793 struct frame *f = XFRAME (tip_frame); 6793 struct frame *f = XFRAME (tip_frame);
6794 6794
@@ -6931,7 +6931,7 @@ Text larger than the specified size is clipped. */)
6931 } 6931 }
6932#endif /* USE_GTK */ 6932#endif /* USE_GTK */
6933 6933
6934 if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) 6934 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
6935 { 6935 {
6936 if (FRAME_VISIBLE_P (XFRAME (tip_frame)) 6936 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
6937 && EQ (frame, tip_last_frame) 6937 && EQ (frame, tip_last_frame)
@@ -7016,7 +7016,7 @@ Text larger than the specified size is clipped. */)
7016 tip_last_string = string; 7016 tip_last_string = string;
7017 tip_last_parms = parms; 7017 tip_last_parms = parms;
7018 7018
7019 if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) 7019 if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
7020 { 7020 {
7021 /* Add default values to frame parameters. */ 7021 /* Add default values to frame parameters. */
7022 if (NILP (Fassq (Qname, parms))) 7022 if (NILP (Fassq (Qname, parms)))
@@ -7836,7 +7836,6 @@ syms_of_xfns (void)
7836 DEFSYM (Qfont_parameter, "font-parameter"); 7836 DEFSYM (Qfont_parameter, "font-parameter");
7837 DEFSYM (Qmono, "mono"); 7837 DEFSYM (Qmono, "mono");
7838 DEFSYM (Qassq_delete_all, "assq-delete-all"); 7838 DEFSYM (Qassq_delete_all, "assq-delete-all");
7839 DEFSYM (Qhide, "hide");
7840 DEFSYM (Qresize_mode, "resize-mode"); 7839 DEFSYM (Qresize_mode, "resize-mode");
7841 7840
7842#ifdef USE_CAIRO 7841#ifdef USE_CAIRO
diff --git a/src/xmenu.c b/src/xmenu.c
index a6762236bc4..ea2cbab2030 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1603,6 +1603,14 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
1603 STRINGP (help) ? help : Qnil); 1603 STRINGP (help) ? help : Qnil);
1604 if (prev_wv) 1604 if (prev_wv)
1605 prev_wv->next = wv; 1605 prev_wv->next = wv;
1606 else if (!save_wv)
1607 {
1608 /* This emacs_abort call pacifies gcc 11.2.1 when Emacs
1609 is configured with --enable-gcc-warnings. FIXME: If
1610 save_wv can be null, do something better; otherwise,
1611 explain why save_wv cannot be null. */
1612 emacs_abort ();
1613 }
1606 else 1614 else
1607 save_wv->contents = wv; 1615 save_wv->contents = wv;
1608 if (!NILP (descrip)) 1616 if (!NILP (descrip))
diff --git a/src/xterm.c b/src/xterm.c
index 1887c3255d4..172abe919dd 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1563,22 +1563,6 @@ x_set_cursor_gc (struct glyph_string *s)
1563static void 1563static void
1564x_set_mouse_face_gc (struct glyph_string *s) 1564x_set_mouse_face_gc (struct glyph_string *s)
1565{ 1565{
1566 int face_id;
1567 struct face *face;
1568
1569 /* What face has to be used last for the mouse face? */
1570 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1571 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1572 if (face == NULL)
1573 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1574
1575 if (s->first_glyph->type == CHAR_GLYPH)
1576 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1577 else
1578 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1579 s->face = FACE_FROM_ID (s->f, face_id);
1580 prepare_face_for_display (s->f, s->face);
1581
1582 if (s->font == s->face->font) 1566 if (s->font == s->face->font)
1583 s->gc = s->face->gc; 1567 s->gc = s->face->gc;
1584 else 1568 else
@@ -3209,11 +3193,14 @@ x_draw_image_relief (struct glyph_string *s)
3209 if (s->hl == DRAW_IMAGE_SUNKEN 3193 if (s->hl == DRAW_IMAGE_SUNKEN
3210 || s->hl == DRAW_IMAGE_RAISED) 3194 || s->hl == DRAW_IMAGE_RAISED)
3211 { 3195 {
3212 thick = (tab_bar_button_relief < 0 3196 if (s->face->id == TAB_BAR_FACE_ID)
3213 ? DEFAULT_TAB_BAR_BUTTON_RELIEF 3197 thick = (tab_bar_button_relief < 0
3214 : (tool_bar_button_relief < 0 3198 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
3215 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF 3199 : min (tab_bar_button_relief, 1000000));
3216 : min (tool_bar_button_relief, 1000000))); 3200 else
3201 thick = (tool_bar_button_relief < 0
3202 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
3203 : min (tool_bar_button_relief, 1000000));
3217 raised_p = s->hl == DRAW_IMAGE_RAISED; 3204 raised_p = s->hl == DRAW_IMAGE_RAISED;
3218 } 3205 }
3219 else 3206 else
@@ -3232,11 +3219,11 @@ x_draw_image_relief (struct glyph_string *s)
3232 && FIXNUMP (XCAR (Vtab_bar_button_margin)) 3219 && FIXNUMP (XCAR (Vtab_bar_button_margin))
3233 && FIXNUMP (XCDR (Vtab_bar_button_margin))) 3220 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
3234 { 3221 {
3235 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)); 3222 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
3236 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)); 3223 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
3237 } 3224 }
3238 else if (FIXNUMP (Vtab_bar_button_margin)) 3225 else if (FIXNUMP (Vtab_bar_button_margin))
3239 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin); 3226 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
3240 } 3227 }
3241 3228
3242 if (s->face->id == TOOL_BAR_FACE_ID) 3229 if (s->face->id == TOOL_BAR_FACE_ID)
@@ -3585,29 +3572,15 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
3585 else if (!s->background_filled_p) 3572 else if (!s->background_filled_p)
3586 { 3573 {
3587 int background_width = s->background_width; 3574 int background_width = s->background_width;
3588 int x = s->x, text_left_x = window_box_left_offset (s->w, TEXT_AREA); 3575 int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
3589 3576
3590 /* Don't draw into left fringe or scrollbar area except for 3577 /* Don't draw into left fringe or scrollbar area except for
3591 header line and mode line. */ 3578 header line and mode line. */
3592 if (x < text_left_x && !s->row->mode_line_p) 3579 if (s->area == TEXT_AREA
3580 && x < text_left_x && !s->row->mode_line_p)
3593 { 3581 {
3594 int left_x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w); 3582 background_width -= text_left_x - x;
3595 int right_x = text_left_x; 3583 x = text_left_x;
3596
3597 if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w))
3598 left_x += WINDOW_LEFT_FRINGE_WIDTH (s->w);
3599 else
3600 right_x -= WINDOW_LEFT_FRINGE_WIDTH (s->w);
3601
3602 /* Adjust X and BACKGROUND_WIDTH to fit inside the space
3603 between LEFT_X and RIGHT_X. */
3604 if (x < left_x)
3605 {
3606 background_width -= left_x - x;
3607 x = left_x;
3608 }
3609 if (x + background_width > right_x)
3610 background_width = right_x - x;
3611 } 3584 }
3612 if (background_width > 0) 3585 if (background_width > 0)
3613 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height); 3586 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
@@ -4060,7 +4033,7 @@ x_delete_glyphs (struct frame *f, int n)
4060/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable. 4033/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
4061 If they are <= 0, this is probably an error. */ 4034 If they are <= 0, this is probably an error. */
4062 4035
4063static ATTRIBUTE_UNUSED void 4036MAYBE_UNUSED static void
4064x_clear_area1 (Display *dpy, Window window, 4037x_clear_area1 (Display *dpy, Window window,
4065 int x, int y, int width, int height, int exposures) 4038 int x, int y, int width, int height, int exposures)
4066{ 4039{
@@ -4153,6 +4126,8 @@ x_show_hourglass (struct frame *f)
4153 4126
4154 XMapRaised (dpy, x->hourglass_window); 4127 XMapRaised (dpy, x->hourglass_window);
4155 XFlush (dpy); 4128 XFlush (dpy);
4129 /* Ensure that the spinning hourglass is shown. */
4130 flush_frame (f);
4156 } 4131 }
4157 } 4132 }
4158} 4133}
@@ -4416,6 +4391,99 @@ x_scroll_run (struct window *w, struct run *run)
4416 /* Cursor off. Will be switched on again in gui_update_window_end. */ 4391 /* Cursor off. Will be switched on again in gui_update_window_end. */
4417 gui_clear_cursor (w); 4392 gui_clear_cursor (w);
4418 4393
4394#ifdef HAVE_XWIDGETS
4395 /* "Copy" xwidget windows in the area that will be scrolled. */
4396 Display *dpy = FRAME_X_DISPLAY (f);
4397 Window window = FRAME_X_WINDOW (f);
4398
4399 Window root, parent, *children;
4400 unsigned int nchildren;
4401
4402 if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren))
4403 {
4404 /* Now find xwidget views situated between from_y and to_y, and
4405 attached to w. */
4406 for (unsigned int i = 0; i < nchildren; ++i)
4407 {
4408 Window child = children[i];
4409 struct xwidget_view *view = xwidget_view_from_window (child);
4410
4411 if (view && !view->hidden)
4412 {
4413 int window_y = view->y + view->clip_top;
4414 int window_height = view->clip_bottom - view->clip_top;
4415
4416 Emacs_Rectangle r1, r2, result;
4417 r1.x = w->pixel_left;
4418 r1.y = from_y;
4419 r1.width = w->pixel_width;
4420 r1.height = height;
4421 r2 = r1;
4422 r2.y = window_y;
4423 r2.height = window_height;
4424
4425 /* The window is offscreen, just unmap it. */
4426 if (window_height == 0)
4427 {
4428 view->hidden = true;
4429 XUnmapWindow (dpy, child);
4430 continue;
4431 }
4432
4433 bool intersects_p =
4434 gui_intersect_rectangles (&r1, &r2, &result);
4435
4436 if (XWINDOW (view->w) == w && intersects_p)
4437 {
4438 int y = view->y + (to_y - from_y);
4439 int text_area_x, text_area_y, text_area_width, text_area_height;
4440 int clip_top, clip_bottom;
4441
4442 window_box (w, TEXT_AREA, &text_area_x, &text_area_y,
4443 &text_area_width, &text_area_height);
4444
4445 view->y = y;
4446
4447 clip_top = 0;
4448 clip_bottom = XXWIDGET (view->model)->height;
4449
4450 if (y < text_area_y)
4451 clip_top = text_area_y - y;
4452
4453 if ((y + clip_bottom) > (text_area_y + text_area_height))
4454 {
4455 clip_bottom -= (y + clip_bottom) - (text_area_y + text_area_height);
4456 }
4457
4458 view->clip_top = clip_top;
4459 view->clip_bottom = clip_bottom;
4460
4461 /* This means the view has moved offscreen. Unmap
4462 it and hide it here. */
4463 if ((view->clip_bottom - view->clip_top) <= 0)
4464 {
4465 view->hidden = true;
4466 XUnmapWindow (dpy, child);
4467 }
4468 else
4469 {
4470 XMoveResizeWindow (dpy, child, view->x + view->clip_left,
4471 view->y + view->clip_top,
4472 view->clip_right - view->clip_left,
4473 view->clip_bottom - view->clip_top);
4474 cairo_xlib_surface_set_size (view->cr_surface,
4475 view->clip_right - view->clip_left,
4476 view->clip_bottom - view->clip_top);
4477 }
4478 xwidget_expose (view);
4479 XFlush (dpy);
4480 }
4481 }
4482 }
4483 XFree (children);
4484 }
4485#endif
4486
4419#ifdef USE_CAIRO 4487#ifdef USE_CAIRO
4420 if (FRAME_CR_CONTEXT (f)) 4488 if (FRAME_CR_CONTEXT (f))
4421 { 4489 {
@@ -4589,8 +4657,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra
4589 } 4657 }
4590} 4658}
4591 4659
4592/* Return the Emacs frame-object corresponding to an X window. 4660/* Return the Emacs frame-object corresponding to an X window. It
4593 It could be the frame's main window or an icon window. */ 4661 could be the frame's main window, an icon window, or an xwidget
4662 window. */
4594 4663
4595static struct frame * 4664static struct frame *
4596x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) 4665x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
@@ -4601,6 +4670,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4601 if (wdesc == None) 4670 if (wdesc == None)
4602 return NULL; 4671 return NULL;
4603 4672
4673#ifdef HAVE_XWIDGETS
4674 struct xwidget_view *xvw = xwidget_view_from_window (wdesc);
4675
4676 if (xvw && xvw->frame)
4677 return xvw->frame;
4678#endif
4679
4604 FOR_EACH_FRAME (tail, frame) 4680 FOR_EACH_FRAME (tail, frame)
4605 { 4681 {
4606 f = XFRAME (frame); 4682 f = XFRAME (frame);
@@ -5023,7 +5099,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
5023 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); 5099 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
5024} 5100}
5025 5101
5026static int 5102int
5027x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) 5103x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state)
5028{ 5104{
5029 EMACS_INT mod_ctrl = ctrl_modifier; 5105 EMACS_INT mod_ctrl = ctrl_modifier;
@@ -8237,6 +8313,18 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8237 8313
8238 case Expose: 8314 case Expose:
8239 f = x_window_to_frame (dpyinfo, event->xexpose.window); 8315 f = x_window_to_frame (dpyinfo, event->xexpose.window);
8316#ifdef HAVE_XWIDGETS
8317 {
8318 struct xwidget_view *xv =
8319 xwidget_view_from_window (event->xexpose.window);
8320
8321 if (xv)
8322 {
8323 xwidget_expose (xv);
8324 goto OTHER;
8325 }
8326 }
8327#endif
8240 if (f) 8328 if (f)
8241 { 8329 {
8242 if (!FRAME_VISIBLE_P (f)) 8330 if (!FRAME_VISIBLE_P (f))
@@ -8817,6 +8905,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8817 x_display_set_last_user_time (dpyinfo, event->xcrossing.time); 8905 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8818 x_detect_focus_change (dpyinfo, any, event, &inev.ie); 8906 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8819 8907
8908#ifdef HAVE_XWIDGETS
8909 {
8910 struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window);
8911 Mouse_HLInfo *hlinfo;
8912
8913 if (xvw)
8914 {
8915 xwidget_motion_or_crossing (xvw, event);
8916 hlinfo = MOUSE_HL_INFO (xvw->frame);
8917
8918 if (xvw->frame == hlinfo->mouse_face_mouse_frame)
8919 {
8920 clear_mouse_face (hlinfo);
8921 hlinfo->mouse_face_mouse_frame = 0;
8922 }
8923
8924 if (any_help_event_p)
8925 {
8926 do_help = -1;
8927 }
8928 goto OTHER;
8929 }
8930 }
8931#endif
8932
8820 f = any; 8933 f = any;
8821 8934
8822 if (f && x_mouse_click_focus_ignore_position) 8935 if (f && x_mouse_click_focus_ignore_position)
@@ -8860,6 +8973,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8860 goto OTHER; 8973 goto OTHER;
8861 8974
8862 case LeaveNotify: 8975 case LeaveNotify:
8976#ifdef HAVE_XWIDGETS
8977 {
8978 struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window);
8979
8980 if (xvw)
8981 {
8982 xwidget_motion_or_crossing (xvw, event);
8983 goto OTHER;
8984 }
8985 }
8986#endif
8863 x_display_set_last_user_time (dpyinfo, event->xcrossing.time); 8987 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8864 x_detect_focus_change (dpyinfo, any, event, &inev.ie); 8988 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8865 8989
@@ -8910,6 +9034,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8910 if (f && xg_event_is_for_scrollbar (f, event)) 9034 if (f && xg_event_is_for_scrollbar (f, event))
8911 f = 0; 9035 f = 0;
8912#endif 9036#endif
9037#ifdef HAVE_XWIDGETS
9038 struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window);
9039
9040 if (xvw)
9041 xwidget_motion_or_crossing (xvw, event);
9042#endif
8913 if (f) 9043 if (f)
8914 { 9044 {
8915 /* Maybe generate a SELECT_WINDOW_EVENT for 9045 /* Maybe generate a SELECT_WINDOW_EVENT for
@@ -9164,8 +9294,27 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9164 case ButtonRelease: 9294 case ButtonRelease:
9165 case ButtonPress: 9295 case ButtonPress:
9166 { 9296 {
9297#ifdef HAVE_XWIDGETS
9298 struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window);
9299
9300 if (xvw)
9301 {
9302 xwidget_button (xvw, event->type == ButtonPress,
9303 event->xbutton.x, event->xbutton.y,
9304 event->xbutton.button, event->xbutton.state,
9305 event->xbutton.time);
9306
9307 if (!EQ (selected_window, xvw->w))
9308 {
9309 inev.ie.kind = SELECT_WINDOW_EVENT;
9310 inev.ie.frame_or_window = xvw->w;
9311 }
9312 goto OTHER;
9313 }
9314#endif
9167 /* If we decide we want to generate an event to be seen 9315 /* If we decide we want to generate an event to be seen
9168 by the rest of Emacs, we put it here. */ 9316 by the rest of Emacs, we put it here. */
9317 Lisp_Object tab_bar_arg = Qnil;
9169 bool tab_bar_p = false; 9318 bool tab_bar_p = false;
9170 bool tool_bar_p = false; 9319 bool tool_bar_p = false;
9171 9320
@@ -9214,8 +9363,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9214 window = window_from_coordinates (f, x, y, 0, true, true); 9363 window = window_from_coordinates (f, x, y, 0, true, true);
9215 tab_bar_p = EQ (window, f->tab_bar_window); 9364 tab_bar_p = EQ (window, f->tab_bar_window);
9216 9365
9217 if (tab_bar_p && event->xbutton.button < 4) 9366 if (tab_bar_p)
9218 handle_tab_bar_click 9367 tab_bar_arg = handle_tab_bar_click
9219 (f, x, y, event->xbutton.type == ButtonPress, 9368 (f, x, y, event->xbutton.type == ButtonPress,
9220 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state)); 9369 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
9221 } 9370 }
@@ -9239,7 +9388,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9239 } 9388 }
9240#endif /* !USE_GTK */ 9389#endif /* !USE_GTK */
9241 9390
9242 if (!tab_bar_p && !tool_bar_p) 9391 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
9243#if defined (USE_X_TOOLKIT) || defined (USE_GTK) 9392#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
9244 if (! popup_activated ()) 9393 if (! popup_activated ())
9245#endif 9394#endif
@@ -9257,6 +9406,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9257 } 9406 }
9258 else 9407 else
9259 x_construct_mouse_click (&inev.ie, &event->xbutton, f); 9408 x_construct_mouse_click (&inev.ie, &event->xbutton, f);
9409
9410 if (!NILP (tab_bar_arg))
9411 inev.ie.arg = tab_bar_arg;
9260 } 9412 }
9261 if (FRAME_X_EMBEDDED_P (f)) 9413 if (FRAME_X_EMBEDDED_P (f))
9262 xembed_send_message (f, event->xbutton.time, 9414 xembed_send_message (f, event->xbutton.time,
@@ -10140,8 +10292,9 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
10140 frame on it. */ 10292 frame on it. */
10141 dpyinfo->reference_count++; 10293 dpyinfo->reference_count++;
10142 dpyinfo->terminal->reference_count++; 10294 dpyinfo->terminal->reference_count++;
10295 if (ioerror)
10296 dpyinfo->display = 0;
10143 } 10297 }
10144 if (ioerror) dpyinfo->display = 0;
10145 10298
10146 /* First delete frames whose mini-buffers are on frames 10299 /* First delete frames whose mini-buffers are on frames
10147 that are on the dead display. */ 10300 that are on the dead display. */
@@ -12129,6 +12282,10 @@ x_free_frame_resources (struct frame *f)
12129 xfree (f->shell_position); 12282 xfree (f->shell_position);
12130#else /* !USE_X_TOOLKIT */ 12283#else /* !USE_X_TOOLKIT */
12131 12284
12285#ifdef HAVE_XWIDGETS
12286 kill_frame_xwidget_views (f);
12287#endif
12288
12132#ifdef USE_GTK 12289#ifdef USE_GTK
12133 xg_free_frame_widgets (f); 12290 xg_free_frame_widgets (f);
12134#endif /* USE_GTK */ 12291#endif /* USE_GTK */
diff --git a/src/xterm.h b/src/xterm.h
index de6ea50385d..9d9534dd629 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1108,6 +1108,7 @@ extern void x_mouse_leave (struct x_display_info *);
1108extern int x_dispatch_event (XEvent *, Display *); 1108extern int x_dispatch_event (XEvent *, Display *);
1109#endif 1109#endif
1110extern int x_x_to_emacs_modifiers (struct x_display_info *, int); 1110extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
1111extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t);
1111#ifdef USE_CAIRO 1112#ifdef USE_CAIRO
1112extern void x_cr_destroy_frame_context (struct frame *); 1113extern void x_cr_destroy_frame_context (struct frame *);
1113extern void x_cr_update_surface_desired_size (struct frame *, int, int); 1114extern void x_cr_update_surface_desired_size (struct frame *, int, int);
diff --git a/src/xwidget.c b/src/xwidget.c
index ce55af8a4b4..6e2e8a9270e 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -19,6 +19,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20#include <config.h> 20#include <config.h>
21 21
22#include "buffer.h"
22#include "xwidget.h" 23#include "xwidget.h"
23 24
24#include "lisp.h" 25#include "lisp.h"
@@ -35,10 +36,27 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
35#ifdef USE_GTK 36#ifdef USE_GTK
36#include <webkit2/webkit2.h> 37#include <webkit2/webkit2.h>
37#include <JavaScriptCore/JavaScript.h> 38#include <JavaScriptCore/JavaScript.h>
39#include <cairo.h>
40#include <X11/Xlib.h>
38#elif defined NS_IMPL_COCOA 41#elif defined NS_IMPL_COCOA
39#include "nsxwidget.h" 42#include "nsxwidget.h"
40#endif 43#endif
41 44
45static Lisp_Object id_to_xwidget_map;
46static uint32_t xwidget_counter = 0;
47
48#ifdef USE_GTK
49static Lisp_Object x_window_to_xwv_map;
50static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
51static void synthesize_focus_in_event (GtkWidget *);
52static GdkDevice *find_suitable_keyboard (struct frame *);
53static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *,
54 gpointer);
55static void record_osr_embedder (struct xwidget_view *);
56static void from_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
57static void to_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
58#endif
59
42static struct xwidget * 60static struct xwidget *
43allocate_xwidget (void) 61allocate_xwidget (void)
44{ 62{
@@ -64,18 +82,32 @@ static void webkit_javascript_finished_cb (GObject *,
64 GAsyncResult *, 82 GAsyncResult *,
65 gpointer); 83 gpointer);
66static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); 84static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer);
67 85static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer);
68static gboolean 86static gboolean
69webkit_decide_policy_cb (WebKitWebView *, 87webkit_decide_policy_cb (WebKitWebView *,
70 WebKitPolicyDecision *, 88 WebKitPolicyDecision *,
71 WebKitPolicyDecisionType, 89 WebKitPolicyDecisionType,
72 gpointer); 90 gpointer);
91static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *);
92
93struct widget_search_data
94{
95 int x;
96 int y;
97 bool foundp;
98 bool first;
99 GtkWidget *data;
100};
101
102static void find_widget (GtkWidget *t, struct widget_search_data *);
103static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
104 gpointer);
73#endif 105#endif
74 106
75 107
76DEFUN ("make-xwidget", 108DEFUN ("make-xwidget",
77 Fmake_xwidget, Smake_xwidget, 109 Fmake_xwidget, Smake_xwidget,
78 5, 6, 0, 110 4, 7, 0,
79 doc: /* Make an xwidget of TYPE. 111 doc: /* Make an xwidget of TYPE.
80If BUFFER is nil, use the current buffer. 112If BUFFER is nil, use the current buffer.
81If BUFFER is a string and no such buffer exists, create it. 113If BUFFER is a string and no such buffer exists, create it.
@@ -83,10 +115,13 @@ TYPE is a symbol which can take one of the following values:
83 115
84- webkit 116- webkit
85 117
86Returns the newly constructed xwidget, or nil if construction fails. */) 118RELATED is nil, or an xwidget. When constructing a WebKit widget, it
119will share the same settings and internal subprocess as RELATED.
120Returns the newly constructed xwidget, or nil if construction
121fails. */)
87 (Lisp_Object type, 122 (Lisp_Object type,
88 Lisp_Object title, Lisp_Object width, Lisp_Object height, 123 Lisp_Object title, Lisp_Object width, Lisp_Object height,
89 Lisp_Object arguments, Lisp_Object buffer) 124 Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related)
90{ 125{
91#ifdef USE_GTK 126#ifdef USE_GTK
92 if (!xg_gtk_initialized) 127 if (!xg_gtk_initialized)
@@ -96,6 +131,9 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
96 CHECK_FIXNAT (width); 131 CHECK_FIXNAT (width);
97 CHECK_FIXNAT (height); 132 CHECK_FIXNAT (height);
98 133
134 if (!EQ (type, Qwebkit))
135 error ("Bad xwidget type");
136
99 struct xwidget *xw = allocate_xwidget (); 137 struct xwidget *xw = allocate_xwidget ();
100 Lisp_Object val; 138 Lisp_Object val;
101 xw->type = type; 139 xw->type = type;
@@ -108,13 +146,19 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
108 XSETXWIDGET (val, xw); 146 XSETXWIDGET (val, xw);
109 Vxwidget_list = Fcons (val, Vxwidget_list); 147 Vxwidget_list = Fcons (val, Vxwidget_list);
110 xw->plist = Qnil; 148 xw->plist = Qnil;
149 xw->xwidget_id = ++xwidget_counter;
150 xw->find_text = NULL;
151
152 Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map);
111 153
112#ifdef USE_GTK 154#ifdef USE_GTK
113 xw->widgetwindow_osr = NULL; 155 xw->widgetwindow_osr = NULL;
114 xw->widget_osr = NULL; 156 xw->widget_osr = NULL;
157 xw->hit_result = 0;
115 if (EQ (xw->type, Qwebkit)) 158 if (EQ (xw->type, Qwebkit))
116 { 159 {
117 block_input (); 160 block_input ();
161 WebKitSettings *settings;
118 WebKitWebContext *webkit_context = webkit_web_context_get_default (); 162 WebKitWebContext *webkit_context = webkit_web_context_get_default ();
119 163
120# if WEBKIT_CHECK_VERSION (2, 26, 0) 164# if WEBKIT_CHECK_VERSION (2, 26, 0)
@@ -132,18 +176,33 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
132 176
133 if (EQ (xw->type, Qwebkit)) 177 if (EQ (xw->type, Qwebkit))
134 { 178 {
135 xw->widget_osr = webkit_web_view_new (); 179 WebKitWebView *related_view;
136 180
137 /* webkitgtk uses GSubprocess which sets sigaction causing 181 if (NILP (related)
138 Emacs to not catch SIGCHLD with its usual handle setup in 182 || !XWIDGETP (related)
139 catch_child_signal(). This resets the SIGCHLD 183 || !EQ (XXWIDGET (related)->type, Qwebkit))
140 sigaction. */ 184 {
141 struct sigaction old_action; 185 xw->widget_osr = webkit_web_view_new ();
142 sigaction (SIGCHLD, NULL, &old_action); 186
143 webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr), 187 /* webkitgtk uses GSubprocess which sets sigaction causing
144 "about:blank"); 188 Emacs to not catch SIGCHLD with its usual handle setup in
145 sigaction (SIGCHLD, &old_action, NULL); 189 'catch_child_signal'. This resets the SIGCHLD sigaction. */
146 } 190 struct sigaction old_action;
191 sigaction (SIGCHLD, NULL, &old_action);
192 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
193 "about:blank");
194 sigaction (SIGCHLD, &old_action, NULL);
195 }
196 else
197 {
198 related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
199 xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
200 }
201
202 /* Enable the developer extras. */
203 settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
204 g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
205 }
147 206
148 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, 207 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
149 xw->height); 208 xw->height);
@@ -161,6 +220,13 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
161 220
162 gtk_widget_show (xw->widget_osr); 221 gtk_widget_show (xw->widget_osr);
163 gtk_widget_show (xw->widgetwindow_osr); 222 gtk_widget_show (xw->widgetwindow_osr);
223 synthesize_focus_in_event (xw->widgetwindow_osr);
224
225
226 g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
227 "from-embedder", G_CALLBACK (from_embedder), NULL);
228 g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
229 "to-embedder", G_CALLBACK (to_embedder), NULL);
164 230
165 /* Store some xwidget data in the gtk widgets for convenient 231 /* Store some xwidget data in the gtk widgets for convenient
166 retrieval in the event handlers. */ 232 retrieval in the event handlers. */
@@ -183,8 +249,24 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
183 G_CALLBACK 249 G_CALLBACK
184 (webkit_decide_policy_cb), 250 (webkit_decide_policy_cb),
185 xw); 251 xw);
252
253 g_signal_connect (G_OBJECT (xw->widget_osr),
254 "mouse-target-changed",
255 G_CALLBACK (mouse_target_changed),
256 xw);
257 g_signal_connect (G_OBJECT (xw->widget_osr),
258 "create",
259 G_CALLBACK (webkit_create_cb),
260 xw);
261 g_signal_connect (G_OBJECT (xw->widget_osr),
262 "script-dialog",
263 G_CALLBACK (webkit_script_dialog_cb),
264 NULL);
186 } 265 }
187 266
267 g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
268 G_CALLBACK (offscreen_damage_event), xw);
269
188 unblock_input (); 270 unblock_input ();
189 } 271 }
190#elif defined NS_IMPL_COCOA 272#elif defined NS_IMPL_COCOA
@@ -194,6 +276,156 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
194 return val; 276 return val;
195} 277}
196 278
279#ifdef USE_GTK
280static void
281set_widget_if_text_view (GtkWidget *widget, void *data)
282{
283 GtkWidget **pointer = data;
284
285 if (GTK_IS_TEXT_VIEW (widget))
286 *pointer = widget;
287}
288#endif
289
290DEFUN ("xwidget-perform-lispy-event",
291 Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event,
292 2, 3, 0, doc: /* Send a lispy event to XWIDGET.
293EVENT should be the event that will be sent. FRAME should be the
294frame which generated the event, and defaults to the selected frame.
295On X11, modifier keys will not be processed if FRAME is nil and the
296selected frame is not an X-Windows frame. */)
297 (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame)
298{
299 struct xwidget *xw;
300 struct frame *f = NULL;
301 int character = -1, keycode = -1;
302 int modifiers = 0;
303
304#ifdef USE_GTK
305 GdkEvent *xg_event;
306 GtkContainerClass *klass;
307 GtkWidget *widget;
308 GtkWidget *temp = NULL;
309#endif
310
311 CHECK_XWIDGET (xwidget);
312 xw = XXWIDGET (xwidget);
313
314 if (!NILP (frame))
315 f = decode_window_system_frame (frame);
316 else if (FRAME_X_P (SELECTED_FRAME ()))
317 f = SELECTED_FRAME ();
318
319#ifdef USE_GTK
320 widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr));
321
322 if (!widget)
323 widget = xw->widget_osr;
324
325 if (RANGED_FIXNUMP (0, event, INT_MAX))
326 {
327 character = XFIXNUM (event);
328
329 if (character < 32)
330 modifiers |= ctrl_modifier;
331
332 modifiers |= character & meta_modifier;
333 modifiers |= character & hyper_modifier;
334 modifiers |= character & super_modifier;
335 modifiers |= character & shift_modifier;
336 modifiers |= character & ctrl_modifier;
337
338 character = character & ~(1 << 21);
339
340 if (character < 32)
341 character += '_';
342
343 if (f)
344 modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
345 else
346 modifiers = 0;
347 }
348 else if (SYMBOLP (event))
349 {
350 Lisp_Object decoded = parse_modifiers (event);
351 Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded));
352
353 int off = 0;
354 bool found = false;
355
356 while (off < 256)
357 {
358 if (lispy_function_keys[off]
359 && !strcmp (lispy_function_keys[off],
360 SSDATA (decoded_name)))
361 {
362 found = true;
363 break;
364 }
365 ++off;
366 }
367
368 if (f)
369 modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
370 XFIXNUM (XCAR (XCDR (decoded))));
371 else
372 modifiers = 0;
373
374 if (found)
375 keycode = off + 0xff00;
376 }
377
378 if (character == -1 && keycode == -1)
379 return Qnil;
380
381 block_input ();
382 xg_event = gdk_event_new (GDK_KEY_PRESS);
383 xg_event->any.window = gtk_widget_get_window (xw->widget_osr);
384 g_object_ref (xg_event->any.window);
385
386 if (character > -1)
387 keycode = gdk_unicode_to_keyval (character);
388
389 xg_event->key.keyval = keycode;
390 xg_event->key.state = modifiers;
391
392 if (keycode > -1)
393 {
394 /* WebKitGTK internals abuse follows. */
395 if (WEBKIT_IS_WEB_VIEW (widget))
396 {
397 /* WebKitGTK relies on an internal GtkTextView object to
398 "translate" keys such as backspace. We must find that
399 widget and activate its binding to this key if any. */
400 klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget));
401
402 klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE,
403 set_widget_if_text_view, &temp);
404
405 if (GTK_IS_WIDGET (temp))
406 {
407 if (!gtk_widget_get_realized (temp))
408 gtk_widget_realize (temp);
409
410 gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers);
411 }
412 }
413 }
414
415 if (f)
416 gdk_event_set_device (xg_event,
417 find_suitable_keyboard (SELECTED_FRAME ()));
418
419 gtk_main_do_event (xg_event);
420 xg_event->type = GDK_KEY_RELEASE;
421 gtk_main_do_event (xg_event);
422 gdk_event_free (xg_event);
423 unblock_input ();
424#endif
425
426 return Qnil;
427}
428
197DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 429DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
198 1, 1, 0, 430 1, 1, 0,
199 doc: /* Return a list of xwidgets associated with BUFFER. 431 doc: /* Return a list of xwidgets associated with BUFFER.
@@ -225,16 +457,505 @@ xwidget_hidden (struct xwidget_view *xv)
225 return xv->hidden; 457 return xv->hidden;
226} 458}
227 459
460struct xwidget *
461xwidget_from_id (uint32_t id)
462{
463 Lisp_Object key = make_fixnum (id);
464 Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil);
465
466 if (NILP (xwidget))
467 emacs_abort ();
468
469 return XXWIDGET (xwidget);
470}
471
228#ifdef USE_GTK 472#ifdef USE_GTK
229static void 473static void
474record_osr_embedder (struct xwidget_view *view)
475{
476 struct xwidget *xw;
477 GdkWindow *window, *embedder;
478
479 xw = XXWIDGET (view->model);
480 window = gtk_widget_get_window (xw->widgetwindow_osr);
481 embedder = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (view->frame));
482
483 gdk_offscreen_window_set_embedder (window, embedder);
484 xw->embedder = view->frame;
485 xw->embedder_view = view;
486}
487
488static struct xwidget *
489find_xwidget_for_offscreen_window (GdkWindow *window)
490{
491 Lisp_Object tem;
492 struct xwidget *xw;
493 GdkWindow *w;
494
495 for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem))
496 {
497 if (XWIDGETP (XCAR (tem)))
498 {
499 xw = XXWIDGET (XCAR (tem));
500 w = gtk_widget_get_window (xw->widgetwindow_osr);
501
502 if (w == window)
503 return xw;
504 }
505 }
506
507 return NULL;
508}
509
510static void
511from_embedder (GdkWindow *window, double x, double y,
512 gpointer x_out_ptr, gpointer y_out_ptr,
513 gpointer user_data)
514{
515 double *xout = x_out_ptr;
516 double *yout = y_out_ptr;
517 struct xwidget *xw = find_xwidget_for_offscreen_window (window);
518 struct xwidget_view *xvw;
519 gint xoff, yoff;
520
521 if (!xw)
522 emacs_abort ();
523
524 xvw = xw->embedder_view;
525
526 if (!xvw)
527 {
528 *xout = x;
529 *yout = y;
530 }
531 else
532 {
533 gtk_widget_translate_coordinates (FRAME_GTK_WIDGET (xvw->frame),
534 FRAME_GTK_OUTER_WIDGET (xvw->frame),
535 0, 0, &xoff, &yoff);
536
537 *xout = x - xvw->x - xoff;
538 *yout = y - xvw->y - yoff;
539 }
540}
541
542static void
543to_embedder (GdkWindow *window, double x, double y,
544 gpointer x_out_ptr, gpointer y_out_ptr,
545 gpointer user_data)
546{
547 double *xout = x_out_ptr;
548 double *yout = y_out_ptr;
549 struct xwidget *xw = find_xwidget_for_offscreen_window (window);
550 struct xwidget_view *xvw;
551 gint xoff, yoff;
552
553 if (!xw)
554 emacs_abort ();
555
556 xvw = xw->embedder_view;
557
558 if (!xvw)
559 {
560 *xout = x;
561 *yout = y;
562 }
563 else
564 {
565 gtk_widget_translate_coordinates (FRAME_GTK_WIDGET (xvw->frame),
566 FRAME_GTK_OUTER_WIDGET (xvw->frame),
567 0, 0, &xoff, &yoff);
568
569 *xout = x + xvw->x + xoff;
570 *yout = y + xvw->y + yoff;
571 }
572}
573
574static GdkDevice *
575find_suitable_pointer (struct frame *f)
576{
577 GdkSeat *seat = gdk_display_get_default_seat
578 (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
579
580 if (!seat)
581 return NULL;
582
583 return gdk_seat_get_pointer (seat);
584}
585
586static GdkDevice *
587find_suitable_keyboard (struct frame *f)
588{
589 GdkSeat *seat = gdk_display_get_default_seat
590 (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
591
592 if (!seat)
593 return NULL;
594
595 return gdk_seat_get_keyboard (seat);
596}
597
598static void
599find_widget_cb (GtkWidget *widget, void *user)
600{
601 find_widget (widget, user);
602}
603
604static void
605find_widget (GtkWidget *widget,
606 struct widget_search_data *data)
607{
608 GtkAllocation new_allocation;
609 GdkWindow *window;
610 int x_offset = 0;
611 int y_offset = 0;
612
613 gtk_widget_get_allocation (widget, &new_allocation);
614
615 if (gtk_widget_get_has_window (widget))
616 {
617 new_allocation.x = 0;
618 new_allocation.y = 0;
619 }
620
621 if (gtk_widget_get_parent (widget) && !data->first)
622 {
623 window = gtk_widget_get_window (widget);
624 while (window != gtk_widget_get_window (gtk_widget_get_parent (widget)))
625 {
626 gint tx, ty, twidth, theight;
627
628 if (!window)
629 return;
630
631 twidth = gdk_window_get_width (window);
632 theight = gdk_window_get_height (window);
633
634 if (new_allocation.x < 0)
635 {
636 new_allocation.width += new_allocation.x;
637 new_allocation.x = 0;
638 }
639
640 if (new_allocation.y < 0)
641 {
642 new_allocation.height += new_allocation.y;
643 new_allocation.y = 0;
644 }
645
646 if (new_allocation.x + new_allocation.width > twidth)
647 new_allocation.width = twidth - new_allocation.x;
648 if (new_allocation.y + new_allocation.height > theight)
649 new_allocation.height = theight - new_allocation.y;
650
651 gdk_window_get_position (window, &tx, &ty);
652 new_allocation.x += tx;
653 x_offset += tx;
654 new_allocation.y += ty;
655 y_offset += ty;
656
657 window = gdk_window_get_parent (window);
658 }
659 }
660
661 if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
662 (data->x < new_allocation.x + new_allocation.width) &&
663 (data->y < new_allocation.y + new_allocation.height))
664 {
665 /* First, check if the drag is in a valid drop site in one of
666 our children. */
667 if (GTK_IS_CONTAINER (widget))
668 {
669 struct widget_search_data new_data = *data;
670
671 new_data.x -= x_offset;
672 new_data.y -= y_offset;
673 new_data.foundp = false;
674 new_data.first = false;
675
676 gtk_container_forall (GTK_CONTAINER (widget),
677 find_widget_cb, &new_data);
678
679 data->foundp = new_data.foundp;
680 if (data->foundp)
681 data->data = new_data.data;
682 }
683
684 /* If not, and this widget is registered as a drop site, check
685 to emit "drag_motion" to check if we are actually in a drop
686 site. */
687 if (!data->foundp)
688 {
689 data->foundp = true;
690 data->data = widget;
691 }
692 }
693}
694
695static GtkWidget *
696find_widget_at_pos (GtkWidget *w, int x, int y,
697 int *new_x, int *new_y)
698{
699 struct widget_search_data data;
700
701 data.x = x;
702 data.y = y;
703 data.foundp = false;
704 data.first = true;
705
706 find_widget (w, &data);
707
708 if (data.foundp)
709 {
710 gtk_widget_translate_coordinates (w, data.data, x,
711 y, new_x, new_y);
712 return data.data;
713 }
714
715 *new_x = x;
716 *new_y = y;
717
718 return NULL;
719}
720
721static Emacs_Cursor
722cursor_for_hit (guint result, struct frame *frame)
723{
724 Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor;
725
726 if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
727 || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)
728 || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
729 cursor = FRAME_X_OUTPUT (frame)->text_cursor;
730
731 if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR)
732 cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor;
733
734 if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
735 cursor = FRAME_X_OUTPUT (frame)->hand_cursor;
736
737 return cursor;
738}
739
740static void
741define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
742{
743 struct xwidget_view *xvw;
744
745 xw->hit_result = webkit_hit_test_result_get_context (res);
746
747 for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem);
748 tem = XCDR (tem))
749 {
750 if (XWIDGET_VIEW_P (XCAR (tem)))
751 {
752 xvw = XXWIDGET_VIEW (XCAR (tem));
753
754 if (XXWIDGET (xvw->model) == xw)
755 {
756 xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame);
757 if (xvw->wdesc != None)
758 XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor);
759 }
760 }
761 }
762}
763
764static void
765mouse_target_changed (WebKitWebView *webview,
766 WebKitHitTestResult *hitresult,
767 guint modifiers, gpointer xw)
768{
769 define_cursors (xw, hitresult);
770}
771
772
773static void
774xwidget_button_1 (struct xwidget_view *view,
775 bool down_p, int x, int y, int button,
776 int modifier_state, Time time)
777{
778 GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
779 struct xwidget *model = XXWIDGET (view->model);
780 GtkWidget *target;
781
782 /* X and Y should be relative to the origin of view->wdesc. */
783 x += view->clip_left;
784 y += view->clip_top;
785
786 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
787
788 if (!target)
789 target = model->widget_osr;
790
791 xg_event->any.window = gtk_widget_get_window (target);
792 g_object_ref (xg_event->any.window); /* The window will be unrefed
793 later by gdk_event_free. */
794
795 xg_event->button.x = x;
796 xg_event->button.x_root = x;
797 xg_event->button.y = y;
798 xg_event->button.y_root = y;
799 xg_event->button.button = button;
800 xg_event->button.state = modifier_state;
801 xg_event->button.time = time;
802 xg_event->button.device = find_suitable_pointer (view->frame);
803
804 gtk_main_do_event (xg_event);
805 gdk_event_free (xg_event);
806}
807
808void
809xwidget_button (struct xwidget_view *view,
810 bool down_p, int x, int y, int button,
811 int modifier_state, Time time)
812{
813 record_osr_embedder (view);
814
815 if (button < 4 || button > 8)
816 xwidget_button_1 (view, down_p, x, y, button, modifier_state, time);
817 else
818 {
819 GdkEvent *xg_event = gdk_event_new (GDK_SCROLL);
820 struct xwidget *model = XXWIDGET (view->model);
821 GtkWidget *target;
822
823 x += view->clip_left;
824 y += view->clip_top;
825
826 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
827
828 if (!target)
829 target = model->widget_osr;
830
831 xg_event->any.window = gtk_widget_get_window (target);
832 g_object_ref (xg_event->any.window); /* The window will be unrefed
833 later by gdk_event_free. */
834 if (button == 4)
835 xg_event->scroll.direction = GDK_SCROLL_UP;
836 else if (button == 5)
837 xg_event->scroll.direction = GDK_SCROLL_DOWN;
838 else if (button == 6)
839 xg_event->scroll.direction = GDK_SCROLL_LEFT;
840 else
841 xg_event->scroll.direction = GDK_SCROLL_RIGHT;
842
843 xg_event->scroll.device = find_suitable_pointer (view->frame);
844
845 xg_event->scroll.x = x;
846 xg_event->scroll.x_root = x;
847 xg_event->scroll.y = y;
848 xg_event->scroll.y_root = y;
849 xg_event->scroll.state = modifier_state;
850 xg_event->scroll.time = time;
851
852 xg_event->scroll.delta_x = 0;
853 xg_event->scroll.delta_y = 0;
854
855 gtk_main_do_event (xg_event);
856 gdk_event_free (xg_event);
857 }
858}
859
860void
861xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
862{
863 GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify
864 ? GDK_MOTION_NOTIFY
865 : (event->type == LeaveNotify
866 ? GDK_LEAVE_NOTIFY
867 : GDK_ENTER_NOTIFY));
868 struct xwidget *model = XXWIDGET (view->model);
869 int x;
870 int y;
871 GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr,
872 (event->type == MotionNotify
873 ? event->xmotion.x + view->clip_left
874 : event->xcrossing.x + view->clip_left),
875 (event->type == MotionNotify
876 ? event->xmotion.y + view->clip_top
877 : event->xcrossing.y + view->clip_top),
878 &x, &y);
879
880 if (!target)
881 target = model->widget_osr;
882
883 record_osr_embedder (view);
884 xg_event->any.window = gtk_widget_get_window (target);
885 g_object_ref (xg_event->any.window); /* The window will be unrefed
886 later by gdk_event_free. */
887
888 if (event->type == MotionNotify)
889 {
890 xg_event->motion.x = x;
891 xg_event->motion.y = y;
892 xg_event->motion.x_root = event->xmotion.x_root;
893 xg_event->motion.y_root = event->xmotion.y_root;
894 xg_event->motion.time = event->xmotion.time;
895 xg_event->motion.state = event->xmotion.state;
896 xg_event->motion.device = find_suitable_pointer (view->frame);
897 }
898 else
899 {
900 xg_event->crossing.detail = min (5, event->xcrossing.detail);
901 xg_event->crossing.time = event->xcrossing.time;
902 xg_event->crossing.x = x;
903 xg_event->crossing.y = y;
904 xg_event->crossing.x_root = event->xcrossing.x_root;
905 xg_event->crossing.y_root = event->xcrossing.y_root;
906 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
907 }
908
909 gtk_main_do_event (xg_event);
910 gdk_event_free (xg_event);
911}
912
913static void
914synthesize_focus_in_event (GtkWidget *offscreen_window)
915{
916 GdkWindow *wnd;
917 GdkEvent *focus_event;
918
919 if (!gtk_widget_get_realized (offscreen_window))
920 gtk_widget_realize (offscreen_window);
921
922 wnd = gtk_widget_get_window (offscreen_window);
923
924 focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
925 focus_event->any.window = wnd;
926 focus_event->focus_change.in = TRUE;
927
928 if (FRAME_WINDOW_P (SELECTED_FRAME ()))
929 gdk_event_set_device (focus_event,
930 find_suitable_pointer (SELECTED_FRAME ()));
931
932 g_object_ref (wnd);
933
934 gtk_main_do_event (focus_event);
935 gdk_event_free (focus_event);
936}
937
938struct xwidget_view *
939xwidget_view_from_window (Window wdesc)
940{
941 Lisp_Object key = make_fixnum (wdesc);
942 Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil);
943
944 if (NILP (xwv))
945 return NULL;
946
947 return XXWIDGET_VIEW (xwv);
948}
949
950static void
230xwidget_show_view (struct xwidget_view *xv) 951xwidget_show_view (struct xwidget_view *xv)
231{ 952{
232 xv->hidden = false; 953 xv->hidden = false;
233 gtk_widget_show (xv->widgetwindow); 954 XMoveWindow (xv->dpy, xv->wdesc,
234 gtk_fixed_move (GTK_FIXED (xv->emacswindow), 955 xv->x + xv->clip_left,
235 xv->widgetwindow, 956 xv->y + xv->clip_top);
236 xv->x + xv->clip_left, 957 XMapWindow (xv->dpy, xv->wdesc);
237 xv->y + xv->clip_top); 958 XFlush (xv->dpy);
238} 959}
239 960
240/* Hide an xwidget view. */ 961/* Hide an xwidget view. */
@@ -242,28 +963,64 @@ static void
242xwidget_hide_view (struct xwidget_view *xv) 963xwidget_hide_view (struct xwidget_view *xv)
243{ 964{
244 xv->hidden = true; 965 xv->hidden = true;
245 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, 966 XUnmapWindow (xv->dpy, xv->wdesc);
246 10000, 10000); 967 XFlush (xv->dpy);
968}
969
970static void
971xv_do_draw (struct xwidget_view *xw, struct xwidget *w)
972{
973 GtkOffscreenWindow *wnd;
974 cairo_surface_t *surface;
975 block_input ();
976 wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
977 surface = gtk_offscreen_window_get_surface (wnd);
978
979 cairo_save (xw->cr_context);
980 if (surface)
981 {
982 cairo_translate (xw->cr_context, -xw->clip_left, -xw->clip_top);
983 cairo_set_source_surface (xw->cr_context, surface, 0, 0);
984 cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE);
985 cairo_paint (xw->cr_context);
986 }
987 cairo_restore (xw->cr_context);
988
989 unblock_input ();
247} 990}
248 991
249/* When the off-screen webkit master view changes this signal is called. 992/* When the off-screen webkit master view changes this signal is called.
250 It copies the bitmap from the off-screen instance. */ 993 It copies the bitmap from the off-screen instance. */
251static gboolean 994static gboolean
252offscreen_damage_event (GtkWidget *widget, GdkEvent *event, 995offscreen_damage_event (GtkWidget *widget, GdkEvent *event,
253 gpointer xv_widget) 996 gpointer xwidget)
254{ 997{
255 /* Queue a redraw of onscreen widget. 998 block_input ();
256 There is a guard against receiving an invalid widget, 999
257 which should only happen if we failed to remove the 1000 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
258 specific signal handler for the damage event. */ 1001 tail = XCDR (tail))
259 if (GTK_IS_WIDGET (xv_widget)) 1002 {
260 gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); 1003 if (XWIDGET_VIEW_P (XCAR (tail)))
261 else 1004 {
262 message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", 1005 struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail));
263 xv_widget); 1006
1007 if (view->wdesc && XXWIDGET (view->model) == xwidget)
1008 xv_do_draw (view, XXWIDGET (view->model));
1009 }
1010 }
1011
1012 unblock_input ();
264 1013
265 return FALSE; 1014 return FALSE;
266} 1015}
1016
1017void
1018xwidget_expose (struct xwidget_view *xv)
1019{
1020 struct xwidget *xw = XXWIDGET (xv->model);
1021
1022 xv_do_draw (xv, xw);
1023}
267#endif /* USE_GTK */ 1024#endif /* USE_GTK */
268 1025
269void 1026void
@@ -317,22 +1074,108 @@ store_xwidget_js_callback_event (struct xwidget *xw,
317 1074
318 1075
319#ifdef USE_GTK 1076#ifdef USE_GTK
1077static void
1078store_xwidget_display_event (struct xwidget *xw)
1079{
1080 struct input_event evt;
1081 Lisp_Object val;
1082
1083 XSETXWIDGET (val, xw);
1084 EVENT_INIT (evt);
1085 evt.kind = XWIDGET_DISPLAY_EVENT;
1086 evt.frame_or_window = Qnil;
1087 evt.arg = val;
1088 kbd_buffer_store_event (&evt);
1089}
1090
1091static void
1092webkit_ready_to_show (WebKitWebView *new_view,
1093 gpointer user_data)
1094{
1095 Lisp_Object tem;
1096 struct xwidget *xw;
1097
1098 for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem))
1099 {
1100 if (XWIDGETP (XCAR (tem)))
1101 {
1102 xw = XXWIDGET (XCAR (tem));
1103
1104 if (EQ (xw->type, Qwebkit)
1105 && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view)
1106 store_xwidget_display_event (xw);
1107 }
1108 }
1109}
1110
1111static GtkWidget *
1112webkit_create_cb_1 (WebKitWebView *webview,
1113 struct xwidget_view *xv)
1114{
1115 Lisp_Object related;
1116 Lisp_Object xwidget;
1117 GtkWidget *widget;
1118
1119 XSETXWIDGET (related, xv);
1120 xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
1121 make_fixnum (0), Qnil,
1122 build_string (" *detached xwidget buffer*"),
1123 related);
1124
1125 if (NILP (xwidget))
1126 return NULL;
1127
1128 widget = XXWIDGET (xwidget)->widget_osr;
1129
1130 g_signal_connect (G_OBJECT (widget), "ready-to-show",
1131 G_CALLBACK (webkit_ready_to_show), NULL);
1132
1133 return widget;
1134}
1135
1136static GtkWidget *
1137webkit_create_cb (WebKitWebView *webview,
1138 WebKitNavigationAction *nav_action,
1139 gpointer user_data)
1140{
1141 switch (webkit_navigation_action_get_navigation_type (nav_action))
1142 {
1143 case WEBKIT_NAVIGATION_TYPE_OTHER:
1144 return webkit_create_cb_1 (webview, user_data);
1145
1146 case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
1147 case WEBKIT_NAVIGATION_TYPE_RELOAD:
1148 case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
1149 case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
1150 case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
1151 default:
1152 return NULL;
1153 }
1154}
1155
320void 1156void
321webkit_view_load_changed_cb (WebKitWebView *webkitwebview, 1157webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
322 WebKitLoadEvent load_event, 1158 WebKitLoadEvent load_event,
323 gpointer data) 1159 gpointer data)
324{ 1160{
325 switch (load_event) { 1161 struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
326 case WEBKIT_LOAD_FINISHED: 1162 XG_XWIDGET);
1163
1164 switch (load_event)
327 { 1165 {
328 struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), 1166 case WEBKIT_LOAD_FINISHED:
329 XG_XWIDGET); 1167 store_xwidget_event_string (xw, "load-changed", "load-finished");
330 store_xwidget_event_string (xw, "load-changed", ""); 1168 break;
1169 case WEBKIT_LOAD_STARTED:
1170 store_xwidget_event_string (xw, "load-changed", "load-started");
1171 break;
1172 case WEBKIT_LOAD_REDIRECTED:
1173 store_xwidget_event_string (xw, "load-changed", "load-redirected");
1174 break;
1175 case WEBKIT_LOAD_COMMITTED:
1176 store_xwidget_event_string (xw, "load-changed", "load-committed");
331 break; 1177 break;
332 } 1178 }
333 default:
334 break;
335 }
336} 1179}
337 1180
338/* Recursively convert a JavaScript value to a Lisp value. */ 1181/* Recursively convert a JavaScript value to a Lisp value. */
@@ -483,6 +1326,33 @@ webkit_decide_policy_cb (WebKitWebView *webView,
483 break; 1326 break;
484 } 1327 }
485 case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION: 1328 case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
1329 {
1330 WebKitNavigationPolicyDecision *navigation_decision =
1331 WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1332 WebKitNavigationAction *navigation_action =
1333 webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
1334 WebKitURIRequest *request =
1335 webkit_navigation_action_get_request (navigation_action);
1336 WebKitWebView *newview;
1337 struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
1338 Lisp_Object val, new_xwidget;
1339
1340 XSETXWIDGET (val, xw);
1341
1342 new_xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
1343 make_fixnum (0), Qnil,
1344 build_string (" *detached xwidget buffer*"),
1345 val);
1346
1347 if (NILP (new_xwidget))
1348 return FALSE;
1349
1350 newview = WEBKIT_WEB_VIEW (XXWIDGET (new_xwidget)->widget_osr);
1351 webkit_web_view_load_request (newview, request);
1352
1353 store_xwidget_display_event (XXWIDGET (new_xwidget));
1354 return TRUE;
1355 }
486 case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: 1356 case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
487 { 1357 {
488 WebKitNavigationPolicyDecision *navigation_decision = 1358 WebKitNavigationPolicyDecision *navigation_decision =
@@ -503,58 +1373,75 @@ webkit_decide_policy_cb (WebKitWebView *webView,
503 } 1373 }
504} 1374}
505 1375
506
507/* For gtk3 offscreen rendered widgets. */
508static gboolean 1376static gboolean
509xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) 1377webkit_script_dialog_cb (WebKitWebView *webview,
1378 WebKitScriptDialog *script_dialog,
1379 gpointer user)
510{ 1380{
511 struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); 1381 struct frame *f = SELECTED_FRAME ();
512 struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), 1382 WebKitScriptDialogType type;
513 XG_XWIDGET_VIEW); 1383 GtkWidget *widget;
1384 GtkWidget *dialog;
1385 GtkWidget *entry;
1386 GtkWidget *content_area;
1387 GtkWidget *box;
1388 GtkWidget *label;
1389 const gchar *content;
1390 const gchar *message;
1391 gint result;
1392
1393 /* Return TRUE to prevent WebKit from showing the default script
1394 dialog in the offscreen window, which runs a nested main loop
1395 Emacs can't respond to, and as such can't pass X events to. */
1396 if (!FRAME_WINDOW_P (f))
1397 return TRUE;
1398
1399 type = webkit_script_dialog_get_dialog_type (script_dialog);;
1400 widget = FRAME_GTK_OUTER_WIDGET (f);
1401 content = webkit_script_dialog_get_message (script_dialog);
1402
1403 if (type == WEBKIT_SCRIPT_DIALOG_ALERT)
1404 dialog = gtk_dialog_new_with_buttons ("Alert", GTK_WINDOW (widget),
1405 GTK_DIALOG_MODAL,
1406 "Dismiss", 1, NULL);
1407 else
1408 dialog = gtk_dialog_new_with_buttons ("Question", GTK_WINDOW (widget),
1409 GTK_DIALOG_MODAL,
1410 "OK", 0, "Cancel", 1, NULL);
514 1411
515 cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); 1412 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
516 cairo_clip (cr); 1413 label = gtk_label_new (content);
1414 content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1415 gtk_container_add (GTK_CONTAINER (content_area), box);
517 1416
518#ifdef HAVE_PGTK 1417 gtk_widget_show (box);
519 gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr)); 1418 gtk_widget_show (label);
520#endif
521 1419
522 gtk_widget_draw (xw->widget_osr, cr); 1420 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
523 return FALSE;
524}
525 1421
526static gboolean 1422 if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
527xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, 1423 {
528 gpointer user_data) 1424 entry = gtk_entry_new ();
529{ 1425 message = webkit_script_dialog_prompt_get_default_text (script_dialog);
530 /* Copy events that arrive at the outer widget to the offscreen widget. */ 1426
531 struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); 1427 gtk_widget_show (entry);
532 GdkEvent *eventcopy = gdk_event_copy (event); 1428 gtk_entry_set_text (GTK_ENTRY (entry), message);
533 eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); 1429 gtk_box_pack_end (GTK_BOX (box), entry, TRUE, TRUE, 0);
1430 }
534 1431
535 /* TODO: This might leak events. They should be deallocated later, 1432 result = gtk_dialog_run (GTK_DIALOG (dialog));
536 perhaps in xwgir_event_cb. */
537 gtk_main_do_event (eventcopy);
538 1433
539#ifdef HAVE_PGTK 1434 if (type == WEBKIT_SCRIPT_DIALOG_CONFIRM
540 /* Pgtk code needs this event */ 1435 || type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM)
541 if (event->type == GDK_MOTION_NOTIFY) 1436 webkit_script_dialog_confirm_set_confirmed (script_dialog, result == 0);
542 return FALSE;
543#endif
544 /* Don't propagate this event further. */
545 return TRUE;
546}
547 1437
548static gboolean 1438 if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
549xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, 1439 webkit_script_dialog_prompt_set_text (script_dialog,
550 gpointer data) 1440 gtk_entry_get_text (GTK_ENTRY (entry)));
551{ 1441
552 struct xwidget_view *xv = data; 1442 gtk_widget_destroy (GTK_WIDGET (dialog));
553 struct xwidget *xww = XXWIDGET (xv->model); 1443
554 gdk_offscreen_window_set_embedder (gtk_widget_get_window 1444 return TRUE;
555 (xww->widgetwindow_osr),
556 gtk_widget_get_window (xv->widget));
557 return FALSE;
558} 1445}
559#endif /* USE_GTK */ 1446#endif /* USE_GTK */
560 1447
@@ -581,63 +1468,19 @@ xwidget_init_view (struct xwidget *xww,
581 XSETXWIDGET (xv->model, xww); 1468 XSETXWIDGET (xv->model, xww);
582 1469
583#ifdef USE_GTK 1470#ifdef USE_GTK
584 if (EQ (xww->type, Qwebkit)) 1471 xv->dpy = FRAME_X_DISPLAY (s->f);
585 {
586 xv->widget = gtk_drawing_area_new ();
587 /* Expose event handling. */
588 gtk_widget_set_app_paintable (xv->widget, TRUE);
589 gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
590
591 /* Draw the view on damage-event. */
592 g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
593 G_CALLBACK (offscreen_damage_event), xv->widget);
594 1472
595 if (EQ (xww->type, Qwebkit))
596 {
597 g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
598 G_CALLBACK (xwidget_osr_event_forward), NULL);
599 g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
600 G_CALLBACK (xwidget_osr_event_forward), NULL);
601 g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
602 G_CALLBACK (xwidget_osr_event_forward), NULL);
603 }
604 else
605 {
606 /* xwgir debug, orthogonal to forwarding. */
607 g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
608 G_CALLBACK (xwidget_osr_event_set_embedder), xv);
609 }
610 g_signal_connect (G_OBJECT (xv->widget), "draw",
611 G_CALLBACK (xwidget_osr_draw_cb), NULL);
612 }
613
614 /* Widget realization.
615
616 Make container widget first, and put the actual widget inside the
617 container later. Drawing should crop container window if necessary
618 to handle case where xwidget is partially obscured by other Emacs
619 windows. Other containers than gtk_fixed where explored, but
620 gtk_fixed had the most predictable behavior so far. */
621
622 xv->emacswindow = FRAME_GTK_WIDGET (s->f);
623 xv->widgetwindow = gtk_fixed_new ();
624 gtk_widget_set_has_window (xv->widgetwindow, TRUE);
625 gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
626
627 /* Store some xwidget data in the gtk widgets. */
628 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f);
629 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww);
630 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv);
631 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww);
632 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv);
633
634 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
635 xww->height);
636 gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
637 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
638 xv->x = x; 1473 xv->x = x;
639 xv->y = y; 1474 xv->y = y;
640 gtk_widget_show_all (xv->widgetwindow); 1475
1476 xv->clip_left = 0;
1477 xv->clip_right = xww->width;
1478 xv->clip_top = 0;
1479 xv->clip_bottom = xww->height;
1480
1481 xv->wdesc = None;
1482 xv->frame = s->f;
1483 xv->cursor = cursor_for_hit (xww->hit_result, s->f);
641#elif defined NS_IMPL_COCOA 1484#elif defined NS_IMPL_COCOA
642 nsxwidget_init_view (xv, xww, s, x, y); 1485 nsxwidget_init_view (xv, xww, s, x, y);
643 nsxwidget_resize_view(xv, xww->width, xww->height); 1486 nsxwidget_resize_view(xv, xww->width, xww->height);
@@ -694,19 +1537,6 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
694 window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, 1537 window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y,
695 &text_area_width, &text_area_height); 1538 &text_area_width, &text_area_height);
696 1539
697 /* Resize xwidget webkit if its container window size is changed in
698 some ways, for example, a buffer became hidden in small split
699 window, then it can appear front in merged whole window. */
700 if (EQ (xww->type, Qwebkit)
701 && (xww->width != text_area_width || xww->height != text_area_height))
702 {
703 Lisp_Object xwl;
704 XSETXWIDGET (xwl, xww);
705 Fxwidget_resize (xwl,
706 make_int (text_area_width),
707 make_int (text_area_height));
708 }
709
710 clip_left = max (0, text_area_x - x); 1540 clip_left = max (0, text_area_x - x);
711 clip_right = max (clip_left, 1541 clip_right = max (clip_left,
712 min (xww->width, text_area_x + text_area_width - x)); 1542 min (xww->width, text_area_x + text_area_width - x));
@@ -724,15 +1554,58 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
724 later. */ 1554 later. */
725 bool moved = (xv->x + xv->clip_left != x + clip_left 1555 bool moved = (xv->x + xv->clip_left != x + clip_left
726 || xv->y + xv->clip_top != y + clip_top); 1556 || xv->y + xv->clip_top != y + clip_top);
1557
1558#ifdef USE_GTK
1559 bool wdesc_was_none = xv->wdesc == None;
1560#endif
727 xv->x = x; 1561 xv->x = x;
728 xv->y = y; 1562 xv->y = y;
729 1563
1564#ifdef USE_GTK
1565 block_input ();
1566 if (xv->wdesc == None)
1567 {
1568 Lisp_Object xvw;
1569 XSETXWIDGET_VIEW (xvw, xv);
1570 XSetWindowAttributes a;
1571 a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask
1572 | PointerMotionMask | EnterWindowMask | LeaveWindowMask);
1573
1574 if (clip_right - clip_left <= 0
1575 || clip_bottom - clip_top <= 0)
1576 {
1577 unblock_input ();
1578 return;
1579 }
1580
1581 xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f),
1582 x + clip_left, y + clip_top,
1583 clip_right - clip_left,
1584 clip_bottom - clip_top, 0,
1585 CopyFromParent, CopyFromParent,
1586 CopyFromParent, CWEventMask, &a);
1587 XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
1588 xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
1589 xv->wdesc,
1590 FRAME_DISPLAY_INFO (s->f)->visual,
1591 clip_right - clip_left,
1592 clip_bottom - clip_top);
1593 xv->cr_context = cairo_create (xv->cr_surface);
1594 Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map);
1595
1596 moved = false;
1597 }
1598#endif
1599
730 /* Has it moved? */ 1600 /* Has it moved? */
731 if (moved) 1601 if (moved)
732 { 1602 {
733#ifdef USE_GTK 1603#ifdef USE_GTK
734 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), 1604 XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
735 xv->widgetwindow, x + clip_left, y + clip_top); 1605 clip_right - clip_left, clip_bottom - clip_top);
1606 XFlush (xv->dpy);
1607 cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
1608 clip_bottom - clip_top);
736#elif defined NS_IMPL_COCOA 1609#elif defined NS_IMPL_COCOA
737 nsxwidget_move_view (xv, x + clip_left, y + clip_top); 1610 nsxwidget_move_view (xv, x + clip_left, y + clip_top);
738#endif 1611#endif
@@ -748,10 +1621,23 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
748 || xv->clip_top != clip_top || xv->clip_left != clip_left) 1621 || xv->clip_top != clip_top || xv->clip_left != clip_left)
749 { 1622 {
750#ifdef USE_GTK 1623#ifdef USE_GTK
751 gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, 1624 if (!wdesc_was_none && !moved)
752 clip_bottom - clip_top); 1625 {
753 gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, 1626 if (clip_right - clip_left <= 0
754 -clip_top); 1627 || clip_bottom - clip_top <= 0)
1628 {
1629 XUnmapWindow (xv->dpy, xv->wdesc);
1630 xv->hidden = true;
1631 }
1632 else
1633 {
1634 XResizeWindow (xv->dpy, xv->wdesc, clip_right - clip_left,
1635 clip_bottom - clip_top);
1636 }
1637 XFlush (xv->dpy);
1638 cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
1639 clip_bottom - clip_top);
1640 }
755#elif defined NS_IMPL_COCOA 1641#elif defined NS_IMPL_COCOA
756 nsxwidget_resize_view (xv, clip_right - clip_left, 1642 nsxwidget_resize_view (xv, clip_right - clip_left,
757 clip_bottom - clip_top); 1643 clip_bottom - clip_top);
@@ -771,12 +1657,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
771 if (!xwidget_hidden (xv)) 1657 if (!xwidget_hidden (xv))
772 { 1658 {
773#ifdef USE_GTK 1659#ifdef USE_GTK
774 gtk_widget_queue_draw (xv->widgetwindow); 1660 gtk_widget_queue_draw (xww->widget_osr);
775 gtk_widget_queue_draw (xv->widget);
776#elif defined NS_IMPL_COCOA 1661#elif defined NS_IMPL_COCOA
777 nsxwidget_set_needsdisplay (xv); 1662 nsxwidget_set_needsdisplay (xv);
778#endif 1663#endif
779 } 1664 }
1665
1666#ifdef USE_GTK
1667 unblock_input ();
1668#endif
780} 1669}
781 1670
782static bool 1671static bool
@@ -852,21 +1741,32 @@ DEFUN ("xwidget-webkit-goto-uri",
852DEFUN ("xwidget-webkit-goto-history", 1741DEFUN ("xwidget-webkit-goto-history",
853 Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history, 1742 Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
854 2, 2, 0, 1743 2, 2, 0,
855 doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse history. */) 1744 doc: /* Make the XWIDGET webkit the REL-POSth element in load history.
1745
1746If REL-POS is 0, the widget will be just reload the current element in
1747history. If REL-POS is more or less than 0, the widget will load the
1748REL-POSth element around the current spot in the load history. */)
856 (Lisp_Object xwidget, Lisp_Object rel_pos) 1749 (Lisp_Object xwidget, Lisp_Object rel_pos)
857{ 1750{
858 WEBKIT_FN_INIT (); 1751 WEBKIT_FN_INIT ();
859 /* Should be one of -1, 0, 1 */ 1752 CHECK_FIXNUM (rel_pos);
860 if (XFIXNUM (rel_pos) < -1 || XFIXNUM (rel_pos) > 1)
861 args_out_of_range_3 (rel_pos, make_fixnum (-1), make_fixnum (1));
862 1753
863#ifdef USE_GTK 1754#ifdef USE_GTK
864 WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr); 1755 WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
865 switch (XFIXNAT (rel_pos)) 1756 WebKitBackForwardList *list;
1757 WebKitBackForwardListItem *it;
1758
1759 if (XFIXNUM (rel_pos) == 0)
1760 webkit_web_view_reload (wkwv);
1761 else
866 { 1762 {
867 case -1: webkit_web_view_go_back (wkwv); break; 1763 list = webkit_web_view_get_back_forward_list (wkwv);
868 case 0: webkit_web_view_reload (wkwv); break; 1764 it = webkit_back_forward_list_get_nth_item (list, XFIXNUM (rel_pos));
869 case 1: webkit_web_view_go_forward (wkwv); break; 1765
1766 if (!it)
1767 error ("There is no item at this index");
1768
1769 webkit_web_view_go_to_back_forward_list_item (wkwv, it);
870 } 1770 }
871#elif defined NS_IMPL_COCOA 1771#elif defined NS_IMPL_COCOA
872 nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos)); 1772 nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
@@ -974,12 +1874,10 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
974#ifndef HAVE_PGTK 1874#ifndef HAVE_PGTK
975 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width, 1875 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
976 xw->height); 1876 xw->height);
977#else
978 gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr));
979#endif
980 gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
981 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, 1877 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
982 xw->height); 1878 xw->height);
1879
1880 gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
983 } 1881 }
984#elif defined NS_IMPL_COCOA 1882#elif defined NS_IMPL_COCOA
985 nsxwidget_resize (xw); 1883 nsxwidget_resize (xw);
@@ -992,16 +1890,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
992 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); 1890 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
993 if (XXWIDGET (xv->model) == xw) 1891 if (XXWIDGET (xv->model) == xw)
994 { 1892 {
995#ifdef USE_GTK 1893 wset_redisplay (XWINDOW (xv->w));
996 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
997 xw->height);
998#elif defined NS_IMPL_COCOA
999 nsxwidget_resize_view(xv, xw->width, xw->height);
1000#endif
1001 } 1894 }
1002 } 1895 }
1003 } 1896 }
1004 1897
1898 redisplay ();
1899
1005 return Qnil; 1900 return Qnil;
1006} 1901}
1007 1902
@@ -1101,13 +1996,28 @@ DEFUN ("delete-xwidget-view",
1101 CHECK_XWIDGET_VIEW (xwidget_view); 1996 CHECK_XWIDGET_VIEW (xwidget_view);
1102 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); 1997 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1103#ifdef USE_GTK 1998#ifdef USE_GTK
1104 gtk_widget_destroy (xv->widgetwindow); 1999 struct xwidget *xw = XXWIDGET (xv->model);
1105 /* xv->model still has signals pointing to the view. There can be 2000 GdkWindow *w;
1106 several views. Find the matching signals and delete them all. */ 2001
1107 g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, 2002 if (xv->wdesc != None)
1108 G_SIGNAL_MATCH_DATA, 2003 {
1109 0, 0, 0, 0, 2004 block_input ();
1110 xv->widget); 2005 cairo_destroy (xv->cr_context);
2006 cairo_surface_destroy (xv->cr_surface);
2007 XDestroyWindow (xv->dpy, xv->wdesc);
2008 Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
2009 unblock_input ();
2010 }
2011
2012 if (xw->embedder_view == xv)
2013 {
2014 w = gtk_widget_get_window (xw->widgetwindow_osr);
2015
2016 XXWIDGET (xv->model)->embedder_view = NULL;
2017 XXWIDGET (xv->model)->embedder = NULL;
2018
2019 gdk_offscreen_window_set_embedder (w, NULL);
2020 }
1111#elif defined NS_IMPL_COCOA 2021#elif defined NS_IMPL_COCOA
1112 nsxwidget_delete_view (xv); 2022 nsxwidget_delete_view (xv);
1113#endif 2023#endif
@@ -1162,6 +2072,19 @@ DEFUN ("xwidget-buffer",
1162 return XXWIDGET (xwidget)->buffer; 2072 return XXWIDGET (xwidget)->buffer;
1163} 2073}
1164 2074
2075DEFUN ("set-xwidget-buffer",
2076 Fset_xwidget_buffer, Sset_xwidget_buffer,
2077 2, 2, 0,
2078 doc: /* Set XWIDGET's buffer to BUFFER. */)
2079 (Lisp_Object xwidget, Lisp_Object buffer)
2080{
2081 CHECK_XWIDGET (xwidget);
2082 CHECK_BUFFER (buffer);
2083
2084 XXWIDGET (xwidget)->buffer = buffer;
2085 return Qnil;
2086}
2087
1165DEFUN ("set-xwidget-plist", 2088DEFUN ("set-xwidget-plist",
1166 Fset_xwidget_plist, Sset_xwidget_plist, 2089 Fset_xwidget_plist, Sset_xwidget_plist,
1167 2, 2, 0, 2090 2, 2, 0,
@@ -1200,6 +2123,166 @@ DEFUN ("xwidget-query-on-exit-flag",
1200 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt); 2123 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1201} 2124}
1202 2125
2126DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
2127 2, 5, 0,
2128 doc: /* Begin an incremental search operation in an xwidget.
2129QUERY should be a string containing the text to search for. XWIDGET
2130should be a WebKit xwidget where the search will take place. When the
2131search operation is complete, callers should also call
2132`xwidget-webkit-finish-search' to complete the search operation.
2133
2134CASE-INSENSITIVE, when non-nil, will cause the search to ignore the
2135case of characters inside QUERY. BACKWARDS, when non-nil, will cause
2136the search to proceed towards the beginning of the widget's contents.
2137WRAP-AROUND, when nil, will cause the search to stop upon hitting the
2138end of the widget's contents.
2139
2140It is OK to call this function even when a search is already in
2141progress. In that case, the previous search query will be replaced
2142with QUERY. */)
2143 (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive,
2144 Lisp_Object backwards, Lisp_Object wrap_around)
2145{
2146#ifdef USE_GTK
2147 WebKitWebView *webview;
2148 WebKitFindController *controller;
2149 WebKitFindOptions opt;
2150 struct xwidget *xw;
2151 gchar *g_query;
2152#endif
2153
2154 CHECK_STRING (query);
2155 CHECK_XWIDGET (xwidget);
2156
2157#ifdef USE_GTK
2158 xw = XXWIDGET (xwidget);
2159 webview = WEBKIT_WEB_VIEW (xw->widget_osr);
2160 query = ENCODE_UTF_8 (query);
2161 opt = WEBKIT_FIND_OPTIONS_NONE;
2162 g_query = xstrdup (SSDATA (query));
2163
2164 if (!NILP (case_insensitive))
2165 opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
2166 if (!NILP (backwards))
2167 opt |= WEBKIT_FIND_OPTIONS_BACKWARDS;
2168 if (!NILP (wrap_around))
2169 opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
2170
2171 if (xw->find_text)
2172 xfree (xw->find_text);
2173 xw->find_text = g_query;
2174
2175 block_input ();
2176 controller = webkit_web_view_get_find_controller (webview);
2177 webkit_find_controller_search (controller, g_query, opt, G_MAXUINT);
2178 unblock_input ();
2179#endif
2180
2181 return Qnil;
2182}
2183
2184DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
2185 Sxwidget_webkit_next_result, 1, 1, 0,
2186 doc: /* Show the next result matching the current search query.
2187
2188XWIDGET should be an xwidget that currently has a search query.
2189Before calling this function, you should start a search operation
2190using `xwidget-webkit-search'. */)
2191 (Lisp_Object xwidget)
2192{
2193 struct xwidget *xw;
2194#ifdef USE_GTK
2195 WebKitWebView *webview;
2196 WebKitFindController *controller;
2197#endif
2198
2199 CHECK_XWIDGET (xwidget);
2200 xw = XXWIDGET (xwidget);
2201
2202 if (!xw->find_text)
2203 error ("Widget has no ongoing search operation");
2204
2205#ifdef USE_GTK
2206 block_input ();
2207 webview = WEBKIT_WEB_VIEW (xw->widget_osr);
2208 controller = webkit_web_view_get_find_controller (webview);
2209 webkit_find_controller_search_next (controller);
2210 unblock_input ();
2211#endif
2212
2213 return Qnil;
2214}
2215
2216DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
2217 Sxwidget_webkit_previous_result, 1, 1, 0,
2218 doc: /* Show the previous result matching the current search query.
2219
2220XWIDGET should be an xwidget that currently has a search query.
2221Before calling this function, you should start a search operation
2222using `xwidget-webkit-search'. */)
2223 (Lisp_Object xwidget)
2224{
2225 struct xwidget *xw;
2226#ifdef USE_GTK
2227 WebKitWebView *webview;
2228 WebKitFindController *controller;
2229#endif
2230
2231 CHECK_XWIDGET (xwidget);
2232 xw = XXWIDGET (xwidget);
2233
2234 if (!xw->find_text)
2235 error ("Widget has no ongoing search operation");
2236
2237#ifdef USE_GTK
2238 block_input ();
2239 webview = WEBKIT_WEB_VIEW (xw->widget_osr);
2240 controller = webkit_web_view_get_find_controller (webview);
2241 webkit_find_controller_search_previous (controller);
2242 unblock_input ();
2243#endif
2244
2245 return Qnil;
2246}
2247
2248DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
2249 Sxwidget_webkit_finish_search, 1, 1, 0,
2250 doc: /* Finish XWIDGET's search operation.
2251
2252XWIDGET should be an xwidget that currently has a search query.
2253Before calling this function, you should start a search operation
2254using `xwidget-webkit-search'. */)
2255 (Lisp_Object xwidget)
2256{
2257 struct xwidget *xw;
2258#ifdef USE_GTK
2259 WebKitWebView *webview;
2260 WebKitFindController *controller;
2261#endif
2262
2263 CHECK_XWIDGET (xwidget);
2264 xw = XXWIDGET (xwidget);
2265
2266 if (!xw->find_text)
2267 error ("Widget has no ongoing search operation");
2268
2269#ifdef USE_GTK
2270 block_input ();
2271 webview = WEBKIT_WEB_VIEW (xw->widget_osr);
2272 controller = webkit_web_view_get_find_controller (webview);
2273 webkit_find_controller_search_finish (controller);
2274
2275 if (xw->find_text)
2276 {
2277 xfree (xw->find_text);
2278 xw->find_text = NULL;
2279 }
2280 unblock_input ();
2281#endif
2282
2283 return Qnil;
2284}
2285
1203void 2286void
1204syms_of_xwidget (void) 2287syms_of_xwidget (void)
1205{ 2288{
@@ -1232,6 +2315,12 @@ syms_of_xwidget (void)
1232 defsubr (&Sxwidget_plist); 2315 defsubr (&Sxwidget_plist);
1233 defsubr (&Sxwidget_buffer); 2316 defsubr (&Sxwidget_buffer);
1234 defsubr (&Sset_xwidget_plist); 2317 defsubr (&Sset_xwidget_plist);
2318 defsubr (&Sxwidget_perform_lispy_event);
2319 defsubr (&Sxwidget_webkit_search);
2320 defsubr (&Sxwidget_webkit_finish_search);
2321 defsubr (&Sxwidget_webkit_next_result);
2322 defsubr (&Sxwidget_webkit_previous_result);
2323 defsubr (&Sset_xwidget_buffer);
1235 2324
1236 DEFSYM (QCxwidget, ":xwidget"); 2325 DEFSYM (QCxwidget, ":xwidget");
1237 DEFSYM (QCtitle, ":title"); 2326 DEFSYM (QCtitle, ":title");
@@ -1253,6 +2342,15 @@ syms_of_xwidget (void)
1253 Vxwidget_view_list = Qnil; 2342 Vxwidget_view_list = Qnil;
1254 2343
1255 Fprovide (intern ("xwidget-internal"), Qnil); 2344 Fprovide (intern ("xwidget-internal"), Qnil);
2345
2346 id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq);
2347 staticpro (&id_to_xwidget_map);
2348
2349#ifdef USE_GTK
2350 x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq);
2351
2352 staticpro (&x_window_to_xwv_map);
2353#endif
1256} 2354}
1257 2355
1258 2356
@@ -1391,7 +2489,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1391 /* The only call to xwidget_end_redisplay is in dispnew. 2489 /* The only call to xwidget_end_redisplay is in dispnew.
1392 xwidget_end_redisplay (w->current_matrix); */ 2490 xwidget_end_redisplay (w->current_matrix); */
1393 struct xwidget_view *xv 2491 struct xwidget_view *xv
1394 = xwidget_view_lookup (glyph->u.xwidget, w); 2492 = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w);
1395#ifdef USE_GTK 2493#ifdef USE_GTK
1396 /* FIXME: Is it safe to assume xwidget_view_lookup 2494 /* FIXME: Is it safe to assume xwidget_view_lookup
1397 always succeeds here? If so, this comment can be removed. 2495 always succeeds here? If so, this comment can be removed.
@@ -1441,6 +2539,25 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1441 } 2539 }
1442} 2540}
1443 2541
2542#ifdef USE_GTK
2543void
2544kill_frame_xwidget_views (struct frame *f)
2545{
2546 Lisp_Object rem = Qnil;
2547
2548 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
2549 tail = XCDR (tail))
2550 {
2551 if (XWIDGET_VIEW_P (XCAR (tail))
2552 && XXWIDGET_VIEW (XCAR (tail))->frame == f)
2553 rem = Fcons (XCAR (tail), rem);
2554 }
2555
2556 for (; CONSP (rem); rem = XCDR (rem))
2557 Fdelete_xwidget_view (XCAR (rem));
2558}
2559#endif
2560
1444/* Kill all xwidget in BUFFER. */ 2561/* Kill all xwidget in BUFFER. */
1445void 2562void
1446kill_buffer_xwidgets (Lisp_Object buffer) 2563kill_buffer_xwidgets (Lisp_Object buffer)
@@ -1454,12 +2571,15 @@ kill_buffer_xwidgets (Lisp_Object buffer)
1454 { 2571 {
1455 CHECK_XWIDGET (xwidget); 2572 CHECK_XWIDGET (xwidget);
1456 struct xwidget *xw = XXWIDGET (xwidget); 2573 struct xwidget *xw = XXWIDGET (xwidget);
2574 Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map);
1457#ifdef USE_GTK 2575#ifdef USE_GTK
1458 if (xw->widget_osr && xw->widgetwindow_osr) 2576 if (xw->widget_osr && xw->widgetwindow_osr)
1459 { 2577 {
1460 gtk_widget_destroy (xw->widget_osr); 2578 gtk_widget_destroy (xw->widget_osr);
1461 gtk_widget_destroy (xw->widgetwindow_osr); 2579 gtk_widget_destroy (xw->widgetwindow_osr);
1462 } 2580 }
2581 if (xw->find_text)
2582 xfree (xw->find_text);
1463 if (!NILP (xw->script_callbacks)) 2583 if (!NILP (xw->script_callbacks))
1464 for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++) 2584 for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++)
1465 { 2585 {
diff --git a/src/xwidget.h b/src/xwidget.h
index 591f23489db..6e6b39c8b4f 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -32,6 +32,8 @@ struct window;
32 32
33#if defined (USE_GTK) 33#if defined (USE_GTK)
34#include <gtk/gtk.h> 34#include <gtk/gtk.h>
35#include <X11/Xlib.h>
36#include "xterm.h"
35#elif defined (NS_IMPL_COCOA) && defined (__OBJC__) 37#elif defined (NS_IMPL_COCOA) && defined (__OBJC__)
36#import <AppKit/NSView.h> 38#import <AppKit/NSView.h>
37#import "nsxwidget.h" 39#import "nsxwidget.h"
@@ -59,11 +61,16 @@ struct xwidget
59 61
60 int height; 62 int height;
61 int width; 63 int width;
64 uint32_t xwidget_id;
65 char *find_text;
62 66
63#if defined (USE_GTK) 67#if defined (USE_GTK)
64 /* For offscreen widgets, unused if not osr. */ 68 /* For offscreen widgets, unused if not osr. */
65 GtkWidget *widget_osr; 69 GtkWidget *widget_osr;
66 GtkWidget *widgetwindow_osr; 70 GtkWidget *widgetwindow_osr;
71 struct frame *embedder;
72 struct xwidget_view *embedder_view;
73 guint hit_result;
67#elif defined (NS_IMPL_COCOA) 74#elif defined (NS_IMPL_COCOA)
68# ifdef __OBJC__ 75# ifdef __OBJC__
69 /* For offscreen widgets, unused if not osr. */ 76 /* For offscreen widgets, unused if not osr. */
@@ -98,9 +105,13 @@ struct xwidget_view
98 bool hidden; 105 bool hidden;
99 106
100#if defined (USE_GTK) 107#if defined (USE_GTK)
101 GtkWidget *widget; 108 Display *dpy;
102 GtkWidget *widgetwindow; 109 Window wdesc;
103 GtkWidget *emacswindow; 110 Emacs_Cursor cursor;
111 struct frame *frame;
112
113 cairo_surface_t *cr_surface;
114 cairo_t *cr_context;
104#elif defined (NS_IMPL_COCOA) 115#elif defined (NS_IMPL_COCOA)
105# ifdef __OBJC__ 116# ifdef __OBJC__
106 XvWindow *xvWindow; 117 XvWindow *xvWindow;
@@ -162,6 +173,18 @@ void store_xwidget_download_callback_event (struct xwidget *xw,
162void store_xwidget_js_callback_event (struct xwidget *xw, 173void store_xwidget_js_callback_event (struct xwidget *xw,
163 Lisp_Object proc, 174 Lisp_Object proc,
164 Lisp_Object argument); 175 Lisp_Object argument);
176
177extern struct xwidget *xwidget_from_id (uint32_t id);
178
179#ifdef HAVE_X_WINDOWS
180struct xwidget_view *xwidget_view_from_window (Window wdesc);
181void xwidget_expose (struct xwidget_view *xv);
182extern void kill_frame_xwidget_views (struct frame *f);
183extern void xwidget_button (struct xwidget_view *, bool, int,
184 int, int, int, Time);
185extern void xwidget_motion_or_crossing (struct xwidget_view *,
186 const XEvent *);
187#endif
165#else 188#else
166INLINE_HEADER_BEGIN 189INLINE_HEADER_BEGIN
167INLINE void syms_of_xwidget (void) {} 190INLINE void syms_of_xwidget (void) {}