diff options
| author | Yuuki Harano | 2021-11-11 00:39:53 +0900 |
|---|---|---|
| committer | Yuuki Harano | 2021-11-11 00:39:53 +0900 |
| commit | 4dd1f56f29fc598a8339a345c2f8945250600602 (patch) | |
| tree | af341efedffe027e533b1bcc0dbf270532e48285 /src | |
| parent | 4c49ec7f865bdad1629d2f125f71f4e506b258f2 (diff) | |
| parent | 810fa21d26453f898de9747ece7205dfe6de9d08 (diff) | |
| download | emacs-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.in | 79 | ||||
| -rw-r--r-- | src/alloc.c | 46 | ||||
| -rw-r--r-- | src/atimer.c | 42 | ||||
| -rw-r--r-- | src/bidi.c | 29 | ||||
| -rw-r--r-- | src/buffer.c | 83 | ||||
| -rw-r--r-- | src/buffer.h | 11 | ||||
| -rw-r--r-- | src/callint.c | 10 | ||||
| -rw-r--r-- | src/callproc.c | 2 | ||||
| -rw-r--r-- | src/casefiddle.c | 57 | ||||
| -rw-r--r-- | src/character.h | 2 | ||||
| -rw-r--r-- | src/cmds.c | 2 | ||||
| -rw-r--r-- | src/coding.c | 47 | ||||
| -rw-r--r-- | src/comp.c | 369 | ||||
| -rw-r--r-- | src/composite.c | 55 | ||||
| -rw-r--r-- | src/composite.h | 4 | ||||
| -rw-r--r-- | src/conf_post.h | 1 | ||||
| -rw-r--r-- | src/data.c | 4 | ||||
| -rw-r--r-- | src/dispextern.h | 18 | ||||
| -rw-r--r-- | src/dispnew.c | 21 | ||||
| -rw-r--r-- | src/editfns.c | 7 | ||||
| -rw-r--r-- | src/emacs-module.h.in | 13 | ||||
| -rw-r--r-- | src/emacs.c | 50 | ||||
| -rw-r--r-- | src/eval.c | 97 | ||||
| -rw-r--r-- | src/fileio.c | 8 | ||||
| -rw-r--r-- | src/fns.c | 24 | ||||
| -rw-r--r-- | src/font.c | 155 | ||||
| -rw-r--r-- | src/font.h | 2 | ||||
| -rw-r--r-- | src/fontset.c | 6 | ||||
| -rw-r--r-- | src/frame.c | 45 | ||||
| -rw-r--r-- | src/frame.h | 4 | ||||
| -rw-r--r-- | src/fringe.c | 10 | ||||
| -rw-r--r-- | src/gtkutil.c | 51 | ||||
| -rw-r--r-- | src/image.c | 466 | ||||
| -rw-r--r-- | src/insdel.c | 9 | ||||
| -rw-r--r-- | src/intervals.c | 20 | ||||
| -rw-r--r-- | src/keyboard.c | 303 | ||||
| -rw-r--r-- | src/keyboard.h | 2 | ||||
| -rw-r--r-- | src/keymap.c | 278 | ||||
| -rw-r--r-- | src/lisp.h | 76 | ||||
| -rw-r--r-- | src/lread.c | 187 | ||||
| -rw-r--r-- | src/macfont.m | 44 | ||||
| -rw-r--r-- | src/menu.c | 23 | ||||
| -rw-r--r-- | src/minibuf.c | 151 | ||||
| -rw-r--r-- | src/module-env-28.h | 4 | ||||
| -rw-r--r-- | src/module-env-29.h | 3 | ||||
| -rw-r--r-- | src/msdos.c | 2 | ||||
| -rw-r--r-- | src/nsfns.m | 80 | ||||
| -rw-r--r-- | src/nsfont.m | 1215 | ||||
| -rw-r--r-- | src/nsimage.m | 49 | ||||
| -rw-r--r-- | src/nsmenu.m | 122 | ||||
| -rw-r--r-- | src/nsterm.h | 102 | ||||
| -rw-r--r-- | src/nsterm.m | 1990 | ||||
| -rw-r--r-- | src/pdumper.c | 53 | ||||
| -rw-r--r-- | src/pdumper.h | 5 | ||||
| -rw-r--r-- | src/print.c | 30 | ||||
| -rw-r--r-- | src/process.c | 63 | ||||
| -rw-r--r-- | src/regex-emacs.c | 4 | ||||
| -rw-r--r-- | src/search.c | 101 | ||||
| -rw-r--r-- | src/syntax.c | 10 | ||||
| -rw-r--r-- | src/sysstdio.h | 2 | ||||
| -rw-r--r-- | src/systhread.h | 13 | ||||
| -rw-r--r-- | src/term.c | 35 | ||||
| -rw-r--r-- | src/termchar.h | 4 | ||||
| -rw-r--r-- | src/termhooks.h | 2 | ||||
| -rw-r--r-- | src/timefns.c | 5 | ||||
| -rw-r--r-- | src/unexcw.c | 6 | ||||
| -rw-r--r-- | src/verbose.mk.in | 4 | ||||
| -rw-r--r-- | src/vm-limit.c | 2 | ||||
| -rw-r--r-- | src/w16select.c | 2 | ||||
| -rw-r--r-- | src/w32.c | 69 | ||||
| -rw-r--r-- | src/w32.h | 9 | ||||
| -rw-r--r-- | src/w32fns.c | 148 | ||||
| -rw-r--r-- | src/w32font.c | 4 | ||||
| -rw-r--r-- | src/w32heap.c | 42 | ||||
| -rw-r--r-- | src/w32inevt.c | 6 | ||||
| -rw-r--r-- | src/w32proc.c | 10 | ||||
| -rw-r--r-- | src/w32term.c | 79 | ||||
| -rw-r--r-- | src/window.c | 68 | ||||
| -rw-r--r-- | src/xdisp.c | 604 | ||||
| -rw-r--r-- | src/xfaces.c | 24 | ||||
| -rw-r--r-- | src/xfns.c | 17 | ||||
| -rw-r--r-- | src/xmenu.c | 8 | ||||
| -rw-r--r-- | src/xterm.c | 259 | ||||
| -rw-r--r-- | src/xterm.h | 1 | ||||
| -rw-r--r-- | src/xwidget.c | 1492 | ||||
| -rw-r--r-- | src/xwidget.h | 29 |
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. |
| 56 | config_h = config.h $(srcdir)/conf_post.h | 56 | config_h = config.h $(srcdir)/conf_post.h |
| 57 | 57 | ||
| 58 | HAVE_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. |
| 59 | OTHER_FILES = @OTHER_FILES@ | 61 | OTHER_FILES = @OTHER_FILES@ |
| 60 | 62 | ||
| @@ -122,7 +124,7 @@ LIB_MATH=@LIB_MATH@ | |||
| 122 | ## -lpthread, or empty. | 124 | ## -lpthread, or empty. |
| 123 | LIB_PTHREAD=@LIB_PTHREAD@ | 125 | LIB_PTHREAD=@LIB_PTHREAD@ |
| 124 | 126 | ||
| 125 | LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ | 127 | LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@ |
| 126 | 128 | ||
| 127 | XCB_LIBS=@XCB_LIBS@ | 129 | XCB_LIBS=@XCB_LIBS@ |
| 128 | XFT_LIBS=@XFT_LIBS@ | 130 | XFT_LIBS=@XFT_LIBS@ |
| @@ -221,6 +223,8 @@ CFLAGS_SOUND= @CFLAGS_SOUND@ | |||
| 221 | RSVG_LIBS= @RSVG_LIBS@ | 223 | RSVG_LIBS= @RSVG_LIBS@ |
| 222 | RSVG_CFLAGS= @RSVG_CFLAGS@ | 224 | RSVG_CFLAGS= @RSVG_CFLAGS@ |
| 223 | 225 | ||
| 226 | WEBP_CFLAGS= @WEBP_CFLAGS@ | ||
| 227 | |||
| 224 | WEBKIT_LIBS= @WEBKIT_LIBS@ | 228 | WEBKIT_LIBS= @WEBKIT_LIBS@ |
| 225 | WEBKIT_CFLAGS= @WEBKIT_CFLAGS@ | 229 | WEBKIT_CFLAGS= @WEBKIT_CFLAGS@ |
| 226 | 230 | ||
| @@ -329,7 +333,8 @@ GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ | |||
| 329 | 333 | ||
| 330 | LIBGMP = @LIBGMP@ | 334 | LIBGMP = @LIBGMP@ |
| 331 | 335 | ||
| 332 | LIBGCCJIT = @LIBGCCJIT_LIB@ | 336 | LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@ |
| 337 | LIBGCCJIT_CFLAGS = @LIBGCCJIT_CFLAGS@ | ||
| 333 | 338 | ||
| 334 | ## dynlib.o if necessary, else empty | 339 | ## dynlib.o if necessary, else empty |
| 335 | DYNLIB_OBJ = @DYNLIB_OBJ@ | 340 | DYNLIB_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! |
| 453 | all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) | 458 | all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES) |
| 459 | ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:) | ||
| 460 | all: ../native-lisp | ||
| 461 | endif | ||
| 454 | .PHONY: all | 462 | .PHONY: all |
| 455 | 463 | ||
| 456 | dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \ | 464 | dmpstruct_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} | 558 | emoji-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 | |||
| 564 | SYSTEM_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} | |||
| 557 | emacs$(EXEEXT): temacs$(EXEEXT) \ | 571 | emacs$(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} |
| 574 | ifeq ($(SYSTEM_TYPE),cygwin) | ||
| 575 | find ${top_builddir} -name '*.eln' | rebase -v -O -T - | ||
| 576 | endif | ||
| 560 | ifeq ($(DUMPING),unexec) | 577 | ifeq ($(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. |
| 633 | temacs$(EXEEXT): $(LIBXMENU) $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ | 650 | temacs$(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 | ||
| 788 | ifeq ($(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). | ||
| 796 | elnlisp := \ | ||
| 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 | ||
| 805 | elnlisp := $(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 | ||
| 831 | endif | ||
| 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) | |||
| 793 | else | 855 | else |
| 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) |
| 858 | ifeq ($(DO_CODESIGN),yes) | ||
| 859 | codesign -s - -f bootstrap-emacs$(EXEEXT) | ||
| 860 | endif | ||
| 796 | endif | 861 | endif |
| 797 | 862 | ||
| 798 | ifeq ($(DUMPING),pdumper) | 863 | ifeq ($(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 | ||
| 1935 | unsigned char * | 1943 | unsigned char * |
| 1936 | resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte, | 1944 | resize_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__ |
| 7325 | DEFUN ("malloc-info", Fmalloc_info, Smalloc_info, 0, 0, "", | 7333 | DEFUN ("malloc-info", Fmalloc_info, Smalloc_info, 0, 0, "", |
| 7326 | doc: /* Report malloc information to stderr. | 7334 | doc: /* Report malloc information to stderr. |
| 7327 | This function outputs to stderr an XML-formatted | 7335 | This 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. */ | ||
| 3568 | ptrdiff_t | 3569 | ptrdiff_t |
| 3569 | bidi_find_first_overridden (struct bidi_it *bidi_it) | 3570 | bidi_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. */) | |||
| 1434 | DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p, | 1434 | DEFUN ("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. |
| 1437 | This function also locks and unlocks the file visited by the buffer, | 1437 | This function also locks or unlocks the file visited by the buffer, |
| 1438 | if both `buffer-file-truename' and `buffer-file-name' are non-nil. | 1438 | if both `buffer-file-truename' and `buffer-file-name' are non-nil. |
| 1439 | 1439 | ||
| 1440 | It is not ensured that mode lines will be updated to show the modified | 1440 | It 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 | ||
| 2804 | DEFUN ("kill-all-local-variables", Fkill_all_local_variables, | 2807 | DEFUN ("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. |
| 2807 | Most local variable bindings are eliminated so that the default values | 2810 | Most local variable bindings are eliminated so that the default values |
| 2808 | become effective once more. Also, the syntax table is set from | 2811 | become effective once more. Also, the syntax table is set from |
| @@ -2813,18 +2816,20 @@ This function also forces redisplay of the mode line. | |||
| 2813 | Every function to select a new major mode starts by | 2816 | Every function to select a new major mode starts by |
| 2814 | calling this function. | 2817 | calling this function. |
| 2815 | 2818 | ||
| 2816 | As a special exception, local variables whose names have | 2819 | As a special exception, local variables whose names have a non-nil |
| 2817 | a non-nil `permanent-local' property are not eliminated by this function. | 2820 | `permanent-local' property are not eliminated by this function. If |
| 2821 | the optional KILL-PERMANENT argument is non-nil, clear out these local | ||
| 2822 | variables, too. | ||
| 2818 | 2823 | ||
| 2819 | The first thing this function does is run | 2824 | The first thing this function does is run |
| 2820 | the normal hook `change-major-mode-hook'. */) | 2825 | the 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. |
| 4269 | Overlap means that at least one character is contained within the overlay | 4276 | Overlap means that at least one character is contained within the overlay |
| 4270 | and also contained within the specified region. | 4277 | and also contained within the specified region. |
| 4278 | |||
| 4271 | Empty overlays are included in the result if they are located at BEG, | 4279 | Empty overlays are included in the result if they are located at BEG, |
| 4272 | between BEG and END, or at END provided END denotes the position at the | 4280 | between BEG and END, or at END provided END denotes the position at the |
| 4273 | end of the buffer. */) | 4281 | end 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 |
| 5802 | and this buffer is not full-frame width. | 5810 | and this buffer is not full-frame width. |
| 5803 | 5811 | ||
| 5804 | Minibuffers set this variable to nil. */); | 5812 | Minibuffers set this variable to nil. |
| 5813 | |||
| 5814 | Don't set this to a non-nil value when `visual-line-mode' is | ||
| 5815 | turned 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 | |||
| 6383 | If `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. | ||
| 6388 | This 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 | ||
| 1007 | INLINE unsigned char * | 1018 | INLINE 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 | |||
| 900 | a way to turn themselves off when a mouse command switches windows. */); | 900 | a 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. | ||
| 905 | If non-nil, `(interactive "e")' doesn't signal an error when the command | ||
| 906 | was invoked by an input event that is not a mouse gesture: a click, a drag, | ||
| 907 | etc. To create the event data when the input was some other event, | ||
| 908 | use `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 | |||
| 232 | input come from an Emacs buffer, use `call-process-region' instead. | 232 | input come from an Emacs buffer, use `call-process-region' instead. |
| 233 | 233 | ||
| 234 | Third argument DESTINATION specifies how to handle program's output. | 234 | Third argument DESTINATION specifies how to handle program's output. |
| 235 | (\"Output\" here means both standard output and standard error | ||
| 236 | output.) | ||
| 235 | If DESTINATION is a buffer, or t that stands for the current buffer, | 237 | If 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. |
| 237 | If DESTINATION is nil, it means discard output; 0 means discard | 239 | If 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 | ||
| 307 | static int | ||
| 308 | ascii_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 | |||
| 300 | static Lisp_Object | 317 | static Lisp_Object |
| 301 | do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj) | 318 | do_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 | ||
| 340 | DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, | 358 | DEFUN ("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. |
| 342 | The argument may be a character or string. The result has the same type. | 360 | The argument may be a character or string. The result has the same |
| 361 | type. (See `downcase' for further details about the type.) | ||
| 362 | |||
| 343 | The argument object is not altered--the value is a copy. If argument | 363 | The argument object is not altered--the value is a copy. If argument |
| 344 | is a character, characters which map to multiple code points when | 364 | is a character, characters which map to multiple code points when |
| 345 | cased, e.g. fi, are returned unchanged. | 365 | cased, e.g. fi, are returned unchanged. |
| 366 | |||
| 346 | See also `capitalize', `downcase' and `upcase-initials'. */) | 367 | See 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 | ||
| 352 | DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0, | 373 | DEFUN ("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. |
| 354 | The argument may be a character or string. The result has the same type. | 375 | The argument may be a character or string. The result has the same type, |
| 376 | including the multibyteness of the string. | ||
| 377 | |||
| 378 | This means that if this function is called with a unibyte string | ||
| 379 | argument, 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 | ||
| 382 | locale, the string must be converted into multibyte first. | ||
| 383 | |||
| 355 | The argument object is not altered--the value is a copy. */) | 384 | The 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. |
| 363 | This means that each word's first character is converted to either | 392 | This means that each word's first character is converted to either |
| 364 | title case or upper case, and the rest to lower case. | 393 | title case or upper case, and the rest to lower case. |
| 365 | The argument may be a character or string. The result has the same type. | 394 | |
| 395 | The argument may be a character or string. The result has the same | ||
| 396 | type. (See `downcase' for further details about the type.) | ||
| 397 | |||
| 366 | The argument object is not altered--the value is a copy. If argument | 398 | The argument object is not altered--the value is a copy. If argument |
| 367 | is a character, characters which map to multiple code points when | 399 | is a character, characters which map to multiple code points when |
| 368 | cased, e.g. fi, are returned unchanged. */) | 400 | cased, 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. |
| 378 | This means that each word's first character is converted to either | 410 | This means that each word's first character is converted to either |
| 379 | title case or upper case, and the rest are left unchanged. | 411 | title case or upper case, and the rest are left unchanged. |
| 380 | The argument may be a character or string. The result has the same type. | 412 | |
| 413 | The argument may be a character or string. The result has the same | ||
| 414 | type. (See `downcase' for further details about the type.) | ||
| 415 | |||
| 381 | The argument object is not altered--the value is a copy. If argument | 416 | The argument object is not altered--the value is a copy. If argument |
| 382 | is a character, characters which map to multiple code points when | 417 | is a character, characters which map to multiple code points when |
| 383 | cased, e.g. fi, are returned unchanged. */) | 418 | cased, 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 | ||
| 87 | extern int char_string (unsigned, unsigned char *); | 89 | extern 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 | |||
| 8253 | void | 8286 | void |
| 8254 | encode_coding_object (struct coding_system *coding, | 8287 | encode_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, | |||
| 151 | DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_function_new_local, | 152 | DEF_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) | ||
| 154 | DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_global_set_initializer, | 156 | DEF_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 | ||
| 156 | DEF_DLL_FN (gcc_jit_lvalue *, gcc_jit_lvalue_access_field, | 159 | DEF_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, | |||
| 176 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_call_through_ptr, | 179 | DEF_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)); |
| 182 | DEF_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)); | ||
| 179 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_comparison, | 185 | DEF_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, | |||
| 255 | DEF_DLL_FN (void, gcc_jit_struct_set_fields, | 261 | DEF_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) | ||
| 258 | DEF_DLL_FN (int, gcc_jit_version_major, (void)); | 265 | DEF_DLL_FN (int, gcc_jit_version_major, (void)); |
| 259 | DEF_DLL_FN (int, gcc_jit_version_minor, (void)); | 266 | DEF_DLL_FN (int, gcc_jit_version_minor, (void)); |
| 260 | DEF_DLL_FN (int, gcc_jit_version_patchlevel, (void)); | 267 | DEF_DLL_FN (int, gcc_jit_version_patchlevel, (void)); |
| 268 | #endif | ||
| 261 | 269 | ||
| 262 | static bool | 270 | static bool |
| 263 | init_gccjit_functions (void) | 271 | init_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 | ||
| 502 | enum cast_kind_of_type | ||
| 503 | { | ||
| 504 | kind_unsigned, | ||
| 505 | kind_signed, | ||
| 506 | kind_pointer | ||
| 507 | }; | ||
| 508 | |||
| 509 | typedef struct { | 520 | typedef 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 { | |||
| 516 | typedef struct { | 527 | typedef 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 | ||
| 3114 | struct 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 | |||
| 3122 | static gcc_jit_function * | 3123 | static gcc_jit_function * |
| 3123 | define_cast_from_to (struct cast_type from, int from_index, struct cast_type to, | 3124 | define_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 | ¶m, | 3136 | ¶m, |
| @@ -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 | |||
| 3161 | struct cast_type | ||
| 3162 | { | ||
| 3163 | gcc_jit_type *type; | ||
| 3164 | const char *name; | ||
| 3165 | bool is_ptr; | ||
| 3166 | }; | ||
| 3167 | |||
| 3168 | static gcc_jit_function * | ||
| 3169 | define_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, ¶m, 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 | |||
| 3176 | define_cast_functions (void) | 3209 | define_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 | ||
| 3244 | static void | 3266 | static void |
| @@ -4029,7 +4051,13 @@ make_directory_wrapper_1 (Lisp_Object ignore) | |||
| 4029 | 4051 | ||
| 4030 | DEFUN ("comp-el-to-eln-rel-filename", Fcomp_el_to_eln_rel_filename, | 4052 | DEFUN ("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. |
| 4055 | FILENAME must exist, and if it's a symlink, the target must exist. | ||
| 4056 | If FILENAME is compressed, it must have the \".gz\" extension, | ||
| 4057 | and Emacs must have been compiled with zlib; the file will be | ||
| 4058 | uncompressed on the fly to hash its contents. | ||
| 4059 | Value includes the original base name, followed by 2 hash values, | ||
| 4060 | one 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 | ||
| 4115 | DEFUN ("comp-el-to-eln-filename", Fcomp_el_to_eln_filename, | 4143 | DEFUN ("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. |
| 4118 | for new compilations. | 4146 | The resulting .eln file name is intended to be used for natively |
| 4119 | If BASE-DIR is non-nil use it as a base directory, look for a suitable | 4147 | compiling FILENAME. FILENAME must exist and be readable, but other |
| 4120 | directory in `comp-eln-load-path' otherwise. */) | 4148 | than that, its leading directories are ignored when constructing |
| 4149 | the name of the .eln file. | ||
| 4150 | If BASE-DIR is non-nil, use it as the directory for the .eln file; | ||
| 4151 | non-absolute BASE-DIR is interpreted as relative to `invocation-directory'. | ||
| 4152 | If BASE-DIR is omitted or nil, look for the first writable directory | ||
| 4153 | in `native-comp-eln-load-path', and use as BASE-DIR its subdirectory | ||
| 4154 | whose name is given by `comp-native-version-dir'. | ||
| 4155 | If FILENAME specifies a preloaded file, the directory for the .eln | ||
| 4156 | file is the \"preloaded/\" subdirectory of the directory determined | ||
| 4157 | as described above. FILENAME is considered to be a preloaded file if | ||
| 4158 | the value of `comp-file-preloaded-p' is non-nil, or if FILENAME | ||
| 4159 | appears in the value of the environment variable LISP_PRELOADED; | ||
| 4160 | the 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" | ||
| 4426 | DEFUN ("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 | |||
| 4386 | static void | 4441 | static void |
| 4387 | add_driver_options (void) | 4442 | add_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 | ||
| 4478 | static void | ||
| 4479 | add_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 | |||
| 4425 | DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, | 4515 | DEFUN ("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 | |||
| 4575 | unknown (before GCC version 10). */) | 4675 | unknown (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 | ||
| 4640 | static Lisp_Object all_loaded_comp_units_h; | 4740 | static 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. */ |
| 4782 | void | 4882 | void |
| 4783 | fixup_eln_load_path (Lisp_Object eln_filename) | 4883 | fixup_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 | ||
| 889 | static Lisp_Object | 890 | static Lisp_Object |
| 890 | autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos, | 891 | autocmp_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 | ||
| 968 | static inline bool | ||
| 969 | inhibit_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. |
| 2043 | Use the command `auto-composition-mode' to change this variable. */); | 2064 | Use the command `auto-composition-mode' to change this variable. |
| 2065 | |||
| 2066 | If this variable is a string, `auto-composition-mode' will be disabled in | ||
| 2067 | buffers 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. | |||
| 2100 | See also the documentation of `auto-composition-mode'. */); | 2124 | See 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 | |||
| 2130 | These are codepoints which have Emoji_Presentation = No, and thus by | ||
| 2131 | default are not displayed as emoji. In certain circumstances, such as | ||
| 2132 | when followed by U+FE0F (VS-16) the emoji font should be used for | ||
| 2133 | them anyway. | ||
| 2134 | |||
| 2135 | This 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. */ |
| 685 | DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, | 685 | DEFUN ("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); |
| 3427 | extern Lisp_Object find_hot_spot (Lisp_Object, int, int); | 3429 | extern Lisp_Object find_hot_spot (Lisp_Object, int, int); |
| 3428 | 3430 | ||
| 3429 | extern void handle_tab_bar_click (struct frame *, | 3431 | extern Lisp_Object handle_tab_bar_click (struct frame *, |
| 3430 | int, int, bool, int); | 3432 | int, int, bool, int); |
| 3431 | extern void handle_tool_bar_click (struct frame *, | 3433 | extern 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. */ | ||
| 3735 | extern bool gui_mouse_grabbed (Display_Info *); | 3736 | extern bool gui_mouse_grabbed (Display_Info *); |
| 3736 | extern void gui_redo_mouse_highlight (Display_Info *); | 3737 | extern 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. |
| 6720 | Possible values are `t' (below the tool bar), `nil' (above the tool bar). | 6715 | Possible values are t (below the tool bar), nil (above the tool bar). |
| 6721 | This option affects only builds where the tool bar is not external. */); | 6716 | This 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 | ||
| 172 | struct 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. */ |
| 173 | extern int emacs_module_init (struct emacs_runtime *runtime) | 186 | extern 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 | ||
| 138 | static const char emacs_version[] = PACKAGE_VERSION; | 139 | static 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 | |||
| 2342 | static const struct standard_args standard_args[] = | 2377 | static 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 | ||
| 371 | DEFUN ("or", For, Sor, 0, UNEVALLED, 0, | 369 | DEFUN ("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 | ||
| 1082 | static void | ||
| 1083 | with_delayed_message_display (struct atimer *timer) | ||
| 1084 | { | ||
| 1085 | message3 (build_string (timer->client_data)); | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | static void | ||
| 1089 | with_delayed_message_cancel (void *timer) | ||
| 1090 | { | ||
| 1091 | xfree (((struct atimer *) timer)->client_data); | ||
| 1092 | cancel_atimer (timer); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | DEFUN ("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. | ||
| 1099 | TIMEOUT is a number of seconds, and can be an integer or a floating | ||
| 1100 | point number. | ||
| 1101 | |||
| 1102 | If FUNCTION takes less time to execute than TIMEOUT seconds, MESSAGE | ||
| 1103 | is 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 | |||
| 1084 | DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0, | 1123 | DEFUN ("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. |
| 1086 | If FORM is not a macro call, it is returned unchanged. | 1125 | If 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. */ | ||
| 1183 | EMACS_INT minibuffer_quit_level = 0; | ||
| 1184 | |||
| 1185 | Lisp_Object | 1216 | Lisp_Object |
| 1186 | internal_catch (Lisp_Object tag, | 1217 | internal_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. |
| 4336 | If Lisp code tries to increase the total number past this amount, | 4356 | |
| 4337 | an error is signaled. | 4357 | If Lisp code tries to use more bindings than this amount, an error is |
| 4338 | You can safely use a value considerably larger than the default value, | 4358 | signaled. |
| 4339 | if that proves inconveniently small. However, if you increase it too far, | 4359 | |
| 4340 | Emacs could run out of memory trying to make the stack bigger. | 4360 | You can safely increase this variable substantially if the default |
| 4341 | Note that this limit may be silently increased by the debugger | 4361 | value proves inconveniently small. However, if you increase it too |
| 4342 | if `debug-on-error' or `debug-on-quit' is set. */); | 4362 | much, Emacs could run out of memory trying to make the stack bigger. |
| 4363 | Note 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 | ||
| 4367 | variables. \"PDL\" is short for \"push-down list\", which is an old | ||
| 4368 | term 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 |
| @@ -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. |
| 673 | The result is a string whose elements are the elements of all the arguments. | 673 | The result is a string whose elements are the elements of all the arguments. |
| 674 | Each argument may be a string or a list or vector of characters (integers). | 674 | Each argument may be a string or a list or vector of characters (integers). |
| 675 | |||
| 676 | Values of the `composition' property of the result are not guaranteed | ||
| 677 | to be `eq'. | ||
| 675 | usage: (concat &rest SEQUENCES) */) | 678 | usage: (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 | ||
| 1180 | Lisp_Object | 1183 | Lisp_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. |
| 1756 | The value is actually the first element of ALIST whose car equals KEY. | 1759 | The value is actually the first element of ALIST whose car equals KEY. |
| 1757 | 1760 | ||
| 1758 | Equality is defined by TESTFN if non-nil or by `equal' if nil. */) | 1761 | Equality is defined by the function TESTFN, defaulting to `equal'. |
| 1762 | TESTFN 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 | ||
| 2854 | DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0, | 2858 | DEFUN ("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. |
| 2856 | In between each pair of results, stick in SEPARATOR. Thus, " " as | 2860 | In 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 | |||
| 2858 | SEQUENCE may be a list, a vector, a bool-vector, or a string. | 2863 | SEQUENCE may be a list, a vector, a bool-vector, or a string. |
| 2859 | SEPARATOR must be a string, a vector, or a list of characters. | 2864 | |
| 2865 | Optional argument SEPARATOR must be a string, a vector, or a list of | ||
| 2866 | characters; nil stands for the empty string. | ||
| 2867 | |||
| 2860 | FUNCTION must be a function of one argument, and must return a value | 2868 | FUNCTION 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) | |||
| 2949 | DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0, | 2957 | DEFUN ("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. |
| 2951 | Return t if answer is yes, and nil if the answer is no. | 2959 | Return t if answer is yes, and nil if the answer is no. |
| 2952 | PROMPT is the string to display to ask the question. It should end in | 2960 | |
| 2953 | a space; `yes-or-no-p' adds \"(yes or no) \" to it. | 2961 | PROMPT is the string to display to ask the question; `yes-or-no-p' |
| 2962 | adds \"(yes or no) \" to it. It does not need to end in space, but if | ||
| 2963 | it does up to one space will be removed. | ||
| 2954 | 2964 | ||
| 2955 | The user must confirm the answer with RET, and can edit it until it | 2965 | The user must confirm the answer with RET, and can edit it until it |
| 2956 | has been confirmed. | 2966 | has 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 | ||
| 66 | static const struct table_entry weight_table[] = | 67 | static 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 | ||
| 1032 | int | 1034 | static int |
| 1033 | font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font) | 1035 | font_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 | ||
| 1230 | int | ||
| 1231 | font_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. */ | ||
| 3878 | static bool | ||
| 3879 | codepoint_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 | ||
| 3842 | Lisp_Object | 3905 | Lisp_Object |
| 3843 | font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, | 3906 | font_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 | ||
| 4980 | DEFUN ("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. | ||
| 4983 | FONT can be either a font-entity or a font-object. If it is | ||
| 4984 | a font-entity and the result is nil, it means the font needs to be | ||
| 4985 | opened (with `open-font') to check. | ||
| 4986 | FRAME 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 | |||
| 4899 | DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0, | 5007 | DEFUN ("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. |
| 4917 | If FONT-OBJECT doesn't have a glyph for a character, | 5025 | |
| 4918 | the corresponding element is nil. */) | 5026 | If FONT-OBJECT doesn't have a glyph for a character, the corresponding |
| 5027 | element is nil. | ||
| 5028 | |||
| 5029 | Also see `font-has-char-p', which is more efficient than this function | ||
| 5030 | if you just want to check whether FONT-OBJECT has a glyph for a | ||
| 5031 | character. */) | ||
| 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) | |||
| 885 | extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list); | 885 | extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list); |
| 886 | extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *, | 886 | extern 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); |
| 889 | extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned int); | 889 | extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned int); |
| 890 | 890 | ||
| 891 | extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop, | 891 | extern 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 | ||
| 1841 | DEFUN ("next-frame", Fnext_frame, Snext_frame, 0, 2, 0, | 1842 | DEFUN ("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. |
| 1843 | It considers only frames on the same terminal as FRAME. | 1844 | Only frames on the same terminal as FRAME are included in the list |
| 1844 | By default, skip minibuffer-only frames. | 1845 | of candidate frames. If omitted, FRAME defaults to the selected frame. |
| 1845 | If omitted, FRAME defaults to the selected frame. | 1846 | |
| 1846 | If optional argument MINIFRAME is nil, exclude minibuffer-only frames. | 1847 | If MINIFRAME is nil (the default), include all frames except |
| 1847 | If MINIFRAME is a window, include only its own frame | 1848 | minibuffer-only frames. |
| 1848 | and any frame now using that window as the minibuffer. | 1849 | |
| 1849 | If MINIFRAME is `visible', include all visible frames. | 1850 | If MINIFRAME is a window, include only its own frame and any frame now |
| 1850 | If MINIFRAME is 0, include all visible and iconified frames. | 1851 | using that window as the minibuffer. |
| 1851 | Otherwise, include all frames. */) | 1852 | |
| 1853 | If MINIFRAME is `visible', include only visible frames. | ||
| 1854 | |||
| 1855 | If MINIFRAME is 0, include only visible and iconified frames. | ||
| 1856 | |||
| 1857 | If 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. |
| 6254 | The pointer becomes visible again when the mouse is moved. */); | 6256 | The pointer becomes visible again when the mouse is moved. |
| 6257 | |||
| 6258 | When using this, you might also want to disable highlighting of | ||
| 6259 | clickable 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) \ | 2620 | static |
| 2621 | (w <= PANGO_WEIGHT_THIN ? Qextra_light \ | 2621 | Lisp_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 | |||
| 2640 | static | ||
| 2641 | Lisp_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 |
| 4252 | static struct xpm_cached_color **xpm_color_cache; | 4250 | static 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 |
| 8404 | DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *)); | 8407 | DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *)); |
| 8405 | DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *)); | 8408 | DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *)); |
| 8409 | DEF_DLL_FN (int, DGifSavedExtensionToGCB, | ||
| 8410 | (GifFileType *, int, GraphicsControlBlock *)); | ||
| 8406 | # endif | 8411 | # endif |
| 8407 | # if HAVE_GIFERRORSTRING | 8412 | # if HAVE_GIFERRORSTRING |
| 8408 | DEF_DLL_FN (char const *, GifErrorString, (int)); | 8413 | DEF_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 | |||
| 8902 | enum 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 | |||
| 8920 | static 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 | |||
| 8936 | static bool | ||
| 8937 | webp_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 | |||
| 8953 | DEF_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. */ | ||
| 8958 | DEF_DLL_FN (VP8StatusCode, WebPGetFeaturesInternal, | ||
| 8959 | (const uint8_t *, size_t, WebPBitstreamFeatures *, int)); | ||
| 8960 | DEF_DLL_FN (uint8_t *, WebPDecodeRGBA, (const uint8_t *, size_t, int *, int *)); | ||
| 8961 | DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *)); | ||
| 8962 | DEF_DLL_FN (void, WebPFree, (void *)); | ||
| 8963 | |||
| 8964 | static bool | ||
| 8965 | init_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 | |||
| 8998 | static bool | ||
| 8999 | webp_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, | |||
| 9816 | DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer, | 10112 | DEF_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 | ||
| 10116 | DEF_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) |
| 9822 | DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet, | 10121 | DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet, |
| 9823 | (RsvgHandle *, const guint8 *, gsize, GError **)); | 10122 | (RsvgHandle *, const guint8 *, gsize, GError **)); |
| 9824 | # endif | 10123 | # endif |
| 9825 | DEF_DLL_FN (void, rsvg_handle_get_dimensions, | ||
| 9826 | (RsvgHandle *, RsvgDimensionData *)); | ||
| 9827 | DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *)); | 10124 | DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *)); |
| 9828 | DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *)); | 10125 | DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *)); |
| 9829 | DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *)); | 10126 | DEF_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, | |||
| 1392 | void | 1392 | void |
| 1393 | replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, | 1393 | replace_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 | ||
| 171 | bool | 172 | static bool |
| 172 | intervals_equal (INTERVAL i0, INTERVAL i1) | 173 | intervals_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 | |||
| 226 | bool | ||
| 227 | intervals_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); | |||
| 375 | static void deliver_user_signal (int); | 375 | static void deliver_user_signal (int); |
| 376 | static char *find_user_signal_name (int); | 376 | static char *find_user_signal_name (int); |
| 377 | static void store_user_signal_events (void); | 377 | static void store_user_signal_events (void); |
| 378 | static 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. |
| 754 | To get out of the recursive edit, a command can throw to `exit' -- for | 755 | To get out of the recursive edit, a command can throw to `exit' -- for |
| 755 | instance (throw \\='exit nil). | 756 | instance (throw \\='exit nil). |
| 756 | If you throw a value other than t, `recursive-edit' returns normally | 757 | |
| 757 | to the function that called it. Throwing a t value causes | 758 | The following values (last argument to `throw') can be used when |
| 758 | `recursive-edit' to quit, so that control returns to the command loop | 759 | throwing to \\='exit: |
| 759 | one 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 | ||
| 761 | This function is called by the editor initialization to begin editing. */) | 773 | This function is called by the editor initialization to begin editing. */) |
| 762 | (void) | 774 | (void) |
| @@ -924,6 +936,7 @@ static Lisp_Object | |||
| 924 | cmd_error (Lisp_Object data) | 936 | cmd_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. */ |
| 4905 | static const char *const lispy_function_keys[] = | 4904 | const 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 | |||
| 11289 | DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0, | 11337 | DEFUN ("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. |
| 11291 | By default, X and Y are relative to text area of the selected window. | 11339 | By default, X and Y are relative to text area of the selected window. |
| 11340 | Note that the text area includes the header-line and the tab-line of | ||
| 11341 | the window, if any of them are present. | ||
| 11292 | Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window. | 11342 | Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window. |
| 11293 | If optional fourth arg WHOLE is non-nil, X is relative to the left | 11343 | If optional fourth arg WHOLE is non-nil, X is relative to the left |
| 11294 | edge of the window. | 11344 | edge 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 | ||
| 11609 | static Lisp_Object | ||
| 11610 | init_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 | |||
| 11630 | static bool | ||
| 11631 | is_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 | |||
| 11559 | static void syms_of_keyboard_for_pdumper (void); | 11655 | static void syms_of_keyboard_for_pdumper (void); |
| 11560 | 11656 | ||
| 11561 | void | 11657 | void |
| @@ -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'. |
| 12551 | Events 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 | ||
| 12553 | occur. */); | ||
| 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). | ||
| 12559 | Emacs allows binding both upper and lower case key sequences to | ||
| 12560 | commands. However, if there is a lower case key sequence bound to a | ||
| 12561 | command, and the user enters an upper case key sequence that is not | ||
| 12562 | bound to a command, Emacs will use the lower case binding. Setting | ||
| 12563 | this 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. | ||
| 12569 | If this variable is non-nil (the default), `input-pending-p' and | ||
| 12570 | other similar functions ignore input events in `while-no-input-ignore-events'. | ||
| 12571 | This 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); | |||
| 491 | extern struct timespec timer_check (void); | 491 | extern struct timespec timer_check (void); |
| 492 | extern void mark_kboards (void); | 492 | extern void mark_kboards (void); |
| 493 | 493 | ||
| 494 | #ifdef HAVE_NTGUI | 494 | #if defined HAVE_NTGUI || defined HAVE_X_WINDOWS |
| 495 | extern const char *const lispy_function_keys[]; | 495 | extern 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. */ |
| 66 | static Lisp_Object command_remapping_vector; | 66 | static Lisp_Object command_remapping_vector; |
| 67 | 67 | ||
| 68 | /* Char table for the backwards-compatibility part in Flookup_key. */ | ||
| 69 | static 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. */ |
| 69 | static Lisp_Object where_is_cache; | 72 | static 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. | |||
| 629 | If KEYMAP has a parent, the parent's bindings are included as well. | 632 | If KEYMAP has a parent, the parent's bindings are included as well. |
| 630 | This works recursively: if the parent has itself a parent, then the | 633 | This works recursively: if the parent has itself a parent, then the |
| 631 | grandparent's bindings are also included and so on. | 634 | grandparent's bindings are also included and so on. |
| 635 | |||
| 636 | For more information, see Info node `(elisp) Keymaps'. | ||
| 637 | |||
| 632 | usage: (map-keymap FUNCTION KEYMAP) */) | 638 | usage: (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 | ||
| 1033 | static Lisp_Object | ||
| 1034 | possibly_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 | ||
| 1029 | DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0, | 1057 | DEFUN ("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. */ | 1215 | static Lisp_Object |
| 1184 | /* GC is possible in this function. */ | 1216 | lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default) |
| 1185 | |||
| 1186 | DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0, | ||
| 1187 | doc: /* Look up key sequence KEY in KEYMAP. Return the definition. | ||
| 1188 | A value of nil means undefined. See doc of `define-key' | ||
| 1189 | for kinds of definitions. | ||
| 1190 | |||
| 1191 | A number as value means KEY is "too long"; | ||
| 1192 | that is, characters or symbols in it except for the last one | ||
| 1193 | fail to be a valid sequence of prefix characters in KEYMAP. | ||
| 1194 | The number is how many characters at the front of KEY | ||
| 1195 | it takes to reach a non-prefix key. | ||
| 1196 | KEYMAP can also be a list of keymaps. | ||
| 1197 | |||
| 1198 | Normally, `lookup-key' ignores bindings for t, which act as default | ||
| 1199 | bindings, used when nothing else in the keymap applies; this makes it | ||
| 1200 | usable as a general function for probing keymaps. However, if the | ||
| 1201 | third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will | ||
| 1202 | recognize 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 | |||
| 1261 | DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0, | ||
| 1262 | doc: /* Look up key sequence KEY in KEYMAP. Return the definition. | ||
| 1263 | A value of nil means undefined. See doc of `define-key' | ||
| 1264 | for kinds of definitions. | ||
| 1265 | |||
| 1266 | A number as value means KEY is "too long"; | ||
| 1267 | that is, characters or symbols in it except for the last one | ||
| 1268 | fail to be a valid sequence of prefix characters in KEYMAP. | ||
| 1269 | The number is how many characters at the front of KEY | ||
| 1270 | it takes to reach a non-prefix key. | ||
| 1271 | KEYMAP can also be a list of keymaps. | ||
| 1272 | |||
| 1273 | Normally, `lookup-key' ignores bindings for t, which act as default | ||
| 1274 | bindings, used when nothing else in the keymap applies; this makes it | ||
| 1275 | usable as a general function for probing keymaps. However, if the | ||
| 1276 | third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will | ||
| 1277 | recognize 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. | ||
| 3354 | If the value is t, describing bindings of consecutive keys will not | ||
| 3355 | report them as a single range if they are shadowed by different | ||
| 3356 | minor-mode commands. | ||
| 3357 | If the value is `ignore-self-insert', assume that consecutive keys | ||
| 3358 | bound to `self-insert-command' are not all shadowed; this speeds up | ||
| 3359 | commands such as \\[describe-bindings] and \\[describe-mode], but could miss some shadowing. | ||
| 3360 | Any other non-nil value is treated is t. | ||
| 3361 | |||
| 3362 | Beware: setting this non-nil could potentially slow down commands | ||
| 3363 | that 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 | |||
| 1558 | INLINE unsigned char * | 1566 | INLINE unsigned char * |
| 1559 | SDATA (Lisp_Object string) | 1567 | SDATA (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 | ||
| 1626 | INLINE void | ||
| 1627 | CHECK_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 | ||
| 1620 | struct Lisp_Vector | 1635 | struct 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. */ | ||
| 2818 | enum char_bits | 2832 | enum 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); |
| 3718 | extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t, | 3732 | extern void adjust_markers_bytepos (ptrdiff_t, ptrdiff_t, |
| 3719 | ptrdiff_t, ptrdiff_t, int); | 3733 | ptrdiff_t, ptrdiff_t, int); |
| 3720 | extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, bool, bool); | 3734 | extern void replace_range (ptrdiff_t, ptrdiff_t, Lisp_Object, bool, bool, |
| 3735 | bool, bool, bool); | ||
| 3721 | extern void replace_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, | 3736 | extern 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); |
| 3723 | extern void syms_of_insdel (void); | 3738 | extern void syms_of_insdel (void); |
| @@ -3932,7 +3947,8 @@ build_string (const char *str) | |||
| 3932 | 3947 | ||
| 3933 | extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object); | 3948 | extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object); |
| 3934 | extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object); | 3949 | extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object); |
| 3935 | extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t); | 3950 | extern 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 | ||
| 3948 | extern struct Lisp_Vector *allocate_vector (ptrdiff_t); | 3964 | extern struct Lisp_Vector *allocate_vector (ptrdiff_t) |
| 3965 | ATTRIBUTE_RETURNS_NONNULL; | ||
| 3949 | 3966 | ||
| 3950 | INLINE Lisp_Object | 3967 | INLINE Lisp_Object |
| 3951 | make_uninit_vector (ptrdiff_t size) | 3968 | make_uninit_vector (ptrdiff_t size) |
| @@ -3977,7 +3994,8 @@ make_nil_vector (ptrdiff_t size) | |||
| 3977 | } | 3994 | } |
| 3978 | 3995 | ||
| 3979 | extern struct Lisp_Vector *allocate_pseudovector (int, int, int, | 3996 | extern 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 *); | |||
| 4009 | extern void init_alloc_once (void); | 4027 | extern void init_alloc_once (void); |
| 4010 | extern void init_alloc (void); | 4028 | extern void init_alloc (void); |
| 4011 | extern void syms_of_alloc (void); | 4029 | extern void syms_of_alloc (void); |
| 4012 | extern struct buffer * allocate_buffer (void); | 4030 | extern struct buffer *allocate_buffer (void) ATTRIBUTE_RETURNS_NONNULL; |
| 4013 | extern int valid_lisp_object_p (Lisp_Object); | 4031 | extern 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. */ |
| 4115 | extern EMACS_INT minibuffer_quit_level; | ||
| 4116 | extern Lisp_Object Vautoload_queue; | 4133 | extern Lisp_Object Vautoload_queue; |
| 4117 | extern Lisp_Object Vrun_hooks; | 4134 | extern Lisp_Object Vrun_hooks; |
| 4118 | extern Lisp_Object Vsignaling_function; | 4135 | extern 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 *)); |
| 4170 | extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object)); | 4187 | extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object)); |
| 4171 | extern struct handler *push_handler (Lisp_Object, enum handlertype); | 4188 | extern struct handler *push_handler (Lisp_Object, enum handlertype) |
| 4189 | ATTRIBUTE_RETURNS_NONNULL; | ||
| 4172 | extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); | 4190 | extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); |
| 4173 | extern void specbind (Lisp_Object, Lisp_Object); | 4191 | extern void specbind (Lisp_Object, Lisp_Object); |
| 4174 | extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object); | 4192 | extern 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 | ||
| 4312 | extern char *splice_dir_file (char *, char const *, char const *); | 4330 | extern char *splice_dir_file (char *, char const *, char const *) |
| 4331 | ATTRIBUTE_RETURNS_NONNULL; | ||
| 4313 | extern bool file_name_absolute_p (const char *); | 4332 | extern bool file_name_absolute_p (const char *); |
| 4314 | extern char const *get_homedir (void); | 4333 | extern char const *get_homedir (void) ATTRIBUTE_RETURNS_NONNULL; |
| 4315 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object); | 4334 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object); |
| 4316 | extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, | 4335 | extern 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) {} | |||
| 4465 | INLINE void synchronize_system_messages_locale (void) {} | 4484 | INLINE void synchronize_system_messages_locale (void) {} |
| 4466 | INLINE void synchronize_system_time_locale (void) {} | 4485 | INLINE void synchronize_system_time_locale (void) {} |
| 4467 | #endif | 4486 | #endif |
| 4468 | extern char *emacs_strerror (int); | 4487 | extern char *emacs_strerror (int) ATTRIBUTE_RETURNS_NONNULL; |
| 4469 | extern void shut_down_emacs (int, Lisp_Object); | 4488 | extern 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 | ||
| 4532 | extern int emacs_spawn (pid_t *, int, int, int, char **, char **, | 4551 | extern 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 *); |
| 4534 | extern char **make_environment_block (Lisp_Object); | 4553 | extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; |
| 4535 | extern void init_callproc_1 (void); | 4554 | extern void init_callproc_1 (void); |
| 4536 | extern void init_callproc (void); | 4555 | extern void init_callproc (void); |
| 4537 | extern void set_initial_environment (void); | 4556 | extern 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. */ |
| 4653 | extern void syms_of_terminal (void); | 4672 | extern void syms_of_terminal (void); |
| 4673 | extern char * tty_type_name (Lisp_Object); | ||
| 4654 | 4674 | ||
| 4655 | /* Defined in font.c. */ | 4675 | /* Defined in font.c. */ |
| 4656 | extern void syms_of_font (void); | 4676 | extern void syms_of_font (void); |
| @@ -4799,17 +4819,24 @@ extern char my_edata[]; | |||
| 4799 | extern char my_endbss[]; | 4819 | extern char my_endbss[]; |
| 4800 | extern char *my_endbss_static; | 4820 | extern char *my_endbss_static; |
| 4801 | 4821 | ||
| 4802 | extern void *xmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); | 4822 | extern void *xmalloc (size_t) |
| 4803 | extern void *xzalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); | 4823 | ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL; |
| 4804 | extern void *xrealloc (void *, size_t) ATTRIBUTE_ALLOC_SIZE ((2)); | 4824 | extern void *xzalloc (size_t) |
| 4825 | ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL; | ||
| 4826 | extern void *xrealloc (void *, size_t) | ||
| 4827 | ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL; | ||
| 4805 | extern void xfree (void *); | 4828 | extern void xfree (void *); |
| 4806 | extern void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2)); | 4829 | extern void *xnmalloc (ptrdiff_t, ptrdiff_t) |
| 4830 | ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL; | ||
| 4807 | extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t) | 4831 | extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t) |
| 4808 | ATTRIBUTE_ALLOC_SIZE ((2,3)); | 4832 | ATTRIBUTE_ALLOC_SIZE ((2,3)) ATTRIBUTE_RETURNS_NONNULL; |
| 4809 | extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t); | 4833 | extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t) |
| 4810 | 4834 | ATTRIBUTE_RETURNS_NONNULL; | |
| 4811 | extern char *xstrdup (const char *) ATTRIBUTE_MALLOC; | 4835 | |
| 4812 | extern char *xlispstrdup (Lisp_Object) ATTRIBUTE_MALLOC; | 4836 | extern char *xstrdup (char const *) |
| 4837 | ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; | ||
| 4838 | extern char *xlispstrdup (Lisp_Object) | ||
| 4839 | ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; | ||
| 4813 | extern void dupstring (char **, char const *); | 4840 | extern 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 | ||
| 4860 | enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 }; | 4887 | enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 }; |
| 4861 | 4888 | ||
| 4862 | extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1)); | 4889 | extern 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 | ||
| 167 | static void build_load_history (Lisp_Object, bool); | 167 | static void build_load_history (Lisp_Object, bool); |
| 168 | |||
| 169 | static 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. */ |
| 195 | static int unread_char; | 201 | static int unread_char = -1; |
| 196 | 202 | ||
| 197 | static int | 203 | static int |
| 198 | readchar (Lisp_Object readcharfun, bool *multibyte) | 204 | readchar (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) | |||
| 4338 | Lisp_Object | 4377 | Lisp_Object |
| 4339 | intern_driver (Lisp_Object string, Lisp_Object obarray, Lisp_Object index) | 4378 | intern_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 | ||
| 4444 | DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, | 4514 | DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, |
| @@ -4450,7 +4520,8 @@ OBARRAY, if nil, defaults to the value of the variable `obarray'. | |||
| 4450 | usage: (unintern NAME OBARRAY) */) | 4520 | usage: (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 | |||
| 4644 | Lisp_Object | ||
| 4645 | oblookup_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 | ||
| 4557 | void | 4699 | void |
| 4558 | map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Object arg) | 4700 | map_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. | ||
| 5457 | This variable's value can only be set via file-local variables. | ||
| 5458 | See 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 | ||
| 616 | static CGColorRef | ||
| 617 | get_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 | ||
| 1548 | static bool | ||
| 1549 | match_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 | |||
| 1540 | DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0, | 1569 | DEFUN ("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. |
| 1542 | Test each possible completion specified by COLLECTION | 1571 | Test each possible completion specified by COLLECTION |
| @@ -1570,6 +1599,7 @@ Additionally to this predicate, `completion-regexp-list' | |||
| 1570 | is used to further constrain the set of candidates. */) | 1599 | is 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 | ||
| 2035 | DEF, if non-nil, is the default value or the list of default values. | 2012 | DEF, 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. */ |
| 2053 | DEFUN ("test-completion", Ftest_completion, Stest_completion, 2, 3, 0, | 2030 | DEFUN ("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. |
| 2032 | For instance, if COLLECTION is a list of strings, STRING is a | ||
| 2033 | valid completion if it appears in the list and PREDICATE is satisfied. | ||
| 2034 | |||
| 2055 | Takes the same arguments as `all-completions' and `try-completion'. | 2035 | Takes the same arguments as `all-completions' and `try-completion'. |
| 2036 | |||
| 2056 | If COLLECTION is a function, it is called with three arguments: | 2037 | If COLLECTION is a function, it is called with three arguments: |
| 2057 | the values STRING, PREDICATE and `lambda'. */) | 2038 | the 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 | |||
| 2527 | instead. */); | 2497 | instead. */); |
| 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. | ||
| 2502 | If this is non-nil (the default), reading input with the minibuffer will | ||
| 2503 | restore, on exit, the window configurations of the frame where the | ||
| 2504 | minibuffer was entered from and, if it is different, the frame that owns | ||
| 2505 | the associated minibuffer window. | ||
| 2506 | |||
| 2507 | If this is nil, window configurations are not restored upon exiting | ||
| 2508 | the minibuffer. However, if `minibuffer-restore-windows' is present | ||
| 2509 | in `minibuffer-exit-hook', exiting the minibuffer will remove the window | ||
| 2510 | showing 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 | ||
| 612 | void | ||
| 613 | ns_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 */ |
| 614 | static void | 660 | static void |
| 615 | ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | 661 | ns_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 |
| 48 | static void ns_uni_to_glyphs (struct nsfont_info *font_info, | 50 | information for each glyph. Borrowed from macfont.h. */ |
| 49 | unsigned char block); | 51 | struct ns_glyph_layout |
| 50 | static 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 | |||
| 76 | enum lgstring_direction | ||
| 77 | { | ||
| 78 | DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum gs_font_slant | ||
| 82 | { | ||
| 83 | GS_FONT_SLANT_ITALIC, | ||
| 84 | GS_FONT_SLANT_REVERSE_ITALIC, | ||
| 85 | GS_FONT_SLANT_NORMAL | ||
| 86 | }; | ||
| 87 | |||
| 88 | enum gs_font_weight | ||
| 89 | { | ||
| 90 | GS_FONT_WEIGHT_LIGHT, | ||
| 91 | GS_FONT_WEIGHT_BOLD, | ||
| 92 | GS_FONT_WEIGHT_NORMAL | ||
| 93 | }; | ||
| 94 | |||
| 95 | enum gs_font_width | ||
| 96 | { | ||
| 97 | GS_FONT_WIDTH_CONDENSED, | ||
| 98 | GS_FONT_WIDTH_EXPANDED, | ||
| 99 | GS_FONT_WIDTH_NORMAL | ||
| 100 | }; | ||
| 101 | |||
| 102 | enum 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 | ||
| 111 | struct 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. */ | ||
| 64 | static void | 121 | static void |
| 65 | ns_escape_name (char *name) | 122 | ns_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. */ | ||
| 74 | static void | 128 | static void |
| 75 | ns_unescape_name (char *name) | 129 | ns_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 | |||
| 224 | static bool | ||
| 225 | ns_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. */ | ||
| 291 | static void ns_uni_to_glyphs (struct nsfont_info *font_info, | ||
| 292 | unsigned char block); | ||
| 293 | static 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. */ |
| 84 | static NSString * | 306 | static 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. */ | ||
| 106 | static float | ||
| 107 | ns_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 | ||
| 118 | static NSFontDescriptor * | 324 | static NSFontDescriptor * |
| 119 | ns_spec_to_descriptor (Lisp_Object font_spec) | 325 | ns_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, | |||
| 223 | static Lisp_Object | 498 | static Lisp_Object |
| 224 | ns_fallback_entity (void) | 499 | ns_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. */ |
| 515 | must return something. Strategy is to drop family name from attribute | ||
| 516 | matching set for match. */ | ||
| 517 | static Lisp_Object | 792 | static Lisp_Object |
| 518 | ns_findfonts (Lisp_Object font_spec, BOOL isMatch) | 793 | ns_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) | |||
| 668 | static Lisp_Object | 919 | static Lisp_Object |
| 669 | nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) | 920 | nsfont_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, | |||
| 934 | static int | 1158 | static int |
| 935 | nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, | 1159 | nsfont_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 | ||
| 1247 | static NSUInteger | ||
| 1248 | ns_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 | |||
| 1497 | static Lisp_Object | ||
| 1498 | nsfont_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 | ||
| 1609 | static NSGlyph | ||
| 1610 | ns_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. */ |
| 1139 | static void | 1655 | static 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. */ |
| 1180 | static void | 1697 | static void |
| 1181 | ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) | 1698 | ns_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) | |||
| 101 | static void | 101 | static void |
| 102 | ns_update_menubar (struct frame *f, bool deep_p) | 102 | ns_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 | ||
| 1005 | void | 1045 | void |
| 1006 | update_frame_tool_bar (struct frame *f) | 1046 | update_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 | |||
| 1172 | void | ||
| 1173 | update_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); |
| 1162 | extern void ns_set_scroll_bar_default_width (struct frame *f); | 1143 | extern void ns_set_scroll_bar_default_width (struct frame *f); |
| 1163 | extern void ns_set_scroll_bar_default_height (struct frame *f); | 1144 | extern void ns_set_scroll_bar_default_height (struct frame *f); |
| 1145 | extern void ns_change_tab_bar_height (struct frame *f, int height); | ||
| 1164 | extern const char *ns_get_string_resource (void *_rdb, | 1146 | extern 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 */ |
| 1177 | extern void update_frame_tool_bar (struct frame *f); | 1159 | extern void update_frame_tool_bar (struct frame *f); |
| 1160 | #ifdef __OBJC__ | ||
| 1161 | extern void update_frame_tool_bar_1 (struct frame *f, EmacsToolbar *toolbar); | ||
| 1162 | #endif | ||
| 1163 | |||
| 1178 | extern void free_frame_tool_bar (struct frame *f); | 1164 | extern void free_frame_tool_bar (struct frame *f); |
| 1179 | extern Lisp_Object find_and_return_menu_selection (struct frame *f, | 1165 | extern 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 */ |
| 274 | static struct frame *ns_updating_frame; | 272 | static struct frame *ns_updating_frame; |
| 275 | #if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 | ||
| 276 | static NSView *focus_view = NULL; | ||
| 277 | #endif | ||
| 278 | static int ns_window_num = 0; | 273 | static int ns_window_num = 0; |
| 279 | static BOOL gsaved = NO; | 274 | static 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 |
| 1385 | static void | 1285 | static void |
| 1386 | hide_bell (void) | 1286 | hide_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 | ||
| 1842 | void | 1715 | void |
| 1843 | ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) | 1716 | ns_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 | ||
| 1891 | void | 1753 | void |
| 1892 | ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) | 1754 | ns_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 | ||
| 1997 | void | 1797 | void |
| @@ -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. */ | ||
| 2784 | static void | 2584 | static void |
| 2785 | ns_redraw_scroll_bars (struct frame *f) | 2585 | ns_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 | ||
| 2893 | static NSMutableDictionary *fringe_bmp; | ||
| 2894 | |||
| 2895 | static void | ||
| 2896 | ns_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 | |||
| 2920 | static void | ||
| 2921 | ns_destroy_fringe_bitmap (int which) | ||
| 2922 | { | ||
| 2923 | [fringe_bmp removeObjectForKey:[NSNumber numberWithInt:which]]; | ||
| 2924 | } | ||
| 2925 | |||
| 3095 | 2926 | ||
| 3096 | extern int max_used_fringe_bitmap; | ||
| 3097 | static void | 2927 | static void |
| 3098 | ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | 2928 | ns_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 | ||
| 3692 | static void | 3455 | static void |
| 3693 | ns_draw_relief (NSRect r, int hthickness, int vthickness, char raised_p, | 3456 | ns_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) | |||
| 4070 | static void | 3820 | static void |
| 4071 | ns_dumpglyphs_stretch (struct glyph_string *s) | 3821 | ns_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) | |||
| 4138 | static void | 3857 | static void |
| 4139 | ns_draw_glyph_string_foreground (struct glyph_string *s) | 3858 | ns_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 | ||
| 4929 | static void | ||
| 4930 | ns_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 | ||
| 315 | static void | 315 | void |
| 316 | dump_fingerprint (char const *label, | 316 | dump_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 | ||
| 802 | static void ATTRIBUTE_UNUSED | 803 | static void |
| 803 | dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value) | 804 | dump_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 | ||
| 812 | static void ATTRIBUTE_UNUSED | ||
| 813 | dump_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 | |||
| 830 | static bool | 813 | static bool |
| 831 | dump_tailq_empty_p (struct dump_tailq *tailq) | 814 | dump_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 (§ions[i]); | 5709 | dump_mmap_release (§ions[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 | ||
| 25 | INLINE_HEADER_BEGIN | 27 | INLINE_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 | ||
| 55 | extern void dump_fingerprint (FILE *output, const char *label, | ||
| 56 | unsigned char const fingerp[sizeof fingerprint]); | ||
| 57 | |||
| 53 | extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes); | 58 | extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes); |
| 54 | 59 | ||
| 55 | INLINE void | 60 | INLINE 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. */ | ||
| 688 | static bool | ||
| 689 | kbd_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 |
| 1719 | to the standard error of subprocess. Specifying this implies | 1736 | to 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 |
| 1721 | is mixed with standard output and sent to BUFFER or FILTER. | 1738 | is mixed with standard output and sent to BUFFER or FILTER. (Note |
| 1739 | that specifying :stderr will create a new, separate (but associated) | ||
| 1740 | process, with its own filter and sentinel. See | ||
| 1741 | Info 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 |
| 1724 | for a file name handler for the current buffer's `default-directory' | 1744 | for 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, | |||
| 6888 | don't send the signal. | 6912 | don't send the signal. |
| 6889 | 6913 | ||
| 6890 | This function calls the functions of `interrupt-process-functions' in | 6914 | This function calls the functions of `interrupt-process-functions' in |
| 6891 | the order of the list, until one of them returns non-`nil'. */) | 6915 | the 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 | ||
| 8240 | DEFUN ("num-processors", Fnum_processors, Snum_processors, 0, 1, 0, | ||
| 8241 | doc: /* Return the number of processors, a positive integer. | ||
| 8242 | Each usable thread execution unit counts as a processor. | ||
| 8243 | By default, count the number of available processors, | ||
| 8244 | overridable via the OMP_NUM_THREADS environment variable. | ||
| 8245 | If optional argument QUERY is `current', ignore OMP_NUM_THREADS. | ||
| 8246 | If 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'. |
| 8516 | The arguments of the functions are the same as for `interrupt-process'. | 8556 | The arguments of the functions are the same as for `interrupt-process'. |
| 8517 | These functions are called in the order of the list, until one of them | 8557 | These functions are called in the order of the list, until one of them |
| 8518 | returns non-`nil'. */); | 8558 | returns 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 | ||
| 261 | static Lisp_Object | 262 | static Lisp_Object |
| 262 | looking_at_1 (Lisp_Object string, bool posix) | 263 | looking_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 | ||
| 345 | DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0, | 346 | DEFUN ("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. |
| 347 | This function modifies the match data that `match-beginning', | 348 | By 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 |
| 349 | data if you want to preserve them. */) | 350 | INHIBIT-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 | ||
| 355 | DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 1, 0, | 356 | DEFUN ("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. |
| 357 | Find the longest match, in accordance with Posix regular expression rules. | 358 | Find the longest match, in accordance with Posix regular expression rules. |
| 358 | This function modifies the match data that `match-beginning', | 359 | |
| 359 | `match-end' and `match-data' access; save and restore the match | 360 | By default, this function modifies the match data that |
| 360 | data if you want to preserve them. */) | 361 | `match-beginning', `match-end' and `match-data' access. If |
| 361 | (Lisp_Object regexp) | 362 | INHIBIT-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 | ||
| 366 | static Lisp_Object | 368 | static Lisp_Object |
| 367 | string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start, | 369 | string_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 | ||
| 436 | DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0, | 437 | DEFUN ("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. |
| 438 | Matching ignores case if `case-fold-search' is non-nil. | 439 | Matching ignores case if `case-fold-search' is non-nil. |
| 439 | If third arg START is non-nil, start search at that index in STRING. | 440 | If third arg START is non-nil, start search at that index in STRING. |
| 440 | For index of first char beyond the match, do (match-end 0). | ||
| 441 | `match-end' and `match-beginning' also give indices of substrings | ||
| 442 | matched by parenthesis constructs in the pattern. | ||
| 443 | 441 | ||
| 444 | You can use the function `match-string' to extract the substrings | 442 | If INHIBIT-MODIFY is non-nil, match data is not changed. |
| 445 | matched by the parenthesis constructions in REGEXP. */) | 443 | |
| 446 | (Lisp_Object regexp, Lisp_Object string, Lisp_Object start) | 444 | If INHIBIT-MODIFY is nil or missing, match data is changed, and |
| 445 | `match-end' and `match-beginning' give indices of substrings matched | ||
| 446 | by parenthesis constructs in the pattern. You can use the function | ||
| 447 | `match-string' to extract the substrings matched by the parenthesis | ||
| 448 | constructions 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 | ||
| 451 | DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 3, 0, | 456 | DEFUN ("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. |
| 453 | Find the longest match, in accord with Posix regular expression rules. | 458 | Find the longest match, in accord with Posix regular expression rules. |
| 454 | Case is ignored if `case-fold-search' is non-nil in the current buffer. | 459 | Case is ignored if `case-fold-search' is non-nil in the current buffer. |
| 455 | If third arg START is non-nil, start search at that index in STRING. | 460 | |
| 456 | For index of first char beyond the match, do (match-end 0). | 461 | If INHIBIT-MODIFY is non-nil, match data is not changed. |
| 457 | `match-end' and `match-beginning' also give indices of substrings | 462 | |
| 458 | matched by parenthesis constructs in the pattern. */) | 463 | If 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 |
| 465 | by parenthesis constructs in the pattern. You can use the function | ||
| 466 | `match-string' to extract the substrings matched by the parenthesis | ||
| 467 | constructions 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. | |||
| 17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License |
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | 18 | along 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. |
| 3548 | Parsing stops at TO or when certain criteria are met; | 3547 | Parsing 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. |
| 3550 | If fifth arg OLDSTATE is omitted or nil, | 3549 | |
| 3551 | parsing assumes that FROM is the beginning of a function. | 3550 | If 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 | ||
| 3553 | Value is a list of elements describing final state of parsing: | 3554 | Value 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 | ||
| 29 | extern FILE *emacs_fopen (char const *, char const *); | 29 | extern FILE *emacs_fopen (char const *, char const *) ATTRIBUTE_MALLOC; |
| 30 | extern void errputc (int); | 30 | extern void errputc (int); |
| 31 | extern void errwrite (void const *, ptrdiff_t); | 31 | extern void errwrite (void const *, ptrdiff_t); |
| 32 | extern void close_output_streams (void); | 32 | extern 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 *); | |||
| 101 | extern void sys_cond_broadcast (sys_cond_t *); | 101 | extern void sys_cond_broadcast (sys_cond_t *); |
| 102 | extern void sys_cond_destroy (sys_cond_t *); | 102 | extern void sys_cond_destroy (sys_cond_t *); |
| 103 | 103 | ||
| 104 | extern sys_thread_t sys_thread_self (void) | 104 | NODISCARD extern sys_thread_t sys_thread_self (void); |
| 105 | NODISCARD; | 105 | NODISCARD extern bool sys_thread_equal (sys_thread_t, sys_thread_t); |
| 106 | extern bool sys_thread_equal (sys_thread_t, sys_thread_t) | 106 | |
| 107 | NODISCARD; | 107 | NODISCARD extern bool sys_thread_create (sys_thread_t *, |
| 108 | 108 | thread_creation_function *, void *); | |
| 109 | extern bool sys_thread_create (sys_thread_t *, thread_creation_function *, | ||
| 110 | void *) | ||
| 111 | NODISCARD; | ||
| 112 | 109 | ||
| 113 | extern void sys_thread_yield (void); | 110 | extern void sys_thread_yield (void); |
| 114 | extern void sys_thread_set_name (const char *); | 111 | extern 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 | ||
| 2173 | char * | ||
| 2174 | tty_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 | |||
| 2172 | DEFUN ("tty-type", Ftty_type, Stty_type, 0, 1, 0, | 2181 | DEFUN ("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. |
| 2174 | Returns nil if TERMINAL is not on a tty device. | 2183 | Returns 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 | |||
| 2177 | selected frame's terminal). */) | 2186 | selected 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 | ||
| 2186 | DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0, | 2194 | DEFUN ("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 | ||
| 236 | struct input_event; | 236 | struct input_event; |
| 237 | extern bool tty_handle_tab_bar_click (struct frame *, int, int, bool, | 237 | extern 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 * | |||
| 48 | read_exe_header (int fd, exe_header_t * exe_header_buffer) | 48 | read_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 = | |||
| 25 | AM_V_CC = | 25 | AM_V_CC = |
| 26 | AM_V_CCLD = | 26 | AM_V_CCLD = |
| 27 | AM_V_ELC = | 27 | AM_V_ELC = |
| 28 | AM_V_ELN = | ||
| 28 | AM_V_GEN = | 29 | AM_V_GEN = |
| 29 | AM_V_GLOBALS = | 30 | AM_V_GLOBALS = |
| 30 | AM_V_NO_PD = | 31 | AM_V_NO_PD = |
| @@ -37,11 +38,14 @@ AM_V_CCLD = @echo " CCLD " $@; | |||
| 37 | ifeq ($(HAVE_NATIVE_COMP),yes) | 38 | ifeq ($(HAVE_NATIVE_COMP),yes) |
| 38 | ifeq ($(NATIVE_DISABLED),1) | 39 | ifeq ($(NATIVE_DISABLED),1) |
| 39 | AM_V_ELC = @echo " ELC " $@; | 40 | AM_V_ELC = @echo " ELC " $@; |
| 41 | AM_V_ELN = | ||
| 40 | else | 42 | else |
| 41 | AM_V_ELC = @echo " ELC+ELN " $@; | 43 | AM_V_ELC = @echo " ELC+ELN " $@; |
| 44 | AM_V_ELN = @echo " ELN " $@; | ||
| 42 | endif | 45 | endif |
| 43 | else | 46 | else |
| 44 | AM_V_ELC = @echo " ELC " $@; | 47 | AM_V_ELC = @echo " ELC " $@; |
| 48 | AM_V_ELN = | ||
| 45 | endif | 49 | endif |
| 46 | AM_V_GEN = @echo " GEN " $@; | 50 | AM_V_GEN = @echo " GEN " $@; |
| 47 | AM_V_GLOBALS = @echo " GEN " globals.h; | 51 | AM_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. |
| @@ -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. */ | ||
| 1969 | unsigned long | ||
| 1970 | num_processors (enum nproc_query query) | ||
| 1971 | { | ||
| 1972 | /* We ignore QUERY. */ | ||
| 1973 | return w32_get_nproc (); | ||
| 1974 | } | ||
| 1975 | |||
| 1965 | static void | 1976 | static void |
| 1966 | sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user) | 1977 | sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user) |
| 1967 | { | 1978 | { |
| @@ -2389,8 +2400,13 @@ rand_as183 (void) | |||
| 2389 | int | 2400 | int |
| 2390 | random (void) | 2401 | random (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 | ||
| 2396 | void | 2412 | void |
| @@ -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 | ||
| 2807 | LPBYTE | ||
| 2808 | w32_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. */ |
| 2856 | void | 2825 | void |
| @@ -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; |
| @@ -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. */ |
| 157 | extern void prepare_standard_handles (int in, int out, | 157 | extern 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. */ |
| 161 | extern void reset_standard_handles (int in, int out, | 161 | extern 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 |
| 165 | extern LPBYTE w32_get_resource (const char * key, LPDWORD type); | 165 | associated with KEY and NAME of type TYPE. */ |
| 166 | extern LPBYTE w32_get_resource (const char * key, const char * name, LPDWORD type); | ||
| 166 | 167 | ||
| 167 | extern void release_listen_threads (void); | 168 | extern void release_listen_threads (void); |
| 168 | extern void init_ntproc (int); | 169 | extern 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); | |||
| 185 | typedef HRESULT (WINAPI *SetThreadDescription_Proc) | 199 | typedef HRESULT (WINAPI *SetThreadDescription_Proc) |
| 186 | (HANDLE hThread, PCWSTR lpThreadDescription); | 200 | (HANDLE hThread, PCWSTR lpThreadDescription); |
| 187 | 201 | ||
| 202 | typedef HRESULT (WINAPI * SetWindowTheme_Proc) | ||
| 203 | (IN HWND hwnd, IN LPCWSTR pszSubAppName, IN LPCWSTR pszSubIdList); | ||
| 204 | typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) | ||
| 205 | (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); | ||
| 206 | |||
| 188 | TrackMouseEvent_Proc track_mouse_event_fn = NULL; | 207 | TrackMouseEvent_Proc track_mouse_event_fn = NULL; |
| 189 | ImmGetCompositionString_Proc get_composition_string_fn = NULL; | 208 | ImmGetCompositionString_Proc get_composition_string_fn = NULL; |
| 190 | ImmGetContext_Proc get_ime_context_fn = NULL; | 209 | ImmGetContext_Proc get_ime_context_fn = NULL; |
| @@ -199,6 +218,8 @@ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL; | |||
| 199 | GetTitleBarInfo_Proc get_title_bar_info_fn = NULL; | 218 | GetTitleBarInfo_Proc get_title_bar_info_fn = NULL; |
| 200 | IsDebuggerPresent_Proc is_debugger_present = NULL; | 219 | IsDebuggerPresent_Proc is_debugger_present = NULL; |
| 201 | SetThreadDescription_Proc set_thread_description = NULL; | 220 | SetThreadDescription_Proc set_thread_description = NULL; |
| 221 | SetWindowTheme_Proc SetWindowTheme_fn = NULL; | ||
| 222 | DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; | ||
| 202 | 223 | ||
| 203 | extern AppendMenuW_Proc unicode_append_menu; | 224 | extern AppendMenuW_Proc unicode_append_menu; |
| 204 | 225 | ||
| @@ -252,6 +273,9 @@ int w32_major_version; | |||
| 252 | int w32_minor_version; | 273 | int w32_minor_version; |
| 253 | int w32_build_number; | 274 | int w32_build_number; |
| 254 | 275 | ||
| 276 | /* If the OS is set to use dark mode. */ | ||
| 277 | BOOL w32_darkmode = FALSE; | ||
| 278 | |||
| 255 | /* Distinguish between Windows NT and Windows 95. */ | 279 | /* Distinguish between Windows NT and Windows 95. */ |
| 256 | int os_subtype; | 280 | int 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. */ | ||
| 2308 | static void | ||
| 2309 | w32_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 | |||
| 2282 | static HWND | 2332 | static HWND |
| 2283 | w32_createvscrollbar (struct frame *f, struct scroll_bar * bar) | 2333 | w32_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 | ||
| 2296 | static HWND | 2349 | static HWND |
| 2297 | w32_createhscrollbar (struct frame *f, struct scroll_bar * bar) | 2350 | w32_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 | ||
| 2310 | static void | 2366 | static 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. */ | ||
| 10327 | LPBYTE | ||
| 10328 | w32_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) | |||
| 2000 | static Lisp_Object | 2000 | static Lisp_Object |
| 2001 | w32_to_fc_weight (int n) | 2001 | w32_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; | |||
| 189 | realloc_fn the_realloc_fn; | 189 | realloc_fn the_realloc_fn; |
| 190 | free_fn the_free_fn; | 190 | free_fn the_free_fn; |
| 191 | 191 | ||
| 192 | static void * | ||
| 193 | heap_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 | |||
| 201 | static void * | ||
| 202 | heap_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 * | |||
| 346 | malloc_after_dump (size_t size) | 366 | malloc_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 | ||
| 3881 | DEFUN ("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 | ||
| 3890 | void | 3882 | void |
| 3891 | syms_of_ntproc (void) | 3883 | syms_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. |
| 3927 | Because Windows does not directly pass argv arrays to child processes, | 3917 | Because 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; | |||
| 168 | int w32_message_fd = -1; | 168 | int w32_message_fd = -1; |
| 169 | #endif /* CYGWIN */ | 169 | #endif /* CYGWIN */ |
| 170 | 170 | ||
| 171 | static void w32_handle_tab_bar_click (struct frame *, | 171 | static Lisp_Object w32_handle_tab_bar_click (struct frame *, |
| 172 | struct input_event *); | 172 | struct input_event *); |
| 173 | static void w32_handle_tool_bar_click (struct frame *, | 173 | static void w32_handle_tool_bar_click (struct frame *, |
| 174 | struct input_event *); | 174 | struct input_event *); |
| 175 | static void w32_define_cursor (Window, Emacs_Cursor); | 175 | static void w32_define_cursor (Window, Emacs_Cursor); |
| @@ -954,22 +954,6 @@ w32_set_cursor_gc (struct glyph_string *s) | |||
| 954 | static void | 954 | static void |
| 955 | w32_set_mouse_face_gc (struct glyph_string *s) | 955 | w32_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 | ||
| 3687 | static void | 3660 | static Lisp_Object |
| 3688 | w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event) | 3661 | w32_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 | |||
| 769 | DEFUN ("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. | ||
| 772 | WINDOW 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 | ||
| 764 | DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0, | 782 | DEFUN ("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 | |||
| 3194 | window-start value is reasonable when this function is called. */) | 3212 | window-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 | |||
| 8127 | DEFUN ("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 | ||
| 8140 | static void init_window_once_for_pdumper (void); | 8140 | static 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, | |||
| 1179 | static Lisp_Object get_it_property (struct it *, Lisp_Object); | 1179 | static Lisp_Object get_it_property (struct it *, Lisp_Object); |
| 1180 | static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, | 1180 | static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, |
| 1181 | struct font *, int, bool); | 1181 | struct font *, int, bool); |
| 1182 | 1182 | static int adjust_glyph_width_for_mouse_face (struct glyph *, | |
| 1183 | struct glyph_row *, | ||
| 1184 | struct window *, struct face *, | ||
| 1185 | struct face *); | ||
| 1186 | static 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 | ||
| 1185 | static void produce_special_glyphs (struct it *, enum display_element_type); | 1191 | static 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) | |||
| 4472 | static enum prop_handled | 4484 | static enum prop_handled |
| 4473 | handle_face_prop (struct it *it) | 4485 | handle_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 | ||
| 10599 | DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0, | 10629 | DEFUN ("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. |
| 10601 | WINDOW must be a live window and defaults to the selected one. The | 10631 | WINDOW can be any live window and defaults to the selected one. The |
| 10602 | return value is a cons of the maximum pixel-width of any text line | 10632 | return value is a cons of the maximum pixel-width of any text line |
| 10603 | and the pixel-height of all the text lines in the accessible portion | 10633 | and the pixel-height of all the text lines in the accessible portion |
| 10604 | of buffer text. | 10634 | of buffer text. |
| 10635 | WINDOW can also be a buffer, in which case the selected window is used, | ||
| 10636 | and the function behaves as if that window was displaying this buffer. | ||
| 10605 | 10637 | ||
| 10606 | This function exists to allow Lisp programs to adjust the dimensions | 10638 | This function exists to allow Lisp programs to adjust the dimensions |
| 10607 | of WINDOW to the buffer text it needs to display. | 10639 | of WINDOW to the buffer text it needs to display. |
| @@ -10637,16 +10669,17 @@ position specified by TO. Since calculating the text height of a | |||
| 10637 | large buffer can take some time, it makes sense to specify this | 10669 | large buffer can take some time, it makes sense to specify this |
| 10638 | argument if the size of the buffer is large or unknown. | 10670 | argument if the size of the buffer is large or unknown. |
| 10639 | 10671 | ||
| 10640 | Optional argument MODE-AND-HEADER-LINE nil or omitted means do not | 10672 | Optional argument MODE-LINES nil or omitted means do not include the |
| 10641 | include the height of the mode- or header-line of WINDOW in the return | 10673 | height of the mode-, tab- or header-line of WINDOW in the return value. |
| 10642 | value. If it is either the symbol `mode-line' or `header-line', include | 10674 | If it is the symbol `mode-line', 'tab-line' or `header-line', include |
| 10643 | only the height of that line, if present, in the return value. If t, | 10675 | only the height of that line, if present, in the return value. If t, |
| 10644 | include the height of both, if present, in the return value. */) | 10676 | include 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 | ||
| 13748 | void | 13803 | Lisp_Object |
| 13749 | handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | 13804 | handle_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. */ |
| 13896 | static Lisp_Object | 13951 | static Lisp_Object |
| 13897 | tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end) | 13952 | tty_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. */ |
| 13923 | bool | 13981 | Lisp_Object |
| 13924 | tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | 13982 | tty_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 | ||
| 24445 | DEFUN ("bidi-find-overridden-directionality", | 24510 | DEFUN ("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 | ||
| 24450 | This function returns the first character position in the specified | 24515 | This 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, | |||
| 24463 | because this function will then be able to correctly account for | 24528 | because this function will then be able to correctly account for |
| 24464 | window-specific overlays, which can affect the results. | 24529 | window-specific overlays, which can affect the results. |
| 24465 | 24530 | ||
| 24531 | Optional argument BASE-DIR specifies the base paragraph directory | ||
| 24532 | of the text. It should be a symbol, either `left-to-right' | ||
| 24533 | or `right-to-left', and defaults to `left-to-right'. | ||
| 24534 | |||
| 24466 | Strong directional characters `L', `R', and `AL' can have their | 24535 | Strong directional characters `L', `R', and `AL' can have their |
| 24467 | intrinsic directionality overridden by directional override | 24536 | intrinsic directionality overridden by directional override |
| 24468 | control characters RLO (u+202e) and LRO (u+202d). See the | 24537 | control characters RLO (u+202E) and LRO (u+202D). They can also |
| 24469 | function `get-char-code-property' for a way to inquire about | 24538 | have their directionality affected by other formatting control |
| 24539 | characters: LRE (u+202A), RLE (u+202B), LRI (u+2066), and RLI (u+2067). | ||
| 24540 | See the function `get-char-code-property' for a way to inquire about | ||
| 24470 | the `bidi-class' property of a character. */) | 24541 | the `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 | ||
| 25438 | static int | 25509 | static int |
| 25439 | display_mode_lines (struct window *w) | 25510 | display_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 | ||
| 28574 | static void | 28723 | static void |
| 28575 | set_glyph_string_background_width (struct glyph_string *s, int start, int last_x) | 28724 | set_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. | |||
| 35021 | A value of nil means no special handling of these characters. */); | 35235 | A 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. | ||
| 35240 | If the value of this variable is nil, the default, Emacs displays | ||
| 35241 | non-ASCII chars which have the same appearance as an ASCII space | ||
| 35242 | or hyphen as themselves, with the `nobreak-space' or `nobreak-hyphen' | ||
| 35243 | face, respectively. | ||
| 35244 | |||
| 35245 | If the value is t, these characters are displayed as their ASCII | ||
| 35246 | counterparts: whitespace characters as ASCII space, hyphen characters | ||
| 35247 | as ASCII hyphen (a.k.a. \"dash\"), using the `nobreak-space' or | ||
| 35248 | the `nobreak-hyphen' face. | ||
| 35249 | |||
| 35250 | This variable has effect only if `nobreak-char-display' is t; | ||
| 35251 | otherwise it is ignored. | ||
| 35252 | |||
| 35253 | All of the non-ASCII characters in the Unicode horizontal whitespace | ||
| 35254 | character class, as well as U+00AD (soft hyphen), U+2010 (hyphen), and | ||
| 35255 | U+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. |
| 35026 | A value of nil means to show the text pointer. Other options are | 35260 | A value of nil means to show the text pointer. Other options are |
| @@ -35114,7 +35348,10 @@ not span the full frame width. | |||
| 35114 | 35348 | ||
| 35115 | A value of nil means to respect the value of `truncate-lines'. | 35349 | A value of nil means to respect the value of `truncate-lines'. |
| 35116 | 35350 | ||
| 35117 | If `word-wrap' is enabled, you might want to reduce this. */); | 35351 | If `word-wrap' is enabled, you might want to reduce the value of this. |
| 35352 | |||
| 35353 | Don't set this to a non-nil value when `visual-line-mode' is | ||
| 35354 | turned 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. |
| 35427 | Bind this around calls to `message' to let it take effect. */); | 35664 | Bind 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 | |||
| 35737 | mouse stays within the extent of a single glyph (except for images). */); | 35974 | mouse 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. |
| 35742 | The initial frame is not displayed anywhere, so skipping it is | 35983 | The 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. */ | ||
| 36167 | static int | ||
| 36168 | adjust_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. */ | ||
| 36226 | static void | ||
| 36227 | get_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", | |||
| 5396 | The optional argument DISPLAY can be a display name, a frame, or | 5397 | The optional argument DISPLAY can be a display name, a frame, or |
| 5397 | nil (meaning the selected frame's display). | 5398 | nil (meaning the selected frame's display). |
| 5398 | 5399 | ||
| 5400 | For instance, to check whether the display supports underlining: | ||
| 5401 | |||
| 5402 | (display-supports-face-attributes-p \\='(:underline t)) | ||
| 5403 | |||
| 5399 | The definition of `supported' is somewhat heuristic, but basically means | 5404 | The definition of `supported' is somewhat heuristic, but basically means |
| 5400 | that a face containing all the attributes in ATTRIBUTES, when merged | 5405 | that a face containing all the attributes in ATTRIBUTES, when merged |
| 5401 | with the default face for display, can be represented in a way that's | 5406 | with 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: | |||
| 6222 | static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, | 6222 | static 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. */ |
| 6226 | static Lisp_Object tip_frame; | 6226 | static 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) | |||
| 1563 | static void | 1563 | static void |
| 1564 | x_set_mouse_face_gc (struct glyph_string *s) | 1564 | x_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 | ||
| 4063 | static ATTRIBUTE_UNUSED void | 4036 | MAYBE_UNUSED static void |
| 4064 | x_clear_area1 (Display *dpy, Window window, | 4037 | x_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 | ||
| 4595 | static struct frame * | 4664 | static struct frame * |
| 4596 | x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) | 4665 | x_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 | ||
| 5026 | static int | 5102 | int |
| 5027 | x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) | 5103 | x_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 *); | |||
| 1108 | extern int x_dispatch_event (XEvent *, Display *); | 1108 | extern int x_dispatch_event (XEvent *, Display *); |
| 1109 | #endif | 1109 | #endif |
| 1110 | extern int x_x_to_emacs_modifiers (struct x_display_info *, int); | 1110 | extern int x_x_to_emacs_modifiers (struct x_display_info *, int); |
| 1111 | extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t); | ||
| 1111 | #ifdef USE_CAIRO | 1112 | #ifdef USE_CAIRO |
| 1112 | extern void x_cr_destroy_frame_context (struct frame *); | 1113 | extern void x_cr_destroy_frame_context (struct frame *); |
| 1113 | extern void x_cr_update_surface_desired_size (struct frame *, int, int); | 1114 | extern 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 | ||
| 45 | static Lisp_Object id_to_xwidget_map; | ||
| 46 | static uint32_t xwidget_counter = 0; | ||
| 47 | |||
| 48 | #ifdef USE_GTK | ||
| 49 | static Lisp_Object x_window_to_xwv_map; | ||
| 50 | static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); | ||
| 51 | static void synthesize_focus_in_event (GtkWidget *); | ||
| 52 | static GdkDevice *find_suitable_keyboard (struct frame *); | ||
| 53 | static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *, | ||
| 54 | gpointer); | ||
| 55 | static void record_osr_embedder (struct xwidget_view *); | ||
| 56 | static void from_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer); | ||
| 57 | static void to_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer); | ||
| 58 | #endif | ||
| 59 | |||
| 42 | static struct xwidget * | 60 | static struct xwidget * |
| 43 | allocate_xwidget (void) | 61 | allocate_xwidget (void) |
| 44 | { | 62 | { |
| @@ -64,18 +82,32 @@ static void webkit_javascript_finished_cb (GObject *, | |||
| 64 | GAsyncResult *, | 82 | GAsyncResult *, |
| 65 | gpointer); | 83 | gpointer); |
| 66 | static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); | 84 | static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); |
| 67 | 85 | static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer); | |
| 68 | static gboolean | 86 | static gboolean |
| 69 | webkit_decide_policy_cb (WebKitWebView *, | 87 | webkit_decide_policy_cb (WebKitWebView *, |
| 70 | WebKitPolicyDecision *, | 88 | WebKitPolicyDecision *, |
| 71 | WebKitPolicyDecisionType, | 89 | WebKitPolicyDecisionType, |
| 72 | gpointer); | 90 | gpointer); |
| 91 | static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); | ||
| 92 | |||
| 93 | struct widget_search_data | ||
| 94 | { | ||
| 95 | int x; | ||
| 96 | int y; | ||
| 97 | bool foundp; | ||
| 98 | bool first; | ||
| 99 | GtkWidget *data; | ||
| 100 | }; | ||
| 101 | |||
| 102 | static void find_widget (GtkWidget *t, struct widget_search_data *); | ||
| 103 | static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, | ||
| 104 | gpointer); | ||
| 73 | #endif | 105 | #endif |
| 74 | 106 | ||
| 75 | 107 | ||
| 76 | DEFUN ("make-xwidget", | 108 | DEFUN ("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. |
| 80 | If BUFFER is nil, use the current buffer. | 112 | If BUFFER is nil, use the current buffer. |
| 81 | If BUFFER is a string and no such buffer exists, create it. | 113 | If 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 | ||
| 86 | Returns the newly constructed xwidget, or nil if construction fails. */) | 118 | RELATED is nil, or an xwidget. When constructing a WebKit widget, it |
| 119 | will share the same settings and internal subprocess as RELATED. | ||
| 120 | Returns the newly constructed xwidget, or nil if construction | ||
| 121 | fails. */) | ||
| 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 | ||
| 280 | static void | ||
| 281 | set_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 | |||
| 290 | DEFUN ("xwidget-perform-lispy-event", | ||
| 291 | Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event, | ||
| 292 | 2, 3, 0, doc: /* Send a lispy event to XWIDGET. | ||
| 293 | EVENT should be the event that will be sent. FRAME should be the | ||
| 294 | frame which generated the event, and defaults to the selected frame. | ||
| 295 | On X11, modifier keys will not be processed if FRAME is nil and the | ||
| 296 | selected 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 | |||
| 197 | DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, | 429 | DEFUN ("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 | ||
| 460 | struct xwidget * | ||
| 461 | xwidget_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 |
| 229 | static void | 473 | static void |
| 474 | record_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 | |||
| 488 | static struct xwidget * | ||
| 489 | find_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 | |||
| 510 | static void | ||
| 511 | from_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 | |||
| 542 | static void | ||
| 543 | to_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 | |||
| 574 | static GdkDevice * | ||
| 575 | find_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 | |||
| 586 | static GdkDevice * | ||
| 587 | find_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 | |||
| 598 | static void | ||
| 599 | find_widget_cb (GtkWidget *widget, void *user) | ||
| 600 | { | ||
| 601 | find_widget (widget, user); | ||
| 602 | } | ||
| 603 | |||
| 604 | static void | ||
| 605 | find_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 | |||
| 695 | static GtkWidget * | ||
| 696 | find_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 | |||
| 721 | static Emacs_Cursor | ||
| 722 | cursor_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 | |||
| 740 | static void | ||
| 741 | define_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 | |||
| 764 | static void | ||
| 765 | mouse_target_changed (WebKitWebView *webview, | ||
| 766 | WebKitHitTestResult *hitresult, | ||
| 767 | guint modifiers, gpointer xw) | ||
| 768 | { | ||
| 769 | define_cursors (xw, hitresult); | ||
| 770 | } | ||
| 771 | |||
| 772 | |||
| 773 | static void | ||
| 774 | xwidget_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 | |||
| 808 | void | ||
| 809 | xwidget_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 | |||
| 860 | void | ||
| 861 | xwidget_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 | |||
| 913 | static void | ||
| 914 | synthesize_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 | |||
| 938 | struct xwidget_view * | ||
| 939 | xwidget_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 | |||
| 950 | static void | ||
| 230 | xwidget_show_view (struct xwidget_view *xv) | 951 | xwidget_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 | |||
| 242 | xwidget_hide_view (struct xwidget_view *xv) | 963 | xwidget_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 | |||
| 970 | static void | ||
| 971 | xv_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. */ |
| 251 | static gboolean | 994 | static gboolean |
| 252 | offscreen_damage_event (GtkWidget *widget, GdkEvent *event, | 995 | offscreen_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 | |||
| 1017 | void | ||
| 1018 | xwidget_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 | ||
| 269 | void | 1026 | void |
| @@ -317,22 +1074,108 @@ store_xwidget_js_callback_event (struct xwidget *xw, | |||
| 317 | 1074 | ||
| 318 | 1075 | ||
| 319 | #ifdef USE_GTK | 1076 | #ifdef USE_GTK |
| 1077 | static void | ||
| 1078 | store_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 | |||
| 1091 | static void | ||
| 1092 | webkit_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 | |||
| 1111 | static GtkWidget * | ||
| 1112 | webkit_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 | |||
| 1136 | static GtkWidget * | ||
| 1137 | webkit_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 | |||
| 320 | void | 1156 | void |
| 321 | webkit_view_load_changed_cb (WebKitWebView *webkitwebview, | 1157 | webkit_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. */ | ||
| 508 | static gboolean | 1376 | static gboolean |
| 509 | xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) | 1377 | webkit_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 | ||
| 526 | static gboolean | 1422 | if (type == WEBKIT_SCRIPT_DIALOG_PROMPT) |
| 527 | xwidget_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 | ||
| 548 | static gboolean | 1438 | if (type == WEBKIT_SCRIPT_DIALOG_PROMPT) |
| 549 | xwidget_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 | ||
| 782 | static bool | 1671 | static bool |
| @@ -852,21 +1741,32 @@ DEFUN ("xwidget-webkit-goto-uri", | |||
| 852 | DEFUN ("xwidget-webkit-goto-history", | 1741 | DEFUN ("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 | |||
| 1746 | If REL-POS is 0, the widget will be just reload the current element in | ||
| 1747 | history. If REL-POS is more or less than 0, the widget will load the | ||
| 1748 | REL-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 | ||
| 2075 | DEFUN ("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 | |||
| 1165 | DEFUN ("set-xwidget-plist", | 2088 | DEFUN ("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 | ||
| 2126 | DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search, | ||
| 2127 | 2, 5, 0, | ||
| 2128 | doc: /* Begin an incremental search operation in an xwidget. | ||
| 2129 | QUERY should be a string containing the text to search for. XWIDGET | ||
| 2130 | should be a WebKit xwidget where the search will take place. When the | ||
| 2131 | search operation is complete, callers should also call | ||
| 2132 | `xwidget-webkit-finish-search' to complete the search operation. | ||
| 2133 | |||
| 2134 | CASE-INSENSITIVE, when non-nil, will cause the search to ignore the | ||
| 2135 | case of characters inside QUERY. BACKWARDS, when non-nil, will cause | ||
| 2136 | the search to proceed towards the beginning of the widget's contents. | ||
| 2137 | WRAP-AROUND, when nil, will cause the search to stop upon hitting the | ||
| 2138 | end of the widget's contents. | ||
| 2139 | |||
| 2140 | It is OK to call this function even when a search is already in | ||
| 2141 | progress. In that case, the previous search query will be replaced | ||
| 2142 | with 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 | |||
| 2184 | DEFUN ("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 | |||
| 2188 | XWIDGET should be an xwidget that currently has a search query. | ||
| 2189 | Before calling this function, you should start a search operation | ||
| 2190 | using `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 | |||
| 2216 | DEFUN ("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 | |||
| 2220 | XWIDGET should be an xwidget that currently has a search query. | ||
| 2221 | Before calling this function, you should start a search operation | ||
| 2222 | using `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 | |||
| 2248 | DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search, | ||
| 2249 | Sxwidget_webkit_finish_search, 1, 1, 0, | ||
| 2250 | doc: /* Finish XWIDGET's search operation. | ||
| 2251 | |||
| 2252 | XWIDGET should be an xwidget that currently has a search query. | ||
| 2253 | Before calling this function, you should start a search operation | ||
| 2254 | using `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 | |||
| 1203 | void | 2286 | void |
| 1204 | syms_of_xwidget (void) | 2287 | syms_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 | ||
| 2543 | void | ||
| 2544 | kill_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. */ |
| 1445 | void | 2562 | void |
| 1446 | kill_buffer_xwidgets (Lisp_Object buffer) | 2563 | kill_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, | |||
| 162 | void store_xwidget_js_callback_event (struct xwidget *xw, | 173 | void 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 | |||
| 177 | extern struct xwidget *xwidget_from_id (uint32_t id); | ||
| 178 | |||
| 179 | #ifdef HAVE_X_WINDOWS | ||
| 180 | struct xwidget_view *xwidget_view_from_window (Window wdesc); | ||
| 181 | void xwidget_expose (struct xwidget_view *xv); | ||
| 182 | extern void kill_frame_xwidget_views (struct frame *f); | ||
| 183 | extern void xwidget_button (struct xwidget_view *, bool, int, | ||
| 184 | int, int, int, Time); | ||
| 185 | extern void xwidget_motion_or_crossing (struct xwidget_view *, | ||
| 186 | const XEvent *); | ||
| 187 | #endif | ||
| 165 | #else | 188 | #else |
| 166 | INLINE_HEADER_BEGIN | 189 | INLINE_HEADER_BEGIN |
| 167 | INLINE void syms_of_xwidget (void) {} | 190 | INLINE void syms_of_xwidget (void) {} |