diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.gdbinit | 33 | ||||
-rw-r--r-- | src/Makefile.in | 34 | ||||
-rw-r--r-- | src/alloc.c | 150 | ||||
-rw-r--r-- | src/bidi.c | 10 | ||||
-rw-r--r-- | src/buffer.c | 4 | ||||
-rw-r--r-- | src/bytecode.c | 15 | ||||
-rw-r--r-- | src/callint.c | 300 | ||||
-rw-r--r-- | src/character.c | 26 | ||||
-rw-r--r-- | src/character.h | 2 | ||||
-rw-r--r-- | src/cmds.c | 5 | ||||
-rw-r--r-- | src/coding.c | 31 | ||||
-rw-r--r-- | src/coding.h | 27 | ||||
-rw-r--r-- | src/data.c | 22 | ||||
-rw-r--r-- | src/decompress.c | 29 | ||||
-rw-r--r-- | src/dispextern.h | 19 | ||||
-rw-r--r-- | src/dispnew.c | 11 | ||||
-rw-r--r-- | src/doc.c | 42 | ||||
-rw-r--r-- | src/doprnt.c | 2 | ||||
-rw-r--r-- | src/dosfns.c | 6 | ||||
-rw-r--r-- | src/editfns.c | 141 | ||||
-rw-r--r-- | src/emacs-module.c | 42 | ||||
-rw-r--r-- | src/emacs.c | 20 | ||||
-rw-r--r-- | src/eval.c | 73 | ||||
-rw-r--r-- | src/fileio.c | 113 | ||||
-rw-r--r-- | src/fns.c | 3 | ||||
-rw-r--r-- | src/frame.c | 66 | ||||
-rw-r--r-- | src/frame.h | 7 | ||||
-rw-r--r-- | src/fringe.c | 5 | ||||
-rw-r--r-- | src/gmalloc.c | 16 | ||||
-rw-r--r-- | src/gtkutil.c | 39 | ||||
-rw-r--r-- | src/json.c | 920 | ||||
-rw-r--r-- | src/keyboard.c | 386 | ||||
-rw-r--r-- | src/keyboard.h | 1 | ||||
-rw-r--r-- | src/kqueue.c | 2 | ||||
-rw-r--r-- | src/lastfile.c | 3 | ||||
-rw-r--r-- | src/lisp.h | 231 | ||||
-rw-r--r-- | src/lread.c | 149 | ||||
-rw-r--r-- | src/macfont.m | 2 | ||||
-rw-r--r-- | src/menu.c | 96 | ||||
-rw-r--r-- | src/menu.h | 1 | ||||
-rw-r--r-- | src/minibuf.c | 14 | ||||
-rw-r--r-- | src/msdos.c | 2 | ||||
-rw-r--r-- | src/nsfns.m | 286 | ||||
-rw-r--r-- | src/nsimage.m | 116 | ||||
-rw-r--r-- | src/nsmenu.m | 12 | ||||
-rw-r--r-- | src/nsselect.m | 8 | ||||
-rw-r--r-- | src/nsterm.h | 12 | ||||
-rw-r--r-- | src/nsterm.m | 477 | ||||
-rw-r--r-- | src/print.c | 62 | ||||
-rw-r--r-- | src/process.c | 136 | ||||
-rw-r--r-- | src/process.h | 2 | ||||
-rw-r--r-- | src/ptr-bounds.h | 79 | ||||
-rw-r--r-- | src/regex.c | 37 | ||||
-rw-r--r-- | src/regex.h | 9 | ||||
-rw-r--r-- | src/sound.c | 5 | ||||
-rw-r--r-- | src/syntax.c | 26 | ||||
-rw-r--r-- | src/sysdep.c | 29 | ||||
-rw-r--r-- | src/syssignal.h | 1 | ||||
-rw-r--r-- | src/systhread.c | 20 | ||||
-rw-r--r-- | src/systhread.h | 1 | ||||
-rw-r--r-- | src/term.c | 14 | ||||
-rw-r--r-- | src/thread.c | 8 | ||||
-rw-r--r-- | src/thread.h | 1 | ||||
-rw-r--r-- | src/tparam.h | 3 | ||||
-rw-r--r-- | src/w16select.c | 39 | ||||
-rw-r--r-- | src/w32cygwinx.c | 140 | ||||
-rw-r--r-- | src/w32fns.c | 513 | ||||
-rw-r--r-- | src/w32menu.c | 2 | ||||
-rw-r--r-- | src/w32notify.c | 9 | ||||
-rw-r--r-- | src/w32reg.c | 8 | ||||
-rw-r--r-- | src/w32select.c | 42 | ||||
-rw-r--r-- | src/w32term.c | 69 | ||||
-rw-r--r-- | src/w32term.h | 2 | ||||
-rw-r--r-- | src/window.h | 9 | ||||
-rw-r--r-- | src/xdisp.c | 233 | ||||
-rw-r--r-- | src/xfaces.c | 8 | ||||
-rw-r--r-- | src/xfns.c | 355 | ||||
-rw-r--r-- | src/xmenu.c | 17 | ||||
-rw-r--r-- | src/xml.c | 37 | ||||
-rw-r--r-- | src/xterm.c | 63 | ||||
-rw-r--r-- | src/xterm.h | 2 | ||||
-rw-r--r-- | src/xwidget.c | 17 |
82 files changed, 3805 insertions, 2204 deletions
diff --git a/src/.gdbinit b/src/.gdbinit index cc06b2e11ce..eb4d57a5fbb 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -49,7 +49,7 @@ define xgetptr else set $bugfix = $arg0 end - set $ptr = $bugfix & VALMASK + set $ptr = (EMACS_INT) $bugfix & VALMASK end define xgetint @@ -58,7 +58,7 @@ define xgetint else set $bugfix = $arg0 end - set $int = $bugfix << (USE_LSB_TAG ? 0 : INTTYPEBITS) >> INTTYPEBITS + set $int = (EMACS_INT) $bugfix << (USE_LSB_TAG ? 0 : INTTYPEBITS) >> INTTYPEBITS end define xgettype @@ -67,7 +67,7 @@ define xgettype else set $bugfix = $arg0 end - set $type = (enum Lisp_Type) (USE_LSB_TAG ? $bugfix & (1 << GCTYPEBITS) - 1 : (EMACS_UINT) $bugfix >> VALBITS) + set $type = (enum Lisp_Type) (USE_LSB_TAG ? (EMACS_INT) $bugfix & (1 << GCTYPEBITS) - 1 : (EMACS_UINT) $bugfix >> VALBITS) end define xgetsym @@ -819,6 +819,7 @@ define xcompiled xgetptr $ print (struct Lisp_Vector *) $ptr output ($->contents[0])@($->header.size & 0xff) + echo \n end document xcompiled Print $ as a compiled function pointer. @@ -1270,6 +1271,12 @@ end python +# Python 3 compatibility. +try: + long +except: + long = int + # Omit pretty-printing in older (pre-7.3) GDBs that lack it. if hasattr(gdb, 'printing'): @@ -1306,13 +1313,13 @@ if hasattr(gdb, 'printing'): # symbol table, guess reasonable defaults. sym = gdb.lookup_symbol ("EMACS_INT_WIDTH")[0] if sym: - EMACS_INT_WIDTH = int (sym.value ()) + EMACS_INT_WIDTH = long (sym.value ()) else: sym = gdb.lookup_symbol ("EMACS_INT")[0] EMACS_INT_WIDTH = 8 * sym.type.sizeof sym = gdb.lookup_symbol ("USE_LSB_TAG")[0] if sym: - USE_LSB_TAG = int (sym.value ()) + USE_LSB_TAG = long (sym.value ()) else: USE_LSB_TAG = 1 @@ -1321,19 +1328,26 @@ if hasattr(gdb, 'printing'): Lisp_Int0 = 2 Lisp_Int1 = 6 if USE_LSB_TAG else 3 - # Unpack the Lisp value from its containing structure, if necessary. val = self.val basic_type = gdb.types.get_basic_type (val.type) + + # Unpack VAL from its containing structure, if necessary. if (basic_type.code == gdb.TYPE_CODE_STRUCT and gdb.types.has_field (basic_type, "i")): val = val["i"] + # Convert VAL to a Python integer. Convert by hand, as this is + # simpler and works regardless of whether VAL is a pointer or + # integer. Also, val.cast (gdb.lookup.type ("EMACS_UINT")) + # would have problems with GDB 7.12.1; see + # <http://patchwork.sourceware.org/patch/11557/>. + ival = long (val) + # For nil, yield "XIL(0)", which is easier to read than "XIL(0x0)". - if not val: + if not ival: return "XIL(0)" # Extract the integer representation of the value and its Lisp type. - ival = int(val) itype = ival >> (0 if USE_LSB_TAG else VALBITS) itype = itype & ((1 << GCTYPEBITS) - 1) @@ -1352,8 +1366,7 @@ if hasattr(gdb, 'printing'): # integers even when Lisp_Object is an integer. # Perhaps some day the pretty-printing could be fancier. # Prefer the unsigned representation to negative values, converting - # by hand as val.cast(gdb.lookup_type("EMACS_UINT") does not work in - # GDB 7.12.1; see <http://patchwork.sourceware.org/patch/11557/>. + # by hand as val.cast does not work in GDB 7.12.1 as noted above. if ival < 0: ival = ival + (1 << EMACS_INT_WIDTH) return "XIL(0x%x)" % ival diff --git a/src/Makefile.in b/src/Makefile.in index 15ca1667d65..1d23425969c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -234,7 +234,8 @@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@ -LIBLCMS2 = @LIBLCMS2@ +LCMS2_LIBS = @LCMS2_LIBS@ +LCMS2_CFLAGS = @LCMS2_CFLAGS@ LIBZ = @LIBZ@ @@ -277,11 +278,12 @@ NS_OBJC_OBJ=@NS_OBJC_OBJ@ ## Used only for GNUstep. GNU_OBJC_CFLAGS=$(patsubst -specs=%-hardened-cc1,,@GNU_OBJC_CFLAGS@) ## w32fns.o w32menu.c w32reg.o fringe.o fontset.o w32font.o w32term.o -## w32xfns.o w32select.o image.o w32uniscribe.o if HAVE_W32, else -## empty. +## w32xfns.o w32select.o image.o w32uniscribe.o w32cygwinx.o if HAVE_W32, +## w32cygwinx.o if CYGWIN but not HAVE_W32, else empty. W32_OBJ=@W32_OBJ@ ## -lkernel32 -luser32 -lusp10 -lgdi32 -lole32 -lcomdlg32 -lcomctl32 -## --lwinspool if HAVE_W32, else empty. +## -lwinspool if HAVE_W32, +## -lkernel32 if CYGWIN but not HAVE_W32, else empty. W32_LIBS=@W32_LIBS@ ## emacs.res if HAVE_W32 @@ -312,6 +314,10 @@ LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ +JSON_LIBS = @JSON_LIBS@ +JSON_CFLAGS = @JSON_CFLAGS@ +JSON_OBJ = @JSON_OBJ@ + INTERVALS_H = dispextern.h intervals.h composite.h GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ @@ -360,10 +366,10 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \ - $(WEBKIT_CFLAGS) \ + $(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \ $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ - $(LIBSYSTEMD_CFLAGS) \ + $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ $(WERROR_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) @@ -397,7 +403,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ thread.o systhread.o \ $(if $(HYBRID_MALLOC),sheap.o) \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ - $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) + $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) obj = $(base_obj) $(NS_OBJC_OBJ) ## Object files used on some machine or other. @@ -408,7 +414,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \ xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ fontset.o dbusbind.o cygw32.o \ nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o macfont.o \ - w32.o w32console.o w32fns.o w32heap.o w32inevt.o w32notify.o \ + w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \ xsettings.o xgselect.o termcap.o @@ -436,6 +442,10 @@ otherobj= $(TERMCAP_OBJ) $(PRE_ALLOC_OBJ) $(GMALLOC_OBJ) $(RALLOC_OBJ) \ FIRSTFILE_OBJ=@FIRSTFILE_OBJ@ ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj) +# Must be first, before dep inclusion! +all: emacs$(EXEEXT) $(OTHER_FILES) +.PHONY: all + AUTO_DEPEND = @AUTO_DEPEND@ DEPDIR = deps ifeq ($(AUTO_DEPEND),yes) @@ -446,9 +456,6 @@ else include $(srcdir)/deps.mk endif -all: emacs$(EXEEXT) $(OTHER_FILES) -.PHONY: all - ## This is the list of all Lisp files that might be loaded into the ## dumped Emacs. Some of them are not loaded on all platforms, but ## the DOC file on every platform uses them (because the DOC file is @@ -492,8 +499,9 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ - $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LIBLCMS2) \ - $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) + $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ + $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ + $(JSON_LIBS) ## FORCE it so that admin/unidata can decide whether these files ## are up-to-date. Although since charprop depends on bootstrap-emacs, diff --git a/src/alloc.c b/src/alloc.c index 9d0e2d37e3c..f97b99c0f31 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -33,6 +33,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "lisp.h" #include "dispextern.h" #include "intervals.h" +#include "ptr-bounds.h" #include "puresize.h" #include "sheap.h" #include "systime.h" @@ -502,38 +503,27 @@ pointer_align (void *ptr, int alignment) return (void *) ROUNDUP ((uintptr_t) ptr, alignment); } -/* Extract the pointer hidden within A, if A is not a symbol. - If A is a symbol, extract the hidden pointer's offset from lispsym, - converted to void *. */ +/* Extract the pointer hidden within O. Define this as a function, as + functions are cleaner and can be used in debuggers. Also, define + it as a macro if being compiled with GCC without optimization, for + performance in that case. macro_XPNTR is private to this section + of code. */ -#define macro_XPNTR_OR_SYMBOL_OFFSET(a) \ - ((void *) (intptr_t) (USE_LSB_TAG ? XLI (a) - XTYPE (a) : XLI (a) & VALMASK)) - -/* Extract the pointer hidden within A. */ - -#define macro_XPNTR(a) \ - ((void *) ((intptr_t) XPNTR_OR_SYMBOL_OFFSET (a) \ - + (SYMBOLP (a) ? (char *) lispsym : NULL))) - -/* For pointer access, define XPNTR and XPNTR_OR_SYMBOL_OFFSET as - functions, as functions are cleaner and can be used in debuggers. - Also, define them as macros if being compiled with GCC without - optimization, for performance in that case. The macro_* names are - private to this section of code. */ +#define macro_XPNTR(o) \ + ((void *) \ + (SYMBOLP (o) \ + ? ((char *) lispsym \ + - ((EMACS_UINT) Lisp_Symbol << (USE_LSB_TAG ? 0 : VALBITS)) \ + + XLI (o)) \ + : (char *) XLP (o) - (XLI (o) & ~VALMASK))) static ATTRIBUTE_UNUSED void * -XPNTR_OR_SYMBOL_OFFSET (Lisp_Object a) -{ - return macro_XPNTR_OR_SYMBOL_OFFSET (a); -} -static ATTRIBUTE_UNUSED void * XPNTR (Lisp_Object a) { return macro_XPNTR (a); } #if DEFINE_KEY_OPS_AS_MACROS -# define XPNTR_OR_SYMBOL_OFFSET(a) macro_XPNTR_OR_SYMBOL_OFFSET (a) # define XPNTR(a) macro_XPNTR (a) #endif @@ -1737,7 +1727,8 @@ static EMACS_INT total_string_bytes; a pointer to the `u.data' member of its sdata structure; the structure starts at a constant offset in front of that. */ -#define SDATA_OF_STRING(S) ((sdata *) ((S)->u.s.data - SDATA_DATA_OFFSET)) +#define SDATA_OF_STRING(S) ((sdata *) ptr_bounds_init ((S)->u.s.data \ + - SDATA_DATA_OFFSET)) #ifdef GC_CHECK_STRING_OVERRUN @@ -1929,7 +1920,7 @@ allocate_string (void) /* Every string on a free list should have NULL data pointer. */ s->u.s.data = NULL; NEXT_FREE_LISP_STRING (s) = string_free_list; - string_free_list = s; + string_free_list = ptr_bounds_clip (s, sizeof *s); } total_free_strings += STRING_BLOCK_SIZE; @@ -2044,7 +2035,7 @@ allocate_string_data (struct Lisp_String *s, MALLOC_UNBLOCK_INPUT; - s->u.s.data = SDATA_DATA (data); + s->u.s.data = ptr_bounds_clip (SDATA_DATA (data), nbytes + 1); #ifdef GC_CHECK_STRING_BYTES SDATA_NBYTES (data) = nbytes; #endif @@ -2130,7 +2121,7 @@ sweep_strings (void) /* Put the string on the free-list. */ NEXT_FREE_LISP_STRING (s) = string_free_list; - string_free_list = s; + string_free_list = ptr_bounds_clip (s, sizeof *s); ++nfree; } } @@ -2138,7 +2129,7 @@ sweep_strings (void) { /* S was on the free-list before. Put it there again. */ NEXT_FREE_LISP_STRING (s) = string_free_list; - string_free_list = s; + string_free_list = ptr_bounds_clip (s, sizeof *s); ++nfree; } } @@ -2234,9 +2225,9 @@ compact_small_strings (void) nbytes = s ? STRING_BYTES (s) : SDATA_NBYTES (from); eassert (nbytes <= LARGE_STRING_BYTES); - nbytes = SDATA_SIZE (nbytes); + ptrdiff_t size = SDATA_SIZE (nbytes); sdata *from_end = (sdata *) ((char *) from - + nbytes + GC_STRING_EXTRA); + + size + GC_STRING_EXTRA); #ifdef GC_CHECK_STRING_OVERRUN if (memcmp (string_overrun_cookie, @@ -2250,22 +2241,23 @@ compact_small_strings (void) { /* If TB is full, proceed with the next sblock. */ sdata *to_end = (sdata *) ((char *) to - + nbytes + GC_STRING_EXTRA); + + size + GC_STRING_EXTRA); if (to_end > tb_end) { tb->next_free = to; tb = tb->next; tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE); to = tb->data; - to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA); + to_end = (sdata *) ((char *) to + size + GC_STRING_EXTRA); } /* Copy, and update the string's `data' pointer. */ if (from != to) { eassert (tb != b || to < from); - memmove (to, from, nbytes + GC_STRING_EXTRA); - to->string->u.s.data = SDATA_DATA (to); + memmove (to, from, size + GC_STRING_EXTRA); + to->string->u.s.data + = ptr_bounds_clip (SDATA_DATA (to), nbytes + 1); } /* Advance past the sdata we copied to. */ @@ -2299,11 +2291,13 @@ string_overflow (void) error ("Maximum string size exceeded"); } -DEFUN ("make-string", Fmake_string, Smake_string, 2, 2, 0, +DEFUN ("make-string", Fmake_string, Smake_string, 2, 3, 0, doc: /* Return a newly created string of length LENGTH, with INIT in each element. LENGTH must be an integer. -INIT must be an integer that represents a character. */) - (Lisp_Object length, Lisp_Object init) +INIT must be an integer that represents a character. +If optional argument MULTIBYTE is non-nil, the result will be +a multibyte string even if INIT is an ASCII character. */) + (Lisp_Object length, Lisp_Object init, Lisp_Object multibyte) { register Lisp_Object val; int c; @@ -2313,7 +2307,7 @@ INIT must be an integer that represents a character. */) CHECK_CHARACTER (init); c = XFASTINT (init); - if (ASCII_CHAR_P (c)) + if (ASCII_CHAR_P (c) && NILP (multibyte)) { nbytes = XINT (length); val = make_uninit_string (nbytes); @@ -3046,6 +3040,7 @@ static EMACS_INT total_vector_slots, total_free_vector_slots; static void setup_on_free_list (struct Lisp_Vector *v, ptrdiff_t nbytes) { + v = ptr_bounds_clip (v, nbytes); eassume (header_size <= nbytes); ptrdiff_t nwords = (nbytes - header_size) / word_size; XSETPVECTYPESIZE (v, PVEC_FREE, 0, nwords); @@ -3315,15 +3310,14 @@ sweep_vectors (void) static struct Lisp_Vector * allocate_vectorlike (ptrdiff_t len) { - struct Lisp_Vector *p; - - MALLOC_BLOCK_INPUT; - if (len == 0) - p = XVECTOR (zero_vector); + return XVECTOR (zero_vector); else { size_t nbytes = header_size + len * word_size; + struct Lisp_Vector *p; + + MALLOC_BLOCK_INPUT; #ifdef DOUG_LEA_MALLOC if (!mmap_lisp_allowed_p ()) @@ -3353,11 +3347,11 @@ allocate_vectorlike (ptrdiff_t len) consing_since_gc += nbytes; vector_cells_consed += len; - } - MALLOC_UNBLOCK_INPUT; + MALLOC_UNBLOCK_INPUT; - return p; + return ptr_bounds_clip (p, nbytes); + } } @@ -3667,7 +3661,7 @@ struct marker_block static struct marker_block *marker_block; static int marker_block_index = MARKER_BLOCK_SIZE; -static union Lisp_Misc *marker_free_list; +static union Lisp_Misc *misc_free_list; /* Return a newly allocated Lisp_Misc object of specified TYPE. */ @@ -3678,10 +3672,10 @@ allocate_misc (enum Lisp_Misc_Type type) MALLOC_BLOCK_INPUT; - if (marker_free_list) + if (misc_free_list) { - XSETMISC (val, marker_free_list); - marker_free_list = marker_free_list->u_free.chain; + XSETMISC (val, misc_free_list); + misc_free_list = misc_free_list->u_free.chain; } else { @@ -3713,8 +3707,8 @@ void free_misc (Lisp_Object misc) { XMISCANY (misc)->type = Lisp_Misc_Free; - XMISC (misc)->u_free.chain = marker_free_list; - marker_free_list = XMISC (misc); + XMISC (misc)->u_free.chain = misc_free_list; + misc_free_list = XMISC (misc); consing_since_gc -= sizeof (union Lisp_Misc); total_free_markers++; } @@ -3918,7 +3912,7 @@ make_event_array (ptrdiff_t nargs, Lisp_Object *args) { Lisp_Object result; - result = Fmake_string (make_number (nargs), make_number (0)); + result = Fmake_string (make_number (nargs), make_number (0), Qnil); for (i = 0; i < nargs; i++) { SSET (result, i, XINT (args[i])); @@ -4574,6 +4568,7 @@ live_string_holding (struct mem_node *m, void *p) must not be on the free-list. */ if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0]) { + cp = ptr_bounds_copy (cp, b); struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0]; if (s->u.s.data) return make_lisp_ptr (s, Lisp_String); @@ -4608,6 +4603,7 @@ live_cons_holding (struct mem_node *m, void *p) && (b != cons_block || offset / sizeof b->conses[0] < cons_block_index)) { + cp = ptr_bounds_copy (cp, b); struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0]; if (!EQ (s->u.s.car, Vdead)) return make_lisp_ptr (s, Lisp_Cons); @@ -4643,6 +4639,7 @@ live_symbol_holding (struct mem_node *m, void *p) && (b != symbol_block || offset / sizeof b->symbols[0] < symbol_block_index)) { + cp = ptr_bounds_copy (cp, b); struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0]; if (!EQ (s->u.s.function, Vdead)) return make_lisp_symbol (s); @@ -4702,6 +4699,7 @@ live_misc_holding (struct mem_node *m, void *p) && (b != marker_block || offset / sizeof b->markers[0] < marker_block_index)) { + cp = ptr_bounds_copy (cp, b); union Lisp_Misc *s = p = cp -= offset % sizeof b->markers[0]; if (s->u_any.type != Lisp_Misc_Free) return make_lisp_ptr (s, Lisp_Misc); @@ -5363,7 +5361,7 @@ pure_alloc (size_t size, int type) pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp; if (pure_bytes_used <= pure_size) - return result; + return ptr_bounds_clip (result, size); /* Don't allocate a large amount here, because it might get mmap'd and then its address @@ -5448,7 +5446,7 @@ find_string_data_in_pure (const char *data, ptrdiff_t nbytes) /* Check the remaining characters. */ if (memcmp (data, non_lisp_beg + start, nbytes) == 0) /* Found. */ - return non_lisp_beg + start; + return ptr_bounds_clip (non_lisp_beg + start, nbytes + 1); start += last_char_skip; } @@ -5604,7 +5602,7 @@ static Lisp_Object purecopy (Lisp_Object obj) { if (INTEGERP (obj) - || (! SYMBOLP (obj) && PURE_P (XPNTR_OR_SYMBOL_OFFSET (obj))) + || (! SYMBOLP (obj) && PURE_P (XPNTR (obj))) || SUBRP (obj)) return obj; /* Already pure. */ @@ -5965,6 +5963,7 @@ garbage_collect_1 (void *end) stack_copy = xrealloc (stack_copy, stack_size); stack_copy_size = stack_size; } + stack = ptr_bounds_set (stack, stack_size); no_sanitize_memcpy (stack_copy, stack, stack_size); } } @@ -6858,7 +6857,9 @@ sweep_conses (void) for (pos = start; pos < stop; pos++) { - if (!CONS_MARKED_P (&cblk->conses[pos])) + struct Lisp_Cons *acons + = ptr_bounds_copy (&cblk->conses[pos], cblk); + if (!CONS_MARKED_P (acons)) { this_free++; cblk->conses[pos].u.s.u.chain = cons_free_list; @@ -6868,7 +6869,7 @@ sweep_conses (void) else { num_used++; - CONS_UNMARK (&cblk->conses[pos]); + CONS_UNMARK (acons); } } } @@ -6911,17 +6912,20 @@ sweep_floats (void) register int i; int this_free = 0; for (i = 0; i < lim; i++) - if (!FLOAT_MARKED_P (&fblk->floats[i])) - { - this_free++; - fblk->floats[i].u.chain = float_free_list; - float_free_list = &fblk->floats[i]; - } - else - { - num_used++; - FLOAT_UNMARK (&fblk->floats[i]); - } + { + struct Lisp_Float *afloat = ptr_bounds_copy (&fblk->floats[i], fblk); + if (!FLOAT_MARKED_P (afloat)) + { + this_free++; + fblk->floats[i].u.chain = float_free_list; + float_free_list = &fblk->floats[i]; + } + else + { + num_used++; + FLOAT_UNMARK (afloat); + } + } lim = FLOAT_BLOCK_SIZE; /* If this block contains only free floats and we have already seen more than two blocks worth of free floats then deallocate @@ -7075,7 +7079,7 @@ sweep_misc (void) /* Put all unmarked misc's on free list. For a marker, first unchain it from the buffer it points into. */ - marker_free_list = 0; + misc_free_list = 0; for (mblk = marker_block; mblk; mblk = *mprev) { @@ -7102,8 +7106,8 @@ sweep_misc (void) We could leave the type alone, since nobody checks it, but this might catch bugs faster. */ mblk->markers[i].m.u_marker.type = Lisp_Misc_Free; - mblk->markers[i].m.u_free.chain = marker_free_list; - marker_free_list = &mblk->markers[i].m; + mblk->markers[i].m.u_free.chain = misc_free_list; + misc_free_list = &mblk->markers[i].m; this_free++; } else @@ -7120,7 +7124,7 @@ sweep_misc (void) { *mprev = mblk->next; /* Unhook from the free list. */ - marker_free_list = mblk->markers[0].m.u_free.chain; + misc_free_list = mblk->markers[0].m.u_free.chain; lisp_free (mblk); } else diff --git a/src/bidi.c b/src/bidi.c index 1f05a1f7d51..9bc8dbe8603 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -1,6 +1,8 @@ /* Low-level bidirectional buffer/string-scanning functions for GNU Emacs. - Copyright (C) 2000-2001, 2004-2005, 2009-2018 Free Software - Foundation, Inc. + +Copyright (C) 2000-2001, 2004-2005, 2009-2018 Free Software Foundation, Inc. + +Author: Eli Zaretskii <eliz@gnu.org> This file is part of GNU Emacs. @@ -17,9 +19,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ -/* Written by Eli Zaretskii <eliz@gnu.org>. - - A sequential implementation of the Unicode Bidirectional algorithm, +/* A sequential implementation of the Unicode Bidirectional algorithm, (UBA) as per UAX#9, a part of the Unicode Standard. Unlike the Reference Implementation and most other implementations, diff --git a/src/buffer.c b/src/buffer.c index 9b54e4b7787..f8c57a74b4e 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5144,7 +5144,9 @@ init_buffer_once (void) XSETFASTINT (BVAR (&buffer_local_flags, selective_display), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, selective_display_ellipses), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, tab_width), idx); ++idx; - XSETFASTINT (BVAR (&buffer_local_flags, truncate_lines), idx); ++idx; + XSETFASTINT (BVAR (&buffer_local_flags, truncate_lines), idx); + /* Make this one a permanent local. */ + buffer_permanent_local_flags[idx++] = 1; XSETFASTINT (BVAR (&buffer_local_flags, word_wrap), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, ctl_arrow), idx); ++idx; XSETFASTINT (BVAR (&buffer_local_flags, fill_column), idx); ++idx; diff --git a/src/bytecode.c b/src/bytecode.c index e51f9095b36..55b193ffb2f 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "character.h" #include "buffer.h" #include "keyboard.h" +#include "ptr-bounds.h" #include "syntax.h" #include "window.h" @@ -363,13 +364,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, unsigned char quitcounter = 1; EMACS_INT stack_items = XFASTINT (maxdepth) + 1; USE_SAFE_ALLOCA; - Lisp_Object *stack_base; - SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length); - Lisp_Object *stack_lim = stack_base + stack_items; + void *alloc; + SAFE_ALLOCA_LISP_EXTRA (alloc, stack_items, bytestr_length); + ptrdiff_t item_bytes = stack_items * word_size; + Lisp_Object *stack_base = ptr_bounds_clip (alloc, item_bytes); Lisp_Object *top = stack_base; - memcpy (stack_lim, SDATA (bytestr), bytestr_length); - void *void_stack_lim = stack_lim; - unsigned char const *bytestr_data = void_stack_lim; + Lisp_Object *stack_lim = stack_base + stack_items; + unsigned char *bytestr_data = alloc; + bytestr_data = ptr_bounds_clip (bytestr_data + item_bytes, bytestr_length); + memcpy (bytestr_data, SDATA (bytestr), bytestr_length); unsigned char const *pc = bytestr_data; ptrdiff_t count = SPECPDL_INDEX (); diff --git a/src/callint.c b/src/callint.c index e4491e9085a..08a8bba4646 100644 --- a/src/callint.c +++ b/src/callint.c @@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> #include "lisp.h" +#include "ptr-bounds.h" #include "character.h" #include "buffer.h" #include "keyboard.h" @@ -270,44 +271,16 @@ invoke it. If KEYS is omitted or nil, the return value of `this-command-keys-vector' is used. */) (Lisp_Object function, Lisp_Object record_flag, Lisp_Object keys) { - /* `args' will contain the array of arguments to pass to the function. - `visargs' will contain the same list but in a nicer form, so that if we - pass it to Fformat_message it will be understandable to a human. */ - Lisp_Object *args, *visargs; - Lisp_Object specs; - Lisp_Object filter_specs; - Lisp_Object teml; - Lisp_Object up_event; - Lisp_Object enable; - USE_SAFE_ALLOCA; ptrdiff_t speccount = SPECPDL_INDEX (); - /* The index of the next element of this_command_keys to examine for - the 'e' interactive code. */ - ptrdiff_t next_event; - - Lisp_Object prefix_arg; - char *string; - const char *tem; - - /* If varies[i] > 0, the i'th argument shouldn't just have its value - in this call quoted in the command history. It should be - recorded as a call to the function named callint_argfuns[varies[i]]. */ - signed char *varies; - - ptrdiff_t i, nargs; - ptrdiff_t mark; - bool arg_from_tty = 0; + bool arg_from_tty = false; ptrdiff_t key_count; - bool record_then_fail = 0; - - Lisp_Object save_this_command, save_last_command; - Lisp_Object save_this_original_command, save_real_this_command; + bool record_then_fail = false; - save_this_command = Vthis_command; - save_this_original_command = Vthis_original_command; - save_real_this_command = Vreal_this_command; - save_last_command = KVAR (current_kboard, Vlast_command); + Lisp_Object save_this_command = Vthis_command; + Lisp_Object save_this_original_command = Vthis_original_command; + Lisp_Object save_real_this_command = Vreal_this_command; + Lisp_Object save_last_command = KVAR (current_kboard, Vlast_command); if (NILP (keys)) keys = this_command_keys, key_count = this_command_key_count; @@ -318,55 +291,44 @@ invoke it. If KEYS is omitted or nil, the return value of } /* Save this now, since use of minibuffer will clobber it. */ - prefix_arg = Vcurrent_prefix_arg; + Lisp_Object prefix_arg = Vcurrent_prefix_arg; - if (SYMBOLP (function)) - enable = Fget (function, Qenable_recursive_minibuffers); - else - enable = Qnil; - - specs = Qnil; - string = 0; - /* The idea of FILTER_SPECS is to provide a way to - specify how to represent the arguments in command history. - The feature is not fully implemented. */ - filter_specs = Qnil; + Lisp_Object enable = (SYMBOLP (function) + ? Fget (function, Qenable_recursive_minibuffers) + : Qnil); /* If k or K discard an up-event, save it here so it can be retrieved with U. */ - up_event = Qnil; + Lisp_Object up_event = Qnil; /* Set SPECS to the interactive form, or barf if not interactive. */ - { - Lisp_Object form; - form = Finteractive_form (function); - if (CONSP (form)) - specs = filter_specs = Fcar (XCDR (form)); - else - wrong_type_argument (Qcommandp, function); - } + Lisp_Object form = Finteractive_form (function); + if (! CONSP (form)) + wrong_type_argument (Qcommandp, function); + Lisp_Object specs = Fcar (XCDR (form)); + + /* At this point the value of SPECS could help provide a way to + specify how to represent the arguments in command history. + The feature is not fully implemented. */ /* If SPECS is not a string, invent one. */ if (! STRINGP (specs)) { - Lisp_Object input; Lisp_Object funval = Findirect_function (function, Qt); uintmax_t events = num_input_events; - input = specs; + Lisp_Object input = specs; /* Compute the arg values using the user's expression. */ specs = Feval (specs, CONSP (funval) && EQ (Qclosure, XCAR (funval)) ? CAR_SAFE (XCDR (funval)) : Qnil); if (events != num_input_events || !NILP (record_flag)) { - /* We should record this command on the command history. */ - Lisp_Object values; - Lisp_Object this_cmd; - /* Make a copy of the list of values, for the command history, + /* We should record this command on the command history. + Make a copy of the list of values, for the command history, and turn them into things we can eval. */ - values = quotify_args (Fcopy_sequence (specs)); + Lisp_Object values = quotify_args (Fcopy_sequence (specs)); fix_command (input, values); - this_cmd = Fcons (function, values); + Lisp_Object this_cmd = Fcons (function, values); if (history_delete_duplicates) Vcommand_history = Fdelete (this_cmd, Vcommand_history); Vcommand_history = Fcons (this_cmd, Vcommand_history); @@ -374,7 +336,7 @@ invoke it. If KEYS is omitted or nil, the return value of /* Don't keep command history around forever. */ if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0) { - teml = Fnthcdr (Vhistory_length, Vcommand_history); + Lisp_Object teml = Fnthcdr (Vhistory_length, Vcommand_history); if (CONSP (teml)) XSETCDR (teml, Qnil); } @@ -385,46 +347,42 @@ invoke it. If KEYS is omitted or nil, the return value of Vreal_this_command = save_real_this_command; kset_last_command (current_kboard, save_last_command); - Lisp_Object result - = unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively, - function, specs)); - SAFE_FREE (); - return result; + return unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively, + function, specs)); } /* SPECS is set to a string; use it as an interactive prompt. Copy it so that STRING will be valid even if a GC relocates SPECS. */ - SAFE_ALLOCA_STRING (string, specs); - - /* Here if function specifies a string to control parsing the defaults. */ + USE_SAFE_ALLOCA; + ptrdiff_t string_len = SBYTES (specs); + char *string = SAFE_ALLOCA (string_len + 1); + memcpy (string, SDATA (specs), string_len + 1); + char *string_end = string + string_len; - /* Set next_event to point to the first event with parameters. */ + /* The index of the next element of this_command_keys to examine for + the 'e' interactive code. Initialize it to point to the first + event with parameters. */ + ptrdiff_t next_event; for (next_event = 0; next_event < key_count; next_event++) if (EVENT_HAS_PARAMETERS (AREF (keys, next_event))) break; /* Handle special starting chars `*' and `@'. Also `-'. */ /* Note that `+' is reserved for user extensions. */ - while (1) + for (;; string++) { if (*string == '+') error ("`+' is not used in `interactive' for ordinary commands"); else if (*string == '*') { - string++; if (!NILP (BVAR (current_buffer, read_only))) { if (!NILP (record_flag)) { - char *p = string; - while (*p) - { - if (! (*p == 'r' || *p == 'p' || *p == 'P' - || *p == '\n')) - Fbarf_if_buffer_read_only (Qnil); - p++; - } - record_then_fail = 1; + for (char *p = string + 1; p < string_end; p++) + if (! (*p == 'r' || *p == 'p' || *p == 'P' || *p == '\n')) + Fbarf_if_buffer_read_only (Qnil); + record_then_fail = true; } else Fbarf_if_buffer_read_only (Qnil); @@ -432,14 +390,12 @@ invoke it. If KEYS is omitted or nil, the return value of } /* Ignore this for semi-compatibility with Lucid. */ else if (*string == '-') - string++; + ; else if (*string == '@') { - Lisp_Object event, w; - - event = (next_event < key_count - ? AREF (keys, next_event) - : Qnil); + Lisp_Object w, event = (next_event < key_count + ? AREF (keys, next_event) + : Qnil); if (EVENT_HAS_PARAMETERS (event) && (w = XCDR (event), CONSP (w)) && (w = XCAR (w), CONSP (w)) @@ -454,32 +410,23 @@ invoke it. If KEYS is omitted or nil, the return value of Fselect_window (w, Qnil); } - string++; } else if (*string == '^') - { - call0 (Qhandle_shift_selection); - string++; - } + call0 (Qhandle_shift_selection); else break; } /* Count the number of arguments, which is two (the function itself and `funcall-interactively') plus the number of arguments the interactive spec would have us give to the function. */ - tem = string; - for (nargs = 2; *tem; ) + ptrdiff_t nargs = 2; + for (char const *tem = string; tem < string_end; tem++) { /* 'r' specifications ("point and mark as 2 numeric args") produce *two* arguments. */ - if (*tem == 'r') - nargs += 2; - else - nargs++; - tem = strchr (tem, '\n'); - if (tem) - ++tem; - else + nargs += 1 + (*tem == 'r'); + tem = memchr (tem, '\n', string_len - (tem - string)); + if (!tem) break; } @@ -487,21 +434,34 @@ invoke it. If KEYS is omitted or nil, the return value of && MOST_POSITIVE_FIXNUM < nargs) memory_full (SIZE_MAX); - /* Allocate them all at one go. This wastes a bit of memory, but + /* ARGS will contain the array of arguments to pass to the function. + VISARGS will contain the same list but in a nicer form, so that if we + pass it to Fformat_message it will be understandable to a human. + Allocate them all at one go. This wastes a bit of memory, but it's OK to trade space for speed. */ + Lisp_Object *args; SAFE_NALLOCA (args, 3, nargs); - visargs = args + nargs; - varies = (signed char *) (visargs + nargs); + Lisp_Object *visargs = args + nargs; + /* If varies[I] > 0, the Ith argument shouldn't just have its value + in this call quoted in the command history. It should be + recorded as a call to the function named callint_argfuns[varies[I]]. */ + signed char *varies = (signed char *) (visargs + nargs); memclear (args, nargs * (2 * word_size + 1)); + args = ptr_bounds_clip (args, nargs * sizeof *args); + visargs = ptr_bounds_clip (visargs, nargs * sizeof *visargs); + varies = ptr_bounds_clip (varies, nargs * sizeof *varies); if (!NILP (enable)) specbind (Qenable_recursive_minibuffers, Qt); - tem = string; - for (i = 2; *tem; i++) + char const *tem = string; + for (ptrdiff_t i = 2; tem < string_end; i++) { - visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n")); + char *pnl = memchr (tem + 1, '\n', string_len - (tem + 1 - string)); + ptrdiff_t sz = pnl ? pnl - (tem + 1) : string_end - (tem + 1); + + visargs[1] = make_string (tem + 1, sz); callint_message = Fformat_message (i - 1, visargs + 1); switch (*tem) @@ -510,9 +470,7 @@ invoke it. If KEYS is omitted or nil, the return value of visargs[i] = Fcompleting_read (callint_message, Vobarray, Qfboundp, Qt, Qnil, Qnil, Qnil, Qnil); - /* Passing args[i] directly stimulates compiler bug. */ - teml = visargs[i]; - args[i] = Fintern (teml, Qnil); + args[i] = Fintern (visargs[i], Qnil); break; case 'b': /* Name of existing buffer. */ @@ -524,7 +482,8 @@ invoke it. If KEYS is omitted or nil, the return value of case 'B': /* Name of buffer, possibly nonexistent. */ args[i] = Fread_buffer (callint_message, - Fother_buffer (Fcurrent_buffer (), Qnil, Qnil), + Fother_buffer (Fcurrent_buffer (), + Qnil, Qnil), Qnil, Qnil); break; @@ -535,20 +494,17 @@ invoke it. If KEYS is omitted or nil, the return value of Qface, Qminibuffer_prompt, callint_message); args[i] = Fread_char (callint_message, Qnil, Qnil); message1_nolog (0); - /* Passing args[i] directly stimulates compiler bug. */ - teml = args[i]; /* See bug#8479. */ - if (! CHARACTERP (teml)) error ("Non-character input-event"); - visargs[i] = Fchar_to_string (teml); + if (! CHARACTERP (args[i])) + error ("Non-character input-event"); + visargs[i] = Fchar_to_string (args[i]); break; case 'C': /* Command: symbol with interactive function. */ visargs[i] = Fcompleting_read (callint_message, Vobarray, Qcommandp, Qt, Qnil, Qnil, Qnil, Qnil); - /* Passing args[i] directly stimulates compiler bug. */ - teml = visargs[i]; - args[i] = Fintern (teml, Qnil); + args[i] = Fintern (visargs[i], Qnil); break; case 'd': /* Value of point. Does not do I/O. */ @@ -559,8 +515,8 @@ invoke it. If KEYS is omitted or nil, the return value of break; case 'D': /* Directory name. */ - args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda, Qnil, - Qfile_directory_p); + args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda, + Qnil, Qfile_directory_p); break; case 'f': /* Existing file name. */ @@ -591,21 +547,19 @@ invoke it. If KEYS is omitted or nil, the return value of args[i] = Fread_key_sequence (callint_message, Qnil, Qnil, Qnil, Qnil); unbind_to (speccount1, Qnil); - teml = args[i]; - visargs[i] = Fkey_description (teml, Qnil); + visargs[i] = Fkey_description (args[i], Qnil); /* If the key sequence ends with a down-event, discard the following up-event. */ - teml = Faref (args[i], make_number (XINT (Flength (args[i])) - 1)); + Lisp_Object teml + = Faref (args[i], make_number (XINT (Flength (args[i])) - 1)); if (CONSP (teml)) teml = XCAR (teml); if (SYMBOLP (teml)) { - Lisp_Object tem2; - teml = Fget (teml, Qevent_symbol_elements); /* Ignore first element, which is the base key. */ - tem2 = Fmemq (Qdown, Fcdr (teml)); + Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml)); if (! NILP (tem2)) up_event = Fread_event (Qnil, Qnil, Qnil); } @@ -622,22 +576,20 @@ invoke it. If KEYS is omitted or nil, the return value of Qface, Qminibuffer_prompt, callint_message); args[i] = Fread_key_sequence_vector (callint_message, Qnil, Qt, Qnil, Qnil); - teml = args[i]; - visargs[i] = Fkey_description (teml, Qnil); + visargs[i] = Fkey_description (args[i], Qnil); unbind_to (speccount1, Qnil); /* If the key sequence ends with a down-event, discard the following up-event. */ - teml = Faref (args[i], make_number (XINT (Flength (args[i])) - 1)); + Lisp_Object teml + = Faref (args[i], make_number (XINT (Flength (args[i])) - 1)); if (CONSP (teml)) teml = XCAR (teml); if (SYMBOLP (teml)) { - Lisp_Object tem2; - teml = Fget (teml, Qevent_symbol_elements); /* Ignore first element, which is the base key. */ - tem2 = Fmemq (Qdown, Fcdr (teml)); + Lisp_Object tem2 = Fmemq (Qdown, Fcdr (teml)); if (! NILP (tem2)) up_event = Fread_event (Qnil, Qnil, Qnil); } @@ -649,8 +601,7 @@ invoke it. If KEYS is omitted or nil, the return value of { args[i] = Fmake_vector (make_number (1), up_event); up_event = Qnil; - teml = args[i]; - visargs[i] = Fkey_description (teml, Qnil); + visargs[i] = Fkey_description (args[i], Qnil); } break; @@ -661,18 +612,18 @@ invoke it. If KEYS is omitted or nil, the return value of ? SSDATA (SYMBOL_NAME (function)) : "command")); args[i] = AREF (keys, next_event); - next_event++; varies[i] = -1; /* Find the next parameterized event. */ - while (next_event < key_count - && !(EVENT_HAS_PARAMETERS (AREF (keys, next_event)))) + do next_event++; + while (next_event < key_count + && ! EVENT_HAS_PARAMETERS (AREF (keys, next_event))); break; case 'm': /* Value of mark. Does not do I/O. */ - check_mark (0); + check_mark (false); /* visargs[i] = Qnil; */ args[i] = BVAR (current_buffer, mark); varies[i] = 2; @@ -690,9 +641,7 @@ invoke it. If KEYS is omitted or nil, the return value of FALLTHROUGH; case 'n': /* Read number from minibuffer. */ args[i] = call1 (Qread_number, callint_message); - /* Passing args[i] directly stimulates compiler bug. */ - teml = args[i]; - visargs[i] = Fnumber_to_string (teml); + visargs[i] = Fnumber_to_string (args[i]); break; case 'P': /* Prefix arg in raw form. Does no I/O. */ @@ -709,15 +658,16 @@ invoke it. If KEYS is omitted or nil, the return value of break; case 'r': /* Region, point and mark as 2 args. */ - check_mark (1); - set_marker_both (point_marker, Qnil, PT, PT_BYTE); - /* visargs[i+1] = Qnil; */ - mark = marker_position (BVAR (current_buffer, mark)); - /* visargs[i] = Qnil; */ - args[i] = PT < mark ? point_marker : BVAR (current_buffer, mark); - varies[i] = 3; - args[++i] = PT > mark ? point_marker : BVAR (current_buffer, mark); - varies[i] = 4; + { + check_mark (true); + set_marker_both (point_marker, Qnil, PT, PT_BYTE); + ptrdiff_t mark = marker_position (BVAR (current_buffer, mark)); + /* visargs[i] = visargs[i + 1] = Qnil; */ + args[i] = PT < mark ? point_marker : BVAR (current_buffer, mark); + varies[i] = 3; + args[++i] = PT > mark ? point_marker : BVAR (current_buffer, mark); + varies[i] = 4; + } break; case 's': /* String read via minibuffer without @@ -729,9 +679,7 @@ invoke it. If KEYS is omitted or nil, the return value of case 'S': /* Any symbol. */ visargs[i] = Fread_string (callint_message, Qnil, Qnil, Qnil, Qnil); - /* Passing args[i] directly stimulates compiler bug. */ - teml = visargs[i]; - args[i] = Fintern (teml, Qnil); + args[i] = Fintern (visargs[i], Qnil); break; case 'v': /* Variable name: symbol that is @@ -777,7 +725,7 @@ invoke it. If KEYS is omitted or nil, the return value of { /* How many bytes are left unprocessed in the specs string? (Note that this excludes the trailing null byte.) */ - ptrdiff_t bytes_left = SBYTES (specs) - (tem - string); + ptrdiff_t bytes_left = string_len - (tem - string); unsigned letter; /* If we have enough bytes left to treat the sequence as a @@ -788,20 +736,21 @@ invoke it. If KEYS is omitted or nil, the return value of else letter = *((unsigned char *) tem); - error ("Invalid control letter `%c' (#o%03o, #x%04x) in interactive calling string", + error (("Invalid control letter `%c' (#o%03o, #x%04x)" + " in interactive calling string"), (int) letter, letter, letter); } } if (varies[i] == 0) - arg_from_tty = 1; + arg_from_tty = true; if (NILP (visargs[i]) && STRINGP (args[i])) visargs[i] = args[i]; - tem = strchr (tem, '\n'); + tem = memchr (tem, '\n', string_len - (tem - string)); if (tem) tem++; - else tem = ""; + else tem = string_end; } unbind_to (speccount, Qnil); @@ -815,19 +764,16 @@ invoke it. If KEYS is omitted or nil, the return value of /* We don't need `visargs' any more, so let's recycle it since we need an array of just the same size. */ visargs[1] = function; - for (i = 2; i < nargs; i++) - { - if (varies[i] > 0) - visargs[i] = list1 (intern (callint_argfuns[varies[i]])); - else - visargs[i] = quotify_arg (args[i]); - } + for (ptrdiff_t i = 2; i < nargs; i++) + visargs[i] = (varies[i] > 0 + ? list1 (intern (callint_argfuns[varies[i]])) + : quotify_arg (args[i])); Vcommand_history = Fcons (Flist (nargs - 1, visargs + 1), Vcommand_history); /* Don't keep command history around forever. */ if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0) { - teml = Fnthcdr (Vhistory_length, Vcommand_history); + Lisp_Object teml = Fnthcdr (Vhistory_length, Vcommand_history); if (CONSP (teml)) XSETCDR (teml, Qnil); } @@ -835,7 +781,7 @@ invoke it. If KEYS is omitted or nil, the return value of /* If we used a marker to hold point, mark, or an end of the region, temporarily, convert it to an integer now. */ - for (i = 2; i < nargs; i++) + for (ptrdiff_t i = 2; i < nargs; i++) if (varies[i] >= 1 && varies[i] <= 4) XSETINT (args[i], marker_position (args[i])); @@ -847,15 +793,11 @@ invoke it. If KEYS is omitted or nil, the return value of Vreal_this_command = save_real_this_command; kset_last_command (current_kboard, save_last_command); - { - Lisp_Object val; - specbind (Qcommand_debug_status, Qnil); + specbind (Qcommand_debug_status, Qnil); - val = Ffuncall (nargs, args); - val = unbind_to (speccount, val); - SAFE_FREE (); - return val; - } + Lisp_Object val = Ffuncall (nargs, args); + SAFE_FREE (); + return unbind_to (speccount, val); } DEFUN ("prefix-numeric-value", Fprefix_numeric_value, Sprefix_numeric_value, diff --git a/src/character.c b/src/character.c index deac1fa22ec..6a689808043 100644 --- a/src/character.c +++ b/src/character.c @@ -1050,6 +1050,32 @@ blankp (int c) return XINT (category) == UNICODE_CATEGORY_Zs; /* separator, space */ } + +/* Return true for characters that would read as symbol characters, + but graphically may be confused with some kind of punctuation. We + require an escaping backslash, when such characters begin a + symbol. */ +bool +confusable_symbol_character_p (int ch) +{ + switch (ch) + { + case 0x2018: /* LEFT SINGLE QUOTATION MARK */ + case 0x2019: /* RIGHT SINGLE QUOTATION MARK */ + case 0x201B: /* SINGLE HIGH-REVERSED-9 QUOTATION MARK */ + case 0x201C: /* LEFT DOUBLE QUOTATION MARK */ + case 0x201D: /* RIGHT DOUBLE QUOTATION MARK */ + case 0x201F: /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK */ + case 0x301E: /* DOUBLE PRIME QUOTATION MARK */ + case 0xFF02: /* FULLWIDTH QUOTATION MARK */ + case 0xFF07: /* FULLWIDTH APOSTROPHE */ + return true; + + default: + return false; + } +} + signed char HEXDIGIT_CONST hexdigit[UCHAR_MAX + 1] = { #if HEXDIGIT_IS_CONST diff --git a/src/character.h b/src/character.h index 1f21b2ad330..1e420ba54cb 100644 --- a/src/character.h +++ b/src/character.h @@ -682,6 +682,8 @@ extern bool graphicp (int); extern bool printablep (int); extern bool blankp (int); +extern bool confusable_symbol_character_p (int ch); + /* Return a translation table of id number ID. */ #define GET_TRANSLATION_TABLE(id) \ (XCDR (XVECTOR (Vtranslation_table_vector)->contents[(id)])) diff --git a/src/cmds.c b/src/cmds.c index db3924e3f6a..96b712ed6d2 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -439,12 +439,13 @@ internal_self_insert (int c, EMACS_INT n) int mc = ((NILP (BVAR (current_buffer, enable_multibyte_characters)) && SINGLE_BYTE_CHAR_P (c)) ? UNIBYTE_TO_CHAR (c) : c); - Lisp_Object string = Fmake_string (make_number (n), make_number (mc)); + Lisp_Object string = Fmake_string (make_number (n), make_number (mc), + Qnil); if (spaces_to_insert) { tem = Fmake_string (make_number (spaces_to_insert), - make_number (' ')); + make_number (' '), Qnil); string = concat2 (string, tem); } diff --git a/src/coding.c b/src/coding.c index e756ba169dd..a16142a9b41 100644 --- a/src/coding.c +++ b/src/coding.c @@ -1515,13 +1515,6 @@ encode_coding_utf_8 (struct coding_system *coding) /* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions". Return true if a text is encoded in one of UTF-16 based coding systems. */ -#define UTF_16_HIGH_SURROGATE_P(val) \ - (((val) & 0xFC00) == 0xD800) - -#define UTF_16_LOW_SURROGATE_P(val) \ - (((val) & 0xFC00) == 0xDC00) - - static bool detect_coding_utf_16 (struct coding_system *coding, struct coding_detection_info *detect_info) @@ -6360,6 +6353,27 @@ check_utf_8 (struct coding_system *coding) } +/* Return whether STRING is a valid UTF-8 string. STRING must be a + unibyte string. */ + +bool +utf8_string_p (Lisp_Object string) +{ + eassert (!STRING_MULTIBYTE (string)); + struct coding_system coding; + setup_coding_system (Qutf_8_unix, &coding); + /* We initialize only the fields that check_utf_8 accesses. */ + coding.head_ascii = -1; + coding.src_pos = 0; + coding.src_pos_byte = 0; + coding.src_chars = SCHARS (string); + coding.src_bytes = SBYTES (string); + coding.src_object = string; + coding.eol_seen = EOL_SEEN_NONE; + return check_utf_8 (&coding) != -1; +} + + /* Detect how end-of-line of a text of length SRC_BYTES pointed by SOURCE is encoded. If CATEGORY is one of coding_category_utf_16_XXXX, assume that CR and LF are encoded by @@ -10249,7 +10263,7 @@ usage: (define-coding-system-internal ...) */) ASET (attrs, coding_attr_ccl_encoder, val); val = args[coding_arg_ccl_valids]; - valids = Fmake_string (make_number (256), make_number (0)); + valids = Fmake_string (make_number (256), make_number (0), Qnil); for (tail = val; CONSP (tail); tail = XCDR (tail)) { int from, to; @@ -10859,6 +10873,7 @@ syms_of_coding (void) DEFSYM (Qiso_2022, "iso-2022"); DEFSYM (Qutf_8, "utf-8"); + DEFSYM (Qutf_8_unix, "utf-8-unix"); DEFSYM (Qutf_8_emacs, "utf-8-emacs"); #if defined (WINDOWSNT) || defined (CYGWIN) diff --git a/src/coding.h b/src/coding.h index 2a87fc32e9d..165c1b29b71 100644 --- a/src/coding.h +++ b/src/coding.h @@ -662,9 +662,22 @@ struct coding_system /* Note that this encodes utf-8, not utf-8-emacs, so it's not a no-op. */ #define ENCODE_UTF_8(str) code_convert_string_norecord (str, Qutf_8, true) +/* Return true if VAL is a high surrogate. VAL must be a 16-bit code + unit. */ + +#define UTF_16_HIGH_SURROGATE_P(val) \ + (((val) & 0xFC00) == 0xD800) + +/* Return true if VAL is a low surrogate. VAL must be a 16-bit code + unit. */ + +#define UTF_16_LOW_SURROGATE_P(val) \ + (((val) & 0xFC00) == 0xDC00) + /* Extern declarations. */ extern Lisp_Object code_conversion_save (bool, bool); extern bool encode_coding_utf_8 (struct coding_system *); +extern bool utf8_string_p (Lisp_Object); extern void setup_coding_system (Lisp_Object, struct coding_system *); extern Lisp_Object coding_charset_list (struct coding_system *); extern Lisp_Object coding_system_charset_list (Lisp_Object); @@ -687,6 +700,8 @@ extern void decode_coding_object (struct coding_system *, extern void encode_coding_object (struct coding_system *, Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, Lisp_Object); +/* Defined in this file. */ +INLINE int surrogates_to_codepoint (int, int); #if defined (WINDOWSNT) || defined (CYGWIN) @@ -731,6 +746,18 @@ extern Lisp_Object from_unicode_buffer (const wchar_t *wstr); } while (false) +/* Return the Unicode code point for the given UTF-16 surrogates. */ + +INLINE int +surrogates_to_codepoint (int low, int high) +{ + eassert (0 <= low && low <= 0xFFFF); + eassert (0 <= high && high <= 0xFFFF); + eassert (UTF_16_LOW_SURROGATE_P (low)); + eassert (UTF_16_HIGH_SURROGATE_P (high)); + return 0x10000 + (low - 0xDC00) + ((high - 0xD800) * 0x400); +} + extern Lisp_Object preferred_coding_system (void); diff --git a/src/data.c b/src/data.c index 45b2bf73026..62b3fcfeb24 100644 --- a/src/data.c +++ b/src/data.c @@ -1852,7 +1852,7 @@ The function `default-value' gets the default value and `set-default' sets it. } if (SYMBOL_CONSTANT_P (variable)) - error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable))); + xsignal1 (Qsetting_constant, variable); if (!blv) { @@ -1915,8 +1915,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) } if (sym->u.s.trapped_write == SYMBOL_NOWRITE) - error ("Symbol %s may not be buffer-local", - SDATA (SYMBOL_NAME (variable))); + xsignal1 (Qsetting_constant, variable); if (blv ? blv->local_if_set : (forwarded && BUFFER_OBJFWDP (valcontents.fwd))) @@ -3069,6 +3068,22 @@ usage: (logxor &rest INTS-OR-MARKERS) */) return arith_driver (Alogxor, nargs, args); } +DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, + doc: /* Return population count of VALUE. +This is the number of one bits in the two's complement representation +of VALUE. If VALUE is negative, return the number of zero bits in the +representation. */) + (Lisp_Object value) +{ + CHECK_NUMBER (value); + EMACS_INT v = XINT (value) < 0 ? -1 - XINT (value) : XINT (value); + return make_number (EMACS_UINT_WIDTH <= UINT_WIDTH + ? count_one_bits (v) + : EMACS_UINT_WIDTH <= ULONG_WIDTH + ? count_one_bits_l (v) + : count_one_bits_ll (v)); +} + static Lisp_Object ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) { @@ -3856,6 +3871,7 @@ syms_of_data (void) defsubr (&Slogand); defsubr (&Slogior); defsubr (&Slogxor); + defsubr (&Slogcount); defsubr (&Slsh); defsubr (&Sash); defsubr (&Sadd1); diff --git a/src/decompress.c b/src/decompress.c index 41de6da1dd2..6f75f821c40 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "lisp.h" #include "buffer.h" +#include "composite.h" #include <verify.h> @@ -66,7 +67,7 @@ init_zlib_functions (void) struct decompress_unwind_data { - ptrdiff_t old_point, start, nbytes; + ptrdiff_t old_point, orig, start, nbytes; z_stream *stream; }; @@ -76,10 +77,19 @@ unwind_decompress (void *ddata) struct decompress_unwind_data *data = ddata; inflateEnd (data->stream); - /* Delete any uncompressed data already inserted on error. */ + /* Delete any uncompressed data already inserted on error, but + without calling the change hooks. */ if (data->start) - del_range (data->start, data->start + data->nbytes); - + { + del_range_2 (data->start, data->start, /* byte, char offsets the same */ + data->start + data->nbytes, data->start + data->nbytes, + 0); + update_compositions (data->start, data->start, CHECK_HEAD); + /* "Balance" the before-change-functions call, which would + otherwise be left "hanging". */ + signal_after_change (data->orig, data->start - data->orig, + data->start - data->orig); + } /* Put point where it was, or if the buffer has shrunk because the compressed data is bigger than the uncompressed, at point-max. */ @@ -141,6 +151,10 @@ This function can be called only in unibyte buffers. */) the same. */ istart = XINT (start); iend = XINT (end); + + /* Do the following before manipulating the gap. */ + modify_text (istart, iend); + move_gap_both (iend, iend); stream.zalloc = Z_NULL; @@ -154,6 +168,7 @@ This function can be called only in unibyte buffers. */) if (inflateInit2 (&stream, MAX_WBITS + 32) != Z_OK) return Qnil; + unwind_data.orig = istart; unwind_data.start = iend; unwind_data.stream = &stream; unwind_data.old_point = PT; @@ -196,7 +211,11 @@ This function can be called only in unibyte buffers. */) unwind_data.start = 0; /* Delete the compressed data. */ - del_range (istart, iend); + del_range_2 (istart, istart, /* byte and char offsets are the same. */ + iend, iend, 0); + + signal_after_change (istart, iend - istart, unwind_data.nbytes); + update_compositions (istart, istart, CHECK_HEAD); return unbind_to (count, Qt); } diff --git a/src/dispextern.h b/src/dispextern.h index 25bd6b24f22..25d51cdd638 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2462,6 +2462,10 @@ struct it descent/ascent (line-height property). Reset after this glyph. */ bool_bf constrain_row_ascent_descent_p : 1; + /* If true, glyphs for line number display were already produced for + the current row. */ + bool_bf line_number_produced_p : 1; + enum line_wrap_method line_wrap; /* The ID of the default face to use. One of DEFAULT_FACE_ID, @@ -2641,6 +2645,12 @@ struct it /* The line number of point's line, or zero if not computed yet. */ ptrdiff_t pt_lnum; + /* Number of pixels to offset tab stops due to width fixup of the + first glyph that crosses first_visible_x. This is only needed on + GUI frames, only when display-line-numbers is in effect, and only + in hscrolled windows. */ + int tab_offset; + /* Left fringe bitmap number (enum fringe_bitmap_type). */ unsigned left_user_fringe_bitmap : FRINGE_ID_BITS; @@ -3452,15 +3462,6 @@ void gamma_correct (struct frame *, COLORREF *); void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); void x_change_tool_bar_height (struct frame *f, int); -/* The frame used to display a tooltip. - - Note: In a GTK build with non-zero x_gtk_use_system_tooltips, this - variable holds the frame that shows the tooltip, not the frame of - the tooltip itself, so checking whether a frame is a tooltip frame - cannot just compare the frame to what this variable holds. */ -extern Lisp_Object tip_frame; - -extern Window tip_window; extern frame_parm_handler x_frame_parm_handlers[]; extern void start_hourglass (void); diff --git a/src/dispnew.c b/src/dispnew.c index ae6799bb85c..56f125218dc 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -25,6 +25,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <unistd.h> #include "lisp.h" +#include "ptr-bounds.h" #include "termchar.h" /* cm.h must come after dispextern.h on Windows. */ #include "dispextern.h" @@ -4652,6 +4653,11 @@ scrolling (struct frame *frame) unsigned *new_hash = old_hash + height; int *draw_cost = (int *) (new_hash + height); int *old_draw_cost = draw_cost + height; + old_hash = ptr_bounds_clip (old_hash, height * sizeof *old_hash); + new_hash = ptr_bounds_clip (new_hash, height * sizeof *new_hash); + draw_cost = ptr_bounds_clip (draw_cost, height * sizeof *draw_cost); + old_draw_cost = ptr_bounds_clip (old_draw_cost, + height * sizeof *old_draw_cost); eassert (current_matrix); @@ -5208,6 +5214,11 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p #ifdef HAVE_WINDOW_SYSTEM if (it.what == IT_IMAGE) { + /* Note that this ignores images that are fringe bitmaps, + because their image ID is zero, and so IMAGE_OPT_FROM_ID will + return NULL. This is okay, since fringe bitmaps are not + displayed in the text area, and so are never the object we + are interested in. */ img = IMAGE_OPT_FROM_ID (it.f, it.image_id); if (img && !NILP (img->spec)) *object = img->spec; diff --git a/src/doc.c b/src/doc.c index 3424bffdf9a..4264ed50640 100644 --- a/src/doc.c +++ b/src/doc.c @@ -535,7 +535,6 @@ the same file name is found in the `doc-directory'. */) EMACS_INT pos; Lisp_Object sym; char *p, *name; - bool skip_file = 0; ptrdiff_t count; char const *dirname; ptrdiff_t dirlen; @@ -609,34 +608,24 @@ the same file name is found in the `doc-directory'. */) { end = strchr (p, '\n'); - /* See if this is a file name, and if it is a file in build-files. */ - if (p[1] == 'S') - { - skip_file = 0; - if (end - p > 4 && end[-2] == '.' - && (end[-1] == 'o' || end[-1] == 'c')) - { - ptrdiff_t len = end - p - 2; - char *fromfile = SAFE_ALLOCA (len + 1); - memcpy (fromfile, &p[2], len); - fromfile[len] = 0; - if (fromfile[len-1] == 'c') - fromfile[len-1] = 'o'; - - skip_file = NILP (Fmember (build_string (fromfile), - Vbuild_files)); - } - } + /* We used to skip files not in build_files, so that when a + function was defined several times in different files + (typically, once in xterm, once in w32term, ...), we only + paid attention to the relevant one. + + But this meant the doc had to be kept and updated in + multiple files. Nowadays we keep the doc only in eg xterm. + The (f)boundp checks below ensure we don't report + docs for eg w32-specific items on X. + */ sym = oblookup (Vobarray, p + 2, multibyte_chars_in_text ((unsigned char *) p + 2, end - p - 2), end - p - 2); - /* Check skip_file so that when a function is defined several - times in different files (typically, once in xterm, once in - w32term, ...), we only pay attention to the one that - matters. */ - if (! skip_file && SYMBOLP (sym)) + /* Ignore docs that start with SKIP. These mark + placeholders where the real doc is elsewhere. */ + if (SYMBOLP (sym)) { /* Attach a docstring to a variable? */ if (p[1] == 'V') @@ -644,8 +633,9 @@ the same file name is found in the `doc-directory'. */) /* Install file-position as variable-documentation property and make it negative for a user-variable (doc starts with a `*'). */ - if (!NILP (Fboundp (sym)) + if ((!NILP (Fboundp (sym)) || !NILP (Fmemq (sym, delayed_init))) + && strncmp (end, "\nSKIP", 5)) Fput (sym, Qvariable_documentation, make_number ((pos + end + 1 - buf) * (end[1] == '*' ? -1 : 1))); @@ -654,7 +644,7 @@ the same file name is found in the `doc-directory'. */) /* Attach a docstring to a function? */ else if (p[1] == 'F') { - if (!NILP (Ffboundp (sym))) + if (!NILP (Ffboundp (sym)) && strncmp (end, "\nSKIP", 5)) store_function_docstring (sym, pos + end + 1 - buf); } else if (p[1] == 'S') diff --git a/src/doprnt.c b/src/doprnt.c index cc5ce65105b..f194b43e0a9 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -503,7 +503,7 @@ esprintf (char *buf, char const *format, ...) return nbytes; } -#if HAVE_MODULES || (defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT) +#if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT /* Format to buffer *BUF of positive size *BUFSIZE, reallocating *BUF and updating *BUFSIZE if the buffer is too small, and otherwise diff --git a/src/dosfns.c b/src/dosfns.c index c6d4d5b8d82..f9845a3049d 100644 --- a/src/dosfns.c +++ b/src/dosfns.c @@ -480,11 +480,7 @@ x_set_title (struct frame *f, Lisp_Object name) #endif /* !HAVE_X_WINDOWS */ DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0, - doc: /* Return storage information about the file system FILENAME is on. -Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total -storage of the file system, FREE is the free storage, and AVAIL is the -storage available to a non-superuser. All 3 numbers are in bytes. -If the underlying system call fails, value is nil. */) + doc: /* SKIP: real doc in fileio.c. */) (Lisp_Object filename) { struct statfs stfs; diff --git a/src/editfns.c b/src/editfns.c index d0ccdbddc29..3a34dd0980b 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -56,6 +56,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "composite.h" #include "intervals.h" +#include "ptr-bounds.h" #include "character.h" #include "buffer.h" #include "coding.h" @@ -1257,10 +1258,10 @@ If POS is out of range, the value is nil. */) if (NILP (pos)) { pos_byte = PT_BYTE; - XSETFASTINT (pos, PT); + if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE) + return Qnil; } - - if (MARKERP (pos)) + else if (MARKERP (pos)) { pos_byte = marker_byte_position (pos); if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE) @@ -3718,7 +3719,7 @@ It returns the number of characters changed. */) } else { - string = Fmake_string (make_number (1), val); + string = Fmake_string (make_number (1), val, Qnil); } replace_range (pos, pos + len, string, 1, 0, 1, 0); pos_byte += SBYTES (string); @@ -4208,9 +4209,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) ptrdiff_t nspec_bound = SCHARS (args[0]) >> 1; /* Allocate the info and discarded tables. */ - ptrdiff_t alloca_size; - if (INT_MULTIPLY_WRAPV (nspec_bound, sizeof *info, &alloca_size) - || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size) + ptrdiff_t info_size, alloca_size; + if (INT_MULTIPLY_WRAPV (nspec_bound, sizeof *info, &info_size) + || INT_ADD_WRAPV (formatlen, info_size, &alloca_size) || SIZE_MAX < alloca_size) memory_full (SIZE_MAX); info = SAFE_ALLOCA (alloca_size); @@ -4218,6 +4219,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) string was not copied into the output. It is 2 if byte I was not the first byte of its character. */ char *discarded = (char *) &info[nspec_bound]; + info = ptr_bounds_clip (info, info_size); + discarded = ptr_bounds_clip (discarded, formatlen); memset (discarded, 0, formatlen); /* Try to determine whether the result should be multibyte. @@ -4560,32 +4563,30 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) and with pM inserted for integer formats. At most two flags F can be specified at once. */ char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)]; - { - char *f = convspec; - *f++ = '%'; - /* MINUS_FLAG and ZERO_FLAG are dealt with later. */ - *f = '+'; f += plus_flag; - *f = ' '; f += space_flag; - *f = '#'; f += sharp_flag; - *f++ = '.'; - *f++ = '*'; - if (float_conversion) - { - if (INT_AS_LDBL) - { - *f = 'L'; - f += INTEGERP (arg); - } - } - else if (conversion != 'c') - { - memcpy (f, pMd, pMlen); - f += pMlen; - zero_flag &= ! precision_given; - } - *f++ = conversion; - *f = '\0'; - } + char *f = convspec; + *f++ = '%'; + /* MINUS_FLAG and ZERO_FLAG are dealt with later. */ + *f = '+'; f += plus_flag; + *f = ' '; f += space_flag; + *f = '#'; f += sharp_flag; + *f++ = '.'; + *f++ = '*'; + if (float_conversion) + { + if (INT_AS_LDBL) + { + *f = 'L'; + f += INTEGERP (arg); + } + } + else if (conversion != 'c') + { + memcpy (f, pMd, pMlen); + f += pMlen; + zero_flag &= ! precision_given; + } + *f++ = conversion; + *f = '\0'; int prec = -1; if (precision_given) @@ -4623,32 +4624,24 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) /* Don't use sprintf here, as it might mishandle prec. */ sprintf_buf[0] = XINT (arg); sprintf_bytes = prec != 0; + sprintf_buf[sprintf_bytes] = '\0'; } else if (conversion == 'd' || conversion == 'i') { - /* For float, maybe we should use "%1.0f" - instead so it also works for values outside - the integer range. */ - printmax_t x; if (INTEGERP (arg)) - x = XINT (arg); + { + printmax_t x = XINT (arg); + sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); + } else { - double d = XFLOAT_DATA (arg); - if (d < 0) - { - x = TYPE_MINIMUM (printmax_t); - if (x < d) - x = d; - } - else - { - x = TYPE_MAXIMUM (printmax_t); - if (d < x) - x = d; - } + strcpy (f - pMlen - 1, "f"); + double x = XFLOAT_DATA (arg); + sprintf_bytes = sprintf (sprintf_buf, convspec, 0, x); + char c0 = sprintf_buf[0]; + bool signedp = ! ('0' <= c0 && c0 <= '9'); + prec = min (precision, sprintf_bytes - signedp); } - sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); } else { @@ -4659,22 +4652,19 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) else { double d = XFLOAT_DATA (arg); - if (d < 0) - x = 0; - else - { - x = TYPE_MAXIMUM (uprintmax_t); - if (d < x) - x = d; - } + double uprintmax = TYPE_MAXIMUM (uprintmax_t); + if (! (0 <= d && d < uprintmax + 1)) + xsignal1 (Qoverflow_error, arg); + x = d; } sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); } /* Now the length of the formatted item is known, except it omits padding and excess precision. Deal with excess precision - first. This happens only when the format specifies - ridiculously large precision. */ + first. This happens when the format specifies ridiculously + large precision, or when %d or %i formats a float that would + ordinarily need fewer digits than a specified precision. */ ptrdiff_t excess_precision = precision_given ? precision - prec : 0; ptrdiff_t leading_zeros = 0, trailing_zeros = 0; @@ -4722,11 +4712,19 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) char src0 = src[0]; int exponent_bytes = 0; bool signedp = src0 == '-' || src0 == '+' || src0 == ' '; - unsigned char after_sign = src[signedp]; - if (zero_flag && 0 <= char_hexdigit (after_sign)) + int prefix_bytes = (signedp + + ((src[signedp] == '0' + && (src[signedp + 1] == 'x' + || src[signedp + 1] == 'X')) + ? 2 : 0)); + if (zero_flag) { - leading_zeros += padding; - padding = 0; + unsigned char after_prefix = src[prefix_bytes]; + if (0 <= char_hexdigit (after_prefix)) + { + leading_zeros += padding; + padding = 0; + } } if (excess_precision @@ -4745,13 +4743,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) nchars += padding; } - *p = src0; - src += signedp; - p += signedp; + memcpy (p, src, prefix_bytes); + p += prefix_bytes; + src += prefix_bytes; memset (p, '0', leading_zeros); p += leading_zeros; int significand_bytes - = sprintf_bytes - signedp - exponent_bytes; + = sprintf_bytes - prefix_bytes - exponent_bytes; memcpy (p, src, significand_bytes); p += significand_bytes; src += significand_bytes; @@ -5281,8 +5279,7 @@ Transposing beyond buffer boundaries is an error. */) { USE_SAFE_ALLOCA; - modify_text (start1, end1); - modify_text (start2, end2); + modify_text (start1, end2); record_change (start1, len1); record_change (start2, len2); tmp_interval1 = copy_intervals (cur_intv, start1, len1); diff --git a/src/emacs-module.c b/src/emacs-module.c index 1b19e8033df..385c3089a90 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -36,6 +36,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <intprops.h> #include <verify.h> +/* Work around GCC bug 83162. */ +#if GNUC_PREREQ (4, 3, 0) +# pragma GCC diagnostic ignored "-Wclobbered" +#endif + /* We use different strategies for allocating the user-visible objects (struct emacs_runtime, emacs_env, emacs_value), depending on whether the user supplied the -module-assertions flag. If @@ -800,18 +805,6 @@ module_function_arity (const struct Lisp_Module_Function *const function) /* Helper functions. */ -static bool -in_current_thread (void) -{ - if (current_thread == NULL) - return false; -#ifdef HAVE_PTHREAD - return pthread_equal (pthread_self (), current_thread->thread_id); -#elif defined WINDOWSNT - return GetCurrentThreadId () == current_thread->thread_id; -#endif -} - static void module_assert_thread (void) { @@ -915,9 +908,8 @@ static Lisp_Object ltv_mark; static Lisp_Object value_to_lisp_bits (emacs_value v) { - intptr_t i = (intptr_t) v; if (plain_values || USE_LSB_TAG) - return XIL (i); + return XPL (v); /* With wide EMACS_INT and when tag bits are the most significant, reassembling integers differs from reassembling pointers in two @@ -926,6 +918,7 @@ value_to_lisp_bits (emacs_value v) integer when restoring, but zero-extend pointers because that makes TAG_PTR faster. */ + intptr_t i = (intptr_t) v; EMACS_UINT tag = i & (GCALIGNMENT - 1); EMACS_UINT untagged = i - tag; switch (tag) @@ -989,13 +982,22 @@ value_to_lisp (emacs_value v) static emacs_value lisp_to_value_bits (Lisp_Object o) { - EMACS_UINT u = XLI (o); + if (plain_values || USE_LSB_TAG) + return XLP (o); - /* Compress U into the space of a pointer, possibly losing information. */ - uintptr_t p = (plain_values || USE_LSB_TAG - ? u - : (INTEGERP (o) ? u << VALBITS : u & VALMASK) + XTYPE (o)); - return (emacs_value) p; + /* Compress O into the space of a pointer, possibly losing information. */ + EMACS_UINT u = XLI (o); + if (INTEGERP (o)) + { + uintptr_t i = (u << VALBITS) + XTYPE (o); + return (emacs_value) i; + } + else + { + char *p = XLP (o); + void *v = p - (u & ~VALMASK) + XTYPE (o); + return v; + } } /* Convert O to an emacs_value. Allocate storage if needed; this can diff --git a/src/emacs.c b/src/emacs.c index 017c62308c1..8ea61b71fb7 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -83,6 +83,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "charset.h" #include "composite.h" #include "dispextern.h" +#include "ptr-bounds.h" #include "regex.h" #include "sheap.h" #include "syntax.h" @@ -1262,6 +1263,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem running_asynch_code = 0; init_random (); +#if defined HAVE_JSON && !defined WINDOWSNT + init_json (); +#endif + no_loadup = argmatch (argv, argc, "-nl", "--no-loadup", 6, NULL, &skip_args); @@ -1542,9 +1547,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem #endif #endif /* HAVE_X_WINDOWS */ -#ifdef HAVE_LIBXML2 syms_of_xml (); -#endif #ifdef HAVE_LCMS2 syms_of_lcms2 (); @@ -1563,6 +1566,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_fontset (); #endif /* HAVE_NTGUI */ +#if defined HAVE_NTGUI || defined CYGWIN + syms_of_w32cygwinx (); +#endif + #if defined WINDOWSNT || defined HAVE_NTGUI syms_of_w32select (); #endif @@ -1610,6 +1617,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_threads (); syms_of_profiler (); +#ifdef HAVE_JSON + syms_of_json (); +#endif + keys_of_casefiddle (); keys_of_cmds (); keys_of_buffer (); @@ -2013,7 +2024,10 @@ all of which are called before Emacs is actually killed. */ /* Fsignal calls emacs_abort () if it sees that waiting_for_input is set. */ waiting_for_input = 0; - run_hook (Qkill_emacs_hook); + if (noninteractive) + safe_run_hooks (Qkill_emacs_hook); + else + run_hook (Qkill_emacs_hook); #ifdef HAVE_X_WINDOWS /* Transfer any clipboards we own to the clipboard manager. */ diff --git a/src/eval.c b/src/eval.c index ca1eb84ff3f..08a73b1e4a5 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1416,6 +1416,57 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), } } +static Lisp_Object +internal_catch_all_1 (Lisp_Object (*function) (void *), void *argument) +{ + struct handler *c = push_handler_nosignal (Qt, CATCHER_ALL); + if (c == NULL) + return Qcatch_all_memory_full; + + if (sys_setjmp (c->jmp) == 0) + { + Lisp_Object val = function (argument); + eassert (handlerlist == c); + handlerlist = c->next; + return val; + } + else + { + eassert (handlerlist == c); + Lisp_Object val = c->val; + handlerlist = c->next; + Fsignal (Qno_catch, val); + } +} + +/* Like a combination of internal_condition_case_1 and internal_catch. + Catches all signals and throws. Never exits nonlocally; returns + Qcatch_all_memory_full if no handler could be allocated. */ + +Lisp_Object +internal_catch_all (Lisp_Object (*function) (void *), void *argument, + Lisp_Object (*handler) (Lisp_Object)) +{ + struct handler *c = push_handler_nosignal (Qt, CONDITION_CASE); + if (c == NULL) + return Qcatch_all_memory_full; + + if (sys_setjmp (c->jmp) == 0) + { + Lisp_Object val = internal_catch_all_1 (function, argument); + eassert (handlerlist == c); + handlerlist = c->next; + return val; + } + else + { + eassert (handlerlist == c); + Lisp_Object val = c->val; + handlerlist = c->next; + return handler (val); + } +} + struct handler * push_handler (Lisp_Object tag_ch_val, enum handlertype handlertype) { @@ -1989,12 +2040,10 @@ it defines a macro. */) if (!CONSP (fundef) || !EQ (Qautoload, XCAR (fundef))) return fundef; - if (EQ (macro_only, Qmacro)) - { - Lisp_Object kind = Fnth (make_number (4), fundef); - if (! (EQ (kind, Qt) || EQ (kind, Qmacro))) - return fundef; - } + Lisp_Object kind = Fnth (make_number (4), fundef); + if (EQ (macro_only, Qmacro) + && !(EQ (kind, Qt) || EQ (kind, Qmacro))) + return fundef; /* This is to make sure that loadup.el gives a clear picture of what files are preloaded and when. */ @@ -2017,15 +2066,18 @@ it defines a macro. */) The value saved here is to be restored into Vautoload_queue. */ record_unwind_protect (un_autoload, Vautoload_queue); Vautoload_queue = Qt; - /* If `macro_only', assume this autoload to be a "best-effort", + /* If `macro_only' is set and fundef isn't a macro, assume this autoload to + be a "best-effort" (e.g. to try and find a compiler macro), so don't signal an error if autoloading fails. */ - Fload (Fcar (Fcdr (fundef)), macro_only, Qt, Qnil, Qt); + Lisp_Object ignore_errors + = (EQ (kind, Qt) || EQ (kind, Qmacro)) ? Qnil : macro_only; + Fload (Fcar (Fcdr (fundef)), ignore_errors, Qt, Qnil, Qt); /* Once loading finishes, don't undo it. */ Vautoload_queue = Qt; unbind_to (count, Qnil); - if (NILP (funname)) + if (NILP (funname) || !NILP (ignore_errors)) return Qnil; else { @@ -4069,6 +4121,9 @@ alist of active lexical bindings. */); inhibit_lisp_code = Qnil; + DEFSYM (Qcatch_all_memory_full, "catch-all-memory-full"); + Funintern (Qcatch_all_memory_full, Qnil); + defsubr (&Sor); defsubr (&Sand); defsubr (&Sif); diff --git a/src/fileio.c b/src/fileio.c index c4a10000bc3..52ca8b6297e 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -96,6 +96,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <acl.h> #include <allocator.h> #include <careadlinkat.h> +#include <fsusage.h> #include <stat-time.h> #include <tempname.h> @@ -138,7 +139,7 @@ static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, struct coding_system *); -/* Return true if FILENAME exists. */ +/* Return true if FILENAME exists, otherwise return false and set errno. */ static bool check_existing (const char *filename) @@ -2594,7 +2595,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, /* The read-only attribute of the parent directory doesn't affect whether a file or directory can be created within it. Some day we should check ACLs though, which do affect this. */ - return file_directory_p (SSDATA (dir)) ? Qt : Qnil; + return file_directory_p (dir) ? Qt : Qnil; #else return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil; #endif @@ -2688,19 +2689,47 @@ See `file-symlink-p' to distinguish symlinks. */) absname = ENCODE_FILE (absname); - return file_directory_p (SSDATA (absname)) ? Qt : Qnil; + return file_directory_p (absname) ? Qt : Qnil; } -/* Return true if FILE is a directory or a symlink to a directory. */ +/* Return true if FILE is a directory or a symlink to a directory. + Otherwise return false and set errno. */ bool -file_directory_p (char const *file) +file_directory_p (Lisp_Object file) { -#ifdef WINDOWSNT +#ifdef DOS_NT /* This is cheaper than 'stat'. */ - return faccessat (AT_FDCWD, file, D_OK, AT_EACCESS) == 0; + return faccessat (AT_FDCWD, SSDATA (file), D_OK, AT_EACCESS) == 0; #else +# ifdef O_PATH + /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ + int fd = openat (AT_FDCWD, SSDATA (file), O_PATH | O_CLOEXEC | O_DIRECTORY); + if (0 <= fd) + { + emacs_close (fd); + return true; + } + if (errno != EINVAL) + return false; + /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. + Fall back on generic POSIX code. */ +# endif + /* Use file_accessible_directory, as it avoids stat EOVERFLOW + problems and could be cheaper. However, if it fails because FILE + is inaccessible, fall back on stat; if the latter fails with + EOVERFLOW then FILE must have been a directory unless a race + condition occurred (a problem hard to work around portably). */ + if (file_accessible_directory_p (file)) + return true; + if (errno != EACCES) + return false; struct stat st; - return stat (file, &st) == 0 && S_ISDIR (st.st_mode); + if (stat (SSDATA (file), &st) != 0) + return errno == EOVERFLOW; + if (S_ISDIR (st.st_mode)) + return true; + errno = ENOTDIR; + return false; #endif } @@ -2761,7 +2790,7 @@ file_accessible_directory_p (Lisp_Object file) return (SBYTES (file) == 0 || w32_accessible_directory_p (SSDATA (file), SBYTES (file))); # else /* MSDOS */ - return file_directory_p (SSDATA (file)); + return file_directory_p (file); # endif /* MSDOS */ #else /* !DOS_NT */ /* On POSIXish platforms, use just one system call; this avoids a @@ -2782,12 +2811,15 @@ file_accessible_directory_p (Lisp_Object file) dir = data; else { - /* Just check for trailing '/' when deciding whether to append '/'. - That's simpler than testing the two special cases "/" and "//", - and it's a safe optimization here. */ - char *buf = SAFE_ALLOCA (len + 3); + /* Just check for trailing '/' when deciding whether append '/' + before appending '.'. That's simpler than testing the two + special cases "/" and "//", and it's a safe optimization + here. After appending '.', append another '/' to work around + a macOS bug (Bug#30350). */ + static char const appended[] = "/./"; + char *buf = SAFE_ALLOCA (len + sizeof appended); memcpy (buf, data, len); - strcpy (buf + len, &"/."[data[len - 1] == '/']); + strcpy (buf + len, &appended[data[len - 1] == '/']); dir = buf; } @@ -3191,7 +3223,7 @@ Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of { #ifdef MSDOS /* Setting times on a directory always fails. */ - if (file_directory_p (SSDATA (encoded_absname))) + if (file_directory_p (encoded_absname)) return Qnil; #endif report_file_error ("Setting file times", absname); @@ -5786,6 +5818,52 @@ effect except for flushing STREAM's data. */) return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil; } +#ifndef DOS_NT + +/* Yield a Lisp float as close as possible to BLOCKSIZE * BLOCKS, with + the result negated if NEGATE. */ +static Lisp_Object +blocks_to_bytes (uintmax_t blocksize, uintmax_t blocks, bool negate) +{ + /* On typical platforms the following code is accurate to 53 bits, + which is close enough. BLOCKSIZE is invariably a power of 2, so + converting it to double does not lose information. */ + double bs = blocksize; + return make_float (negate ? -bs * -blocks : bs * blocks); +} + +DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0, + doc: /* Return storage information about the file system FILENAME is on. +Value is a list of numbers (TOTAL FREE AVAIL), where TOTAL is the total +storage of the file system, FREE is the free storage, and AVAIL is the +storage available to a non-superuser. All 3 numbers are in bytes. +If the underlying system call fails, value is nil. */) + (Lisp_Object filename) +{ + Lisp_Object encoded = ENCODE_FILE (Fexpand_file_name (filename, Qnil)); + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + Lisp_Object handler = Ffind_file_name_handler (encoded, Qfile_system_info); + if (!NILP (handler)) + { + Lisp_Object result = call2 (handler, Qfile_system_info, encoded); + if (CONSP (result) || NILP (result)) + return result; + error ("Invalid handler in `file-name-handler-alist'"); + } + + struct fs_usage u; + if (get_fs_usage (SSDATA (encoded), NULL, &u) != 0) + return Qnil; + return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false), + blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false), + blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail, + u.fsu_bavail_top_bit_set)); +} + +#endif /* !DOS_NT */ + void init_fileio (void) { @@ -5856,6 +5934,7 @@ syms_of_fileio (void) DEFSYM (Qwrite_region, "write-region"); DEFSYM (Qverify_visited_file_modtime, "verify-visited-file-modtime"); DEFSYM (Qset_visited_file_modtime, "set-visited-file-modtime"); + DEFSYM (Qfile_system_info, "file-system-info"); /* The symbol bound to coding-system-for-read when insert-file-contents is called for recovering a file. This is not @@ -6136,6 +6215,10 @@ This includes interactive calls to `delete-file' and defsubr (&Sset_binary_mode); +#ifndef DOS_NT + defsubr (&Sfile_system_info); +#endif + #ifdef HAVE_SYNC defsubr (&Sunix_sync); #endif diff --git a/src/fns.c b/src/fns.c index de1dad3736e..94b9d984f0d 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3319,6 +3319,7 @@ If the region can't be decoded, signal an error and don't modify the buffer. */ and delete the old. (Insert first in order to preserve markers.) */ TEMP_SET_PT_BOTH (XFASTINT (beg), ibeg); insert_1_both (decoded, inserted_chars, decoded_length, 0, 1, 0); + signal_after_change (XFASTINT (beg), 0, inserted_chars); SAFE_FREE (); /* Delete the original text. */ @@ -4829,8 +4830,6 @@ extract_data_from_object (Lisp_Object spec, record_unwind_current_buffer (); - CHECK_BUFFER (object); - struct buffer *bp = XBUFFER (object); set_buffer_internal (bp); diff --git a/src/frame.c b/src/frame.c index cee775c6fa9..86caa32615d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "buffer.h" /* These help us bind and responding to switch-frame events. */ #include "keyboard.h" +#include "ptr-bounds.h" #include "frame.h" #include "blockinput.h" #include "termchar.h" @@ -316,7 +317,7 @@ predicates which report frame's specific UI-related capabilities. */) /* Placeholder used by temacs -nw before window.el is loaded. */ DEFUN ("frame-windows-min-size", Fframe_windows_min_size, Sframe_windows_min_size, 4, 4, 0, - doc: /* */ + doc: /* SKIP: real doc in window.el. */ attributes: const) (Lisp_Object frame, Lisp_Object horizontal, Lisp_Object ignore, Lisp_Object pixelwise) @@ -846,6 +847,7 @@ make_frame (bool mini_p) f->no_focus_on_map = false; f->no_accept_focus = false; f->z_group = z_group_none; + f->tooltip = false; #if ! defined (USE_GTK) && ! defined (HAVE_NS) f->last_tool_bar_item = -1; #endif @@ -1481,20 +1483,21 @@ DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0, DEFUN ("frame-list", Fframe_list, Sframe_list, 0, 0, 0, - doc: /* Return a list of all live frames. */) + doc: /* Return a list of all live frames. +The return value does not include any tooltip frame. */) (void) { - Lisp_Object frames; - frames = Fcopy_sequence (Vframe_list); #ifdef HAVE_WINDOW_SYSTEM - if (FRAMEP (tip_frame) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) - frames = Fdelq (tip_frame, frames); -#endif - return frames; + Lisp_Object list = Qnil, tail, frame; + + FOR_EACH_FRAME (tail, frame) + if (!FRAME_TOOLTIP_P (XFRAME (frame))) + list = Fcons (frame, list); + /* Reverse list for consistency with the !HAVE_WINDOW_SYSTEM case. */ + return Fnreverse (list); +#else /* !HAVE_WINDOW_SYSTEM */ + return Fcopy_sequence (Vframe_list); +#endif /* HAVE_WINDOW_SYSTEM */ } DEFUN ("frame-parent", Fframe_parent, Sframe_parent, @@ -1725,7 +1728,8 @@ DEFUN ("last-nonminibuffer-frame", Flast_nonminibuf_frame, * other_frames: * * Return true if there exists at least one visible or iconified frame - * but F. Return false otherwise. + * but F. Tooltip frames do not qualify as candidates. Return false + * if no such frame exists. * * INVISIBLE true means we are called from make_frame_invisible where * such a frame must be visible or iconified. INVISIBLE nil means we @@ -1739,7 +1743,6 @@ static bool other_frames (struct frame *f, bool invisible, bool force) { Lisp_Object frames, frame, frame1; - struct frame *f1; Lisp_Object minibuffer_window = FRAME_MINIBUF_WINDOW (f); XSETFRAME (frame, f); @@ -1749,7 +1752,8 @@ other_frames (struct frame *f, bool invisible, bool force) FOR_EACH_FRAME (frames, frame1) { - f1 = XFRAME (frame1); + struct frame *f1 = XFRAME (frame1); + if (f != f1) { /* Verify that we can still talk to the frame's X window, and @@ -1758,7 +1762,7 @@ other_frames (struct frame *f, bool invisible, bool force) if (FRAME_WINDOW_P (f1)) x_sync (f1); #endif - if (NILP (Fframe_parameter (frame1, Qtooltip)) + if (!FRAME_TOOLTIP_P (f1) /* Tooltips and child frames count neither for invisibility nor for deletions. */ && !FRAME_PARENT_FRAME (f1) @@ -1891,7 +1895,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) } } - is_tooltip_frame = !NILP (Fframe_parameter (frame, Qtooltip)); + is_tooltip_frame = FRAME_TOOLTIP_P (f); /* Run `delete-frame-functions' unless FORCE is `noelisp' or frame is a tooltip. FORCE is set to `noelisp' when handling @@ -1939,27 +1943,31 @@ delete_frame (Lisp_Object frame, Lisp_Object force) Do not call next_frame here because it may loop forever. See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=15025. */ FOR_EACH_FRAME (tail, frame1) - if (!EQ (frame, frame1) - && NILP (Fframe_parameter (frame1, Qtooltip)) - && (FRAME_TERMINAL (XFRAME (frame)) - == FRAME_TERMINAL (XFRAME (frame1))) - && FRAME_VISIBLE_P (XFRAME (frame1))) - break; + { + struct frame *f1 = XFRAME (frame1); + + if (!EQ (frame, frame1) + && !FRAME_TOOLTIP_P (f1) + && FRAME_TERMINAL (f) == FRAME_TERMINAL (f1) + && FRAME_VISIBLE_P (f1)) + break; + } /* If there is none, find *some* other frame. */ if (NILP (frame1) || EQ (frame1, frame)) { FOR_EACH_FRAME (tail, frame1) { + struct frame *f1 = XFRAME (frame1); + if (!EQ (frame, frame1) - && FRAME_LIVE_P (XFRAME (frame1)) - && NILP (Fframe_parameter (frame1, Qtooltip))) + && FRAME_LIVE_P (f1) + && !FRAME_TOOLTIP_P (f1)) { - /* Do not change a text terminal's top-frame. */ - struct frame *f1 = XFRAME (frame1); if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1)) { Lisp_Object top_frame = FRAME_TTY (f1)->top_frame; + if (!EQ (top_frame, frame)) frame1 = top_frame; } @@ -4832,6 +4840,8 @@ xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Li USE_SAFE_ALLOCA; char *name_key = SAFE_ALLOCA (name_keysize + class_keysize); char *class_key = name_key + name_keysize; + name_key = ptr_bounds_clip (name_key, name_keysize); + class_key = ptr_bounds_clip (class_key, class_keysize); /* Start with emacs.FRAMENAME for the name (the specific one) and with `Emacs' for the class key (the general one). */ @@ -4910,6 +4920,8 @@ x_get_resource_string (const char *attribute, const char *class) ptrdiff_t class_keysize = sizeof (EMACS_CLASS) - 1 + strlen (class) + 2; char *name_key = SAFE_ALLOCA (name_keysize + class_keysize); char *class_key = name_key + name_keysize; + name_key = ptr_bounds_clip (name_key, name_keysize); + class_key = ptr_bounds_clip (class_key, class_keysize); esprintf (name_key, "%s.%s", SSDATA (Vinvocation_name), attribute); sprintf (class_key, "%s.%s", EMACS_CLASS, class); diff --git a/src/frame.h b/src/frame.h index 402d6c0a7b2..2c9c4143886 100644 --- a/src/frame.h +++ b/src/frame.h @@ -342,6 +342,9 @@ struct frame ENUM_BF (output_method) output_method : 3; #ifdef HAVE_WINDOW_SYSTEM + /* True if this frame is a tooltip frame. */ + bool_bf tooltip : 1; + /* See FULLSCREEN_ enum on top. */ ENUM_BF (fullscreen_type) want_fullscreen : 4; @@ -351,9 +354,7 @@ struct frame /* Nonzero if we should actually display horizontal scroll bars on this frame. */ bool_bf horizontal_scroll_bars : 1; -#endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) /* True if this is an undecorated frame. */ bool_bf undecorated : 1; @@ -967,6 +968,7 @@ default_pixels_per_inch_y (void) #define FRAME_Z_GROUP_ABOVE_SUSPENDED(f) \ ((f)->z_group == z_group_above_suspended) #define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below) +#define FRAME_TOOLTIP_P(f) ((f)->tooltip) #ifdef NS_IMPL_COCOA #define FRAME_NS_APPEARANCE(f) ((f)->ns_appearance) #define FRAME_NS_TRANSPARENT_TITLEBAR(f) ((f)->ns_transparent_titlebar) @@ -983,6 +985,7 @@ default_pixels_per_inch_y (void) #define FRAME_Z_GROUP_NONE(f) ((void) (f), true) #define FRAME_Z_GROUP_ABOVE(f) ((void) (f), false) #define FRAME_Z_GROUP_BELOW(f) ((void) (f), false) +#define FRAME_TOOLTIP_P(f) ((void) f, false) #endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ diff --git a/src/fringe.c b/src/fringe.c index 34bc5db06d1..85aa14da727 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "lisp.h" #include "frame.h" +#include "ptr-bounds.h" #include "window.h" #include "dispextern.h" #include "buffer.h" @@ -1591,7 +1592,9 @@ If BITMAP already exists, the existing definition is replaced. */) fb.dynamic = true; xfb = xmalloc (sizeof fb + fb.height * BYTES_PER_BITMAP_ROW); - fb.bits = b = (unsigned short *) (xfb + 1); + fb.bits = b = ((unsigned short *) + ptr_bounds_clip (xfb + 1, fb.height * BYTES_PER_BITMAP_ROW)); + xfb = ptr_bounds_clip (xfb, sizeof *xfb); memset (b, 0, fb.height); j = 0; diff --git a/src/gmalloc.c b/src/gmalloc.c index d013f1f72c6..ebba789f610 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c @@ -40,6 +40,8 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>. # include "lisp.h" #endif +#include "ptr-bounds.h" + #ifdef HAVE_MALLOC_H # if GNUC_PREREQ (4, 2, 0) # pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -201,7 +203,8 @@ extern size_t _bytes_free; /* Internal versions of `malloc', `realloc', and `free' used when these functions need to call each other. - They are the same but don't call the hooks. */ + They are the same but don't call the hooks + and don't bound the resulting pointers. */ extern void *_malloc_internal (size_t); extern void *_realloc_internal (void *, size_t); extern void _free_internal (void *); @@ -558,7 +561,7 @@ malloc_initialize_1 (void) _heapinfo[0].free.size = 0; _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; _heapindex = 0; - _heapbase = (char *) _heapinfo; + _heapbase = (char *) ptr_bounds_init (_heapinfo); _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); register_heapinfo (); @@ -919,7 +922,8 @@ malloc (size_t size) among multiple threads. We just leave it for compatibility with glibc malloc (i.e., assignments to gmalloc_hook) for now. */ hook = gmalloc_hook; - return (hook != NULL ? *hook : _malloc_internal) (size); + void *result = (hook ? hook : _malloc_internal) (size); + return ptr_bounds_clip (result, size); } #if !(defined (_LIBC) || defined (HYBRID_MALLOC)) @@ -997,6 +1001,7 @@ _free_internal_nolock (void *ptr) if (ptr == NULL) return; + ptr = ptr_bounds_init (ptr); PROTECT_MALLOC_STATE (0); @@ -1308,6 +1313,7 @@ _realloc_internal_nolock (void *ptr, size_t size) else if (ptr == NULL) return _malloc_internal_nolock (size); + ptr = ptr_bounds_init (ptr); block = BLOCK (ptr); PROTECT_MALLOC_STATE (0); @@ -1430,7 +1436,8 @@ realloc (void *ptr, size_t size) return NULL; hook = grealloc_hook; - return (hook != NULL ? *hook : _realloc_internal) (ptr, size); + void *result = (hook ? hook : _realloc_internal) (ptr, size); + return ptr_bounds_clip (result, size); } /* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. @@ -1604,6 +1611,7 @@ aligned_alloc (size_t alignment, size_t size) { l->exact = result; result = l->aligned = (char *) result + adj; + result = ptr_bounds_clip (result, size); } UNLOCK_ALIGNED_BLOCKS (); if (l == NULL) diff --git a/src/gtkutil.c b/src/gtkutil.c index 83b306a730a..3f21288f461 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -687,6 +687,7 @@ qttip_cb (GtkWidget *widget, g_signal_connect (x->ttip_lbl, "hierarchy-changed", G_CALLBACK (hierarchy_ch_cb), f); } + return FALSE; } @@ -713,7 +714,8 @@ xg_prepare_tooltip (struct frame *f, GtkRequisition req; Lisp_Object encoded_string; - if (!x->ttip_lbl) return 0; + if (!x->ttip_lbl) + return FALSE; block_input (); encoded_string = ENCODE_UTF_8 (string); @@ -745,7 +747,7 @@ xg_prepare_tooltip (struct frame *f, unblock_input (); - return 1; + return TRUE; #endif /* USE_GTK_TOOLTIP */ } @@ -768,18 +770,18 @@ xg_show_tooltip (struct frame *f, int root_x, int root_y) #endif } + /* Hide tooltip if shown. Do nothing if not shown. Return true if tip was hidden, false if not (i.e. not using system tooltips). */ - bool xg_hide_tooltip (struct frame *f) { - bool ret = 0; #ifdef USE_GTK_TOOLTIP if (f->output_data.x->ttip_window) { GtkWindow *win = f->output_data.x->ttip_window; + block_input (); gtk_widget_hide (GTK_WIDGET (win)); @@ -792,10 +794,10 @@ xg_hide_tooltip (struct frame *f) } unblock_input (); - ret = 1; + return TRUE; } #endif - return ret; + return FALSE; } @@ -1064,16 +1066,23 @@ static void xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel) { #ifdef HAVE_GTK3 - GdkRGBA bg; XColor xbg; xbg.pixel = pixel; if (XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &xbg)) { - bg.red = (double)xbg.red/65535.0; - bg.green = (double)xbg.green/65535.0; - bg.blue = (double)xbg.blue/65535.0; - bg.alpha = 1.0; - gtk_widget_override_background_color (w, GTK_STATE_FLAG_NORMAL, &bg); + const char format[] = "* { background-color: #%02x%02x%02x; }"; + /* The format is always longer than the resulting string. */ + char buffer[sizeof format]; + int n = snprintf(buffer, sizeof buffer, format, + xbg.red >> 8, xbg.green >> 8, xbg.blue >> 8); + eassert (n > 0); + eassert (n < sizeof buffer); + GtkCssProvider *provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, buffer, -1, NULL); + gtk_style_context_add_provider (gtk_widget_get_style_context(w), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_clear_object (&provider); } #else GdkColor bg; @@ -1237,9 +1246,11 @@ xg_create_frame_widgets (struct frame *f) X and GTK+ drawing to a pure GTK+ build. */ gtk_widget_set_double_buffered (wfixed, FALSE); +#if ! GTK_CHECK_VERSION (3, 22, 0) gtk_window_set_wmclass (GTK_WINDOW (wtop), SSDATA (Vx_resource_name), SSDATA (Vx_resource_class)); +#endif /* Add callback to do nothing on WM_DELETE_WINDOW. The default in GTK is to destroy the widget. We want Emacs to do that instead. */ @@ -4108,8 +4119,10 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value) gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); +#if ! GTK_CHECK_VERSION (3, 18, 0) else if (changed) gtk_adjustment_changed (adj); +#endif xg_ignore_gtk_scrollbar = 0; @@ -4146,7 +4159,9 @@ xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower, (gdouble) upper, (gdouble) step_increment, (gdouble) page_increment, (gdouble) pagesize); +#if ! GTK_CHECK_VERSION (3, 18, 0) gtk_adjustment_changed (adj); +#endif unblock_input (); } } diff --git a/src/json.c b/src/json.c new file mode 100644 index 00000000000..b046d34f667 --- /dev/null +++ b/src/json.c @@ -0,0 +1,920 @@ +/* JSON parsing and serialization. + +Copyright (C) 2017-2018 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> + +#include <jansson.h> + +#include "lisp.h" +#include "buffer.h" +#include "coding.h" + +#define JSON_HAS_ERROR_CODE (JANSSON_VERSION_HEX >= 0x020B00) + +#ifdef WINDOWSNT +# include <windows.h> +# include "w32.h" + +DEF_DLL_FN (void, json_set_alloc_funcs, + (json_malloc_t malloc_fn, json_free_t free_fn)); +DEF_DLL_FN (void, json_delete, (json_t *json)); +DEF_DLL_FN (json_t *, json_array, (void)); +DEF_DLL_FN (int, json_array_append_new, (json_t *array, json_t *value)); +DEF_DLL_FN (size_t, json_array_size, (const json_t *array)); +DEF_DLL_FN (json_t *, json_object, (void)); +DEF_DLL_FN (int, json_object_set_new, + (json_t *object, const char *key, json_t *value)); +DEF_DLL_FN (json_t *, json_null, (void)); +DEF_DLL_FN (json_t *, json_true, (void)); +DEF_DLL_FN (json_t *, json_false, (void)); +DEF_DLL_FN (json_t *, json_integer, (json_int_t value)); +DEF_DLL_FN (json_t *, json_real, (double value)); +DEF_DLL_FN (json_t *, json_stringn, (const char *value, size_t len)); +DEF_DLL_FN (char *, json_dumps, (const json_t *json, size_t flags)); +DEF_DLL_FN (int, json_dump_callback, + (const json_t *json, json_dump_callback_t callback, void *data, + size_t flags)); +DEF_DLL_FN (json_int_t, json_integer_value, (const json_t *integer)); +DEF_DLL_FN (double, json_real_value, (const json_t *real)); +DEF_DLL_FN (const char *, json_string_value, (const json_t *string)); +DEF_DLL_FN (size_t, json_string_length, (const json_t *string)); +DEF_DLL_FN (json_t *, json_array_get, (const json_t *array, size_t index)); +DEF_DLL_FN (json_t *, json_object_get, (const json_t *object, const char *key)); +DEF_DLL_FN (size_t, json_object_size, (const json_t *object)); +DEF_DLL_FN (const char *, json_object_iter_key, (void *iter)); +DEF_DLL_FN (void *, json_object_iter, (json_t *object)); +DEF_DLL_FN (json_t *, json_object_iter_value, (void *iter)); +DEF_DLL_FN (void *, json_object_key_to_iter, (const char *key)); +DEF_DLL_FN (void *, json_object_iter_next, (json_t *object, void *iter)); +DEF_DLL_FN (json_t *, json_loads, + (const char *input, size_t flags, json_error_t *error)); +DEF_DLL_FN (json_t *, json_load_callback, + (json_load_callback_t callback, void *data, size_t flags, + json_error_t *error)); + +/* This is called by json_decref, which is an inline function. */ +void json_delete(json_t *json) +{ + fn_json_delete (json); +} + +static bool json_initialized; + +static bool +init_json_functions (void) +{ + HMODULE library = w32_delayed_load (Qjson); + + if (!library) + return false; + + LOAD_DLL_FN (library, json_set_alloc_funcs); + LOAD_DLL_FN (library, json_delete); + LOAD_DLL_FN (library, json_array); + LOAD_DLL_FN (library, json_array_append_new); + LOAD_DLL_FN (library, json_array_size); + LOAD_DLL_FN (library, json_object); + LOAD_DLL_FN (library, json_object_set_new); + LOAD_DLL_FN (library, json_null); + LOAD_DLL_FN (library, json_true); + LOAD_DLL_FN (library, json_false); + LOAD_DLL_FN (library, json_integer); + LOAD_DLL_FN (library, json_real); + LOAD_DLL_FN (library, json_stringn); + LOAD_DLL_FN (library, json_dumps); + LOAD_DLL_FN (library, json_dump_callback); + LOAD_DLL_FN (library, json_integer_value); + LOAD_DLL_FN (library, json_real_value); + LOAD_DLL_FN (library, json_string_value); + LOAD_DLL_FN (library, json_string_length); + LOAD_DLL_FN (library, json_array_get); + LOAD_DLL_FN (library, json_object_get); + LOAD_DLL_FN (library, json_object_size); + LOAD_DLL_FN (library, json_object_iter_key); + LOAD_DLL_FN (library, json_object_iter); + LOAD_DLL_FN (library, json_object_iter_value); + LOAD_DLL_FN (library, json_object_key_to_iter); + LOAD_DLL_FN (library, json_object_iter_next); + LOAD_DLL_FN (library, json_loads); + LOAD_DLL_FN (library, json_load_callback); + + init_json (); + + return true; +} + +#define json_set_alloc_funcs fn_json_set_alloc_funcs +#define json_array fn_json_array +#define json_array_append_new fn_json_array_append_new +#define json_array_size fn_json_array_size +#define json_object fn_json_object +#define json_object_set_new fn_json_object_set_new +#define json_null fn_json_null +#define json_true fn_json_true +#define json_false fn_json_false +#define json_integer fn_json_integer +#define json_real fn_json_real +#define json_stringn fn_json_stringn +#define json_dumps fn_json_dumps +#define json_dump_callback fn_json_dump_callback +#define json_integer_value fn_json_integer_value +#define json_real_value fn_json_real_value +#define json_string_value fn_json_string_value +#define json_string_length fn_json_string_length +#define json_array_get fn_json_array_get +#define json_object_get fn_json_object_get +#define json_object_size fn_json_object_size +#define json_object_iter_key fn_json_object_iter_key +#define json_object_iter fn_json_object_iter +#define json_object_iter_value fn_json_object_iter_value +#define json_object_key_to_iter fn_json_object_key_to_iter +#define json_object_iter_next fn_json_object_iter_next +#define json_loads fn_json_loads +#define json_load_callback fn_json_load_callback + +#endif /* WINDOWSNT */ + +/* We install a custom allocator so that we can avoid objects larger + than PTRDIFF_MAX. Such objects wouldn't play well with the rest of + Emacs's codebase, which generally uses ptrdiff_t for sizes and + indices. The other functions in this file also generally assume + that size_t values never exceed PTRDIFF_MAX. */ + +static void * +json_malloc (size_t size) +{ + if (size > PTRDIFF_MAX) + { + errno = ENOMEM; + return NULL; + } + return malloc (size); +} + +static void +json_free (void *ptr) +{ + free (ptr); +} + +void +init_json (void) +{ + json_set_alloc_funcs (json_malloc, json_free); +} + +#if !JSON_HAS_ERROR_CODE + +/* Return whether STRING starts with PREFIX. */ + +static bool +json_has_prefix (const char *string, const char *prefix) +{ + size_t string_len = strlen (string); + size_t prefix_len = strlen (prefix); + return string_len >= prefix_len && memcmp (string, prefix, prefix_len) == 0; +} + +/* Return whether STRING ends with SUFFIX. */ + +static bool +json_has_suffix (const char *string, const char *suffix) +{ + size_t string_len = strlen (string); + size_t suffix_len = strlen (suffix); + return string_len >= suffix_len + && memcmp (string + string_len - suffix_len, suffix, suffix_len) == 0; +} + +#endif + +/* Create a multibyte Lisp string from the UTF-8 string in + [DATA, DATA + SIZE). If the range [DATA, DATA + SIZE) does not + contain a valid UTF-8 string, an unspecified string is returned. + Note that all callers below either pass only value UTF-8 strings or + use this function for formatting error messages; in the latter case + correctness isn't critical. */ + +static Lisp_Object +json_make_string (const char *data, ptrdiff_t size) +{ + return code_convert_string (make_specified_string (data, -1, size, false), + Qutf_8_unix, Qt, false, true, true); +} + +/* Create a multibyte Lisp string from the null-terminated UTF-8 + string beginning at DATA. If the string is not a valid UTF-8 + string, an unspecified string is returned. Note that all callers + below either pass only value UTF-8 strings or use this function for + formatting error messages; in the latter case correctness isn't + critical. */ + +static Lisp_Object +json_build_string (const char *data) +{ + return json_make_string (data, strlen (data)); +} + +/* Return a unibyte string containing the sequence of UTF-8 encoding + units of the UTF-8 representation of STRING. If STRING does not + represent a sequence of Unicode scalar values, return a string with + unspecified contents. */ + +static Lisp_Object +json_encode (Lisp_Object string) +{ + /* FIXME: Raise an error if STRING is not a scalar value + sequence. */ + return code_convert_string (string, Qutf_8_unix, Qt, true, true, true); +} + +static _Noreturn void +json_out_of_memory (void) +{ + xsignal0 (Qjson_out_of_memory); +} + +/* Signal a Lisp error corresponding to the JSON ERROR. */ + +static _Noreturn void +json_parse_error (const json_error_t *error) +{ + Lisp_Object symbol; +#if JSON_HAS_ERROR_CODE + switch (json_error_code (error)) + { + case json_error_premature_end_of_input: + symbol = Qjson_end_of_file; + break; + case json_error_end_of_input_expected: + symbol = Qjson_trailing_content; + break; + default: + symbol = Qjson_parse_error; + break; + } +#else + if (json_has_suffix (error->text, "expected near end of file")) + symbol = Qjson_end_of_file; + else if (json_has_prefix (error->text, "end of file expected")) + symbol = Qjson_trailing_content; + else + symbol = Qjson_parse_error; +#endif + xsignal (symbol, + list5 (json_build_string (error->text), + json_build_string (error->source), make_natnum (error->line), + make_natnum (error->column), make_natnum (error->position))); +} + +static void +json_release_object (void *object) +{ + json_decref (object); +} + +/* Signal an error if OBJECT is not a string, or if OBJECT contains + embedded null characters. */ + +static void +check_string_without_embedded_nulls (Lisp_Object object) +{ + CHECK_STRING (object); + CHECK_TYPE (memchr (SDATA (object), '\0', SBYTES (object)) == NULL, + Qstring_without_embedded_nulls_p, object); +} + +/* Signal an error of type `json-out-of-memory' if OBJECT is + NULL. */ + +static json_t * +json_check (json_t *object) +{ + if (object == NULL) + json_out_of_memory (); + return object; +} + +/* If STRING is not a valid UTF-8 string, signal an error of type + `wrong-type-argument'. STRING must be a unibyte string. */ + +static void +json_check_utf8 (Lisp_Object string) +{ + CHECK_TYPE (utf8_string_p (string), Qutf_8_string_p, string); +} + +static json_t *lisp_to_json (Lisp_Object); + +/* Convert a Lisp object to a toplevel JSON object (array or object). + This returns Lisp_Object so we can use unbind_to. The return value + is always nil. */ + +static _GL_ARG_NONNULL ((2)) Lisp_Object +lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) +{ + if (VECTORP (lisp)) + { + ptrdiff_t size = ASIZE (lisp); + *json = json_check (json_array ()); + ptrdiff_t count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, json); + for (ptrdiff_t i = 0; i < size; ++i) + { + int status + = json_array_append_new (*json, lisp_to_json (AREF (lisp, i))); + if (status == -1) + json_out_of_memory (); + } + eassert (json_array_size (*json) == size); + clear_unwind_protect (count); + return unbind_to (count, Qnil); + } + else if (HASH_TABLE_P (lisp)) + { + struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); + *json = json_check (json_object ()); + ptrdiff_t count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, *json); + for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) + if (!NILP (HASH_HASH (h, i))) + { + Lisp_Object key = json_encode (HASH_KEY (h, i)); + /* We can't specify the length, so the string must be + null-terminated. */ + check_string_without_embedded_nulls (key); + const char *key_str = SSDATA (key); + /* Reject duplicate keys. These are possible if the hash + table test is not `equal'. */ + if (json_object_get (*json, key_str) != NULL) + wrong_type_argument (Qjson_value_p, lisp); + int status = json_object_set_new (*json, key_str, + lisp_to_json (HASH_VALUE (h, i))); + if (status == -1) + { + /* A failure can be caused either by an invalid key or + by low memory. */ + json_check_utf8 (key); + json_out_of_memory (); + } + } + clear_unwind_protect (count); + return unbind_to (count, Qnil); + } + else if (NILP (lisp)) + { + *json = json_check (json_object ()); + return Qnil; + } + else if (CONSP (lisp)) + { + Lisp_Object tail = lisp; + *json = json_check (json_object ()); + ptrdiff_t count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, *json); + FOR_EACH_TAIL (tail) + { + Lisp_Object pair = XCAR (tail); + CHECK_CONS (pair); + Lisp_Object key_symbol = XCAR (pair); + Lisp_Object value = XCDR (pair); + CHECK_SYMBOL (key_symbol); + Lisp_Object key = SYMBOL_NAME (key_symbol); + /* We can't specify the length, so the string must be + null-terminated. */ + check_string_without_embedded_nulls (key); + const char *key_str = SSDATA (key); + /* Only add element if key is not already present. */ + if (json_object_get (*json, key_str) == NULL) + { + int status + = json_object_set_new (*json, key_str, lisp_to_json (value)); + if (status == -1) + json_out_of_memory (); + } + } + CHECK_LIST_END (tail, lisp); + clear_unwind_protect (count); + return unbind_to (count, Qnil); + } + wrong_type_argument (Qjson_value_p, lisp); +} + +/* Convert LISP to a toplevel JSON object (array or object). Signal + an error of type `wrong-type-argument' if LISP is not a vector, + hashtable, or alist. */ + +static json_t * +lisp_to_json_toplevel (Lisp_Object lisp) +{ + if (++lisp_eval_depth > max_lisp_eval_depth) + xsignal0 (Qjson_object_too_deep); + json_t *json; + lisp_to_json_toplevel_1 (lisp, &json); + --lisp_eval_depth; + return json; +} + +/* Convert LISP to any JSON object. Signal an error of type + `wrong-type-argument' if the type of LISP can't be converted to a + JSON object. */ + +static json_t * +lisp_to_json (Lisp_Object lisp) +{ + if (EQ (lisp, QCnull)) + return json_check (json_null ()); + else if (EQ (lisp, QCfalse)) + return json_check (json_false ()); + else if (EQ (lisp, Qt)) + return json_check (json_true ()); + else if (INTEGERP (lisp)) + { + CHECK_TYPE_RANGED_INTEGER (json_int_t, lisp); + return json_check (json_integer (XINT (lisp))); + } + else if (FLOATP (lisp)) + return json_check (json_real (XFLOAT_DATA (lisp))); + else if (STRINGP (lisp)) + { + Lisp_Object encoded = json_encode (lisp); + json_t *json = json_stringn (SSDATA (encoded), SBYTES (encoded)); + if (json == NULL) + { + /* A failure can be caused either by an invalid string or by + low memory. */ + json_check_utf8 (encoded); + json_out_of_memory (); + } + return json; + } + + /* LISP now must be a vector, hashtable, or alist. */ + return lisp_to_json_toplevel (lisp); +} + +DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, + doc: /* Return the JSON representation of OBJECT as a string. +OBJECT must be a vector, hashtable, or alist, and its elements can +recursively contain `:null', `:false', t, numbers, strings, or other +vectors hashtables, and alist. `:null', `:false', and t will be +converted to JSON null, false, and true values, respectively. Vectors +will be converted to JSON arrays, and hashtables and alists to JSON +objects. Hashtable keys must be strings without embedded null +characters and must be unique within each object. Alist keys must be +symbols; if a key is duplicate, the first instance is used. */) + (Lisp_Object object) +{ + ptrdiff_t count = SPECPDL_INDEX (); + +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + + json_t *json = lisp_to_json_toplevel (object); + record_unwind_protect_ptr (json_release_object, json); + + /* If desired, we might want to add the following flags: + JSON_DECODE_ANY, JSON_ALLOW_NUL. */ + char *string = json_dumps (json, JSON_COMPACT); + if (string == NULL) + json_out_of_memory (); + record_unwind_protect_ptr (free, string); + + return unbind_to (count, json_build_string (string)); +} + +struct json_buffer_and_size +{ + const char *buffer; + ptrdiff_t size; +}; + +static Lisp_Object +json_insert (void *data) +{ + struct json_buffer_and_size *buffer_and_size = data; + /* FIXME: This should be possible without creating an intermediate + string object. */ + Lisp_Object string + = json_make_string (buffer_and_size->buffer, buffer_and_size->size); + insert1 (string); + return Qnil; +} + +struct json_insert_data +{ + /* nil if json_insert succeeded, otherwise the symbol + Qcatch_all_memory_full or a cons (ERROR-SYMBOL . ERROR-DATA). */ + Lisp_Object error; +}; + +/* Callback for json_dump_callback that inserts the UTF-8 string in + [BUFFER, BUFFER + SIZE) into the current buffer. + If [BUFFER, BUFFER + SIZE) does not contain a valid UTF-8 string, + an unspecified string is inserted into the buffer. DATA must point + to a structure of type json_insert_data. This function may not + exit nonlocally. It catches all nonlocal exits and stores them in + data->error for reraising. */ + +static int +json_insert_callback (const char *buffer, size_t size, void *data) +{ + struct json_insert_data *d = data; + struct json_buffer_and_size buffer_and_size + = {.buffer = buffer, .size = size}; + d->error = internal_catch_all (json_insert, &buffer_and_size, Fidentity); + return NILP (d->error) ? 0 : -1; +} + +DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 1, NULL, + doc: /* Insert the JSON representation of OBJECT before point. +This is the same as (insert (json-serialize OBJECT)), but potentially +faster. See the function `json-serialize' for allowed values of +OBJECT. */) + (Lisp_Object object) +{ + ptrdiff_t count = SPECPDL_INDEX (); + +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + + json_t *json = lisp_to_json (object); + record_unwind_protect_ptr (json_release_object, json); + + struct json_insert_data data; + /* If desired, we might want to add the following flags: + JSON_DECODE_ANY, JSON_ALLOW_NUL. */ + int status + = json_dump_callback (json, json_insert_callback, &data, JSON_COMPACT); + if (status == -1) + { + if (CONSP (data.error)) + xsignal (XCAR (data.error), XCDR (data.error)); + else + json_out_of_memory (); + } + + return unbind_to (count, Qnil); +} + +enum json_object_type { + json_object_hashtable, + json_object_alist, +}; + +/* Convert a JSON object to a Lisp object. */ + +static _GL_ARG_NONNULL ((1)) Lisp_Object +json_to_lisp (json_t *json, enum json_object_type object_type) +{ + switch (json_typeof (json)) + { + case JSON_NULL: + return QCnull; + case JSON_FALSE: + return QCfalse; + case JSON_TRUE: + return Qt; + case JSON_INTEGER: + /* Return an integer if possible, a floating-point number + otherwise. This loses precision for integers with large + magnitude; however, such integers tend to be nonportable + anyway because many JSON implementations use only 64-bit + floating-point numbers with 53 mantissa bits. See + https://tools.ietf.org/html/rfc7159#section-6 for some + discussion. */ + return make_fixnum_or_float (json_integer_value (json)); + case JSON_REAL: + return make_float (json_real_value (json)); + case JSON_STRING: + return json_make_string (json_string_value (json), + json_string_length (json)); + case JSON_ARRAY: + { + if (++lisp_eval_depth > max_lisp_eval_depth) + xsignal0 (Qjson_object_too_deep); + size_t size = json_array_size (json); + if (FIXNUM_OVERFLOW_P (size)) + xsignal0 (Qoverflow_error); + Lisp_Object result = Fmake_vector (make_natnum (size), Qunbound); + for (ptrdiff_t i = 0; i < size; ++i) + ASET (result, i, + json_to_lisp (json_array_get (json, i), object_type)); + --lisp_eval_depth; + return result; + } + case JSON_OBJECT: + { + if (++lisp_eval_depth > max_lisp_eval_depth) + xsignal0 (Qjson_object_too_deep); + Lisp_Object result; + switch (object_type) + { + case json_object_hashtable: + { + size_t size = json_object_size (json); + if (FIXNUM_OVERFLOW_P (size)) + xsignal0 (Qoverflow_error); + result = CALLN (Fmake_hash_table, QCtest, Qequal, QCsize, + make_natnum (size)); + struct Lisp_Hash_Table *h = XHASH_TABLE (result); + const char *key_str; + json_t *value; + json_object_foreach (json, key_str, value) + { + Lisp_Object key = json_build_string (key_str); + EMACS_UINT hash; + ptrdiff_t i = hash_lookup (h, key, &hash); + /* Keys in JSON objects are unique, so the key can't + be present yet. */ + eassert (i < 0); + hash_put (h, key, json_to_lisp (value, object_type), hash); + } + break; + } + case json_object_alist: + { + result = Qnil; + const char *key_str; + json_t *value; + json_object_foreach (json, key_str, value) + { + Lisp_Object key = Fintern (json_build_string (key_str), Qnil); + result + = Fcons (Fcons (key, json_to_lisp (value, object_type)), + result); + } + result = Fnreverse (result); + break; + } + default: + /* Can't get here. */ + emacs_abort (); + } + --lisp_eval_depth; + return result; + } + } + /* Can't get here. */ + emacs_abort (); +} + +static enum json_object_type +json_parse_object_type (ptrdiff_t nargs, Lisp_Object *args) +{ + switch (nargs) + { + case 0: + return json_object_hashtable; + case 2: + { + Lisp_Object key = args[0]; + Lisp_Object value = args[1]; + if (!EQ (key, QCobject_type)) + wrong_choice (list1 (QCobject_type), key); + if (EQ (value, Qhash_table)) + return json_object_hashtable; + else if (EQ (value, Qalist)) + return json_object_alist; + else + wrong_choice (list2 (Qhash_table, Qalist), value); + } + default: + wrong_type_argument (Qplistp, Flist (nargs, args)); + } +} + +DEFUN ("json-parse-string", Fjson_parse_string, Sjson_parse_string, 1, MANY, + NULL, + doc: /* Parse the JSON STRING into a Lisp object. +This is essentially the reverse operation of `json-serialize', which +see. The returned object will be a vector, hashtable, or alist. Its +elements will be `:null', `:false', t, numbers, strings, or further +vectors, hashtables, and alists. If there are duplicate keys in an +object, all but the last one are ignored. If STRING doesn't contain a +valid JSON object, an error of type `json-parse-error' is signaled. +The keyword argument `:object-type' specifies which Lisp type is used +to represent objects; it can be `hash-table' or `alist'. +usage: (json-parse-string STRING &key (OBJECT-TYPE \\='hash-table)) */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + ptrdiff_t count = SPECPDL_INDEX (); + +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + + Lisp_Object string = args[0]; + Lisp_Object encoded = json_encode (string); + check_string_without_embedded_nulls (encoded); + enum json_object_type object_type + = json_parse_object_type (nargs - 1, args + 1); + + json_error_t error; + json_t *object = json_loads (SSDATA (encoded), 0, &error); + if (object == NULL) + json_parse_error (&error); + + /* Avoid leaking the object in case of further errors. */ + if (object != NULL) + record_unwind_protect_ptr (json_release_object, object); + + return unbind_to (count, json_to_lisp (object, object_type)); +} + +struct json_read_buffer_data +{ + /* Byte position of position to read the next chunk from. */ + ptrdiff_t point; +}; + +/* Callback for json_load_callback that reads from the current buffer. + DATA must point to a structure of type json_read_buffer_data. + data->point must point to the byte position to read from; after + reading, data->point is advanced accordingly. The buffer point + itself is ignored. This function may not exit nonlocally. */ + +static size_t +json_read_buffer_callback (void *buffer, size_t buflen, void *data) +{ + struct json_read_buffer_data *d = data; + + /* First, parse from point to the gap or the end of the accessible + portion, whatever is closer. */ + ptrdiff_t point = d->point; + ptrdiff_t end = BUFFER_CEILING_OF (point) + 1; + ptrdiff_t count = end - point; + if (buflen < count) + count = buflen; + memcpy (buffer, BYTE_POS_ADDR (point), count); + d->point += count; + return count; +} + +DEFUN ("json-parse-buffer", Fjson_parse_buffer, Sjson_parse_buffer, + 0, MANY, NULL, + doc: /* Read JSON object from current buffer starting at point. +This is similar to `json-parse-string', which see. Move point after +the end of the object if parsing was successful. On error, point is +not moved. +usage: (json-parse-buffer &key (OBJECT-TYPE \\='hash-table)) */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + ptrdiff_t count = SPECPDL_INDEX (); + +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + + enum json_object_type object_type = json_parse_object_type (nargs, args); + + ptrdiff_t point = PT_BYTE; + struct json_read_buffer_data data = {.point = point}; + json_error_t error; + json_t *object = json_load_callback (json_read_buffer_callback, &data, + JSON_DISABLE_EOF_CHECK, &error); + + if (object == NULL) + json_parse_error (&error); + + /* Avoid leaking the object in case of further errors. */ + record_unwind_protect_ptr (json_release_object, object); + + /* Convert and then move point only if everything succeeded. */ + Lisp_Object lisp = json_to_lisp (object, object_type); + + /* Adjust point by how much we just read. */ + point += error.position; + SET_PT_BOTH (BYTE_TO_CHAR (point), point); + + return unbind_to (count, lisp); +} + +/* Simplified version of 'define-error' that works with pure + objects. */ + +static void +define_error (Lisp_Object name, const char *message, Lisp_Object parent) +{ + eassert (SYMBOLP (name)); + eassert (SYMBOLP (parent)); + Lisp_Object parent_conditions = Fget (parent, Qerror_conditions); + eassert (CONSP (parent_conditions)); + eassert (!NILP (Fmemq (parent, parent_conditions))); + eassert (NILP (Fmemq (name, parent_conditions))); + Fput (name, Qerror_conditions, pure_cons (name, parent_conditions)); + Fput (name, Qerror_message, build_pure_c_string (message)); +} + +void +syms_of_json (void) +{ + DEFSYM (QCnull, ":null"); + DEFSYM (QCfalse, ":false"); + + DEFSYM (Qstring_without_embedded_nulls_p, "string-without-embedded-nulls-p"); + DEFSYM (Qjson_value_p, "json-value-p"); + DEFSYM (Qutf_8_string_p, "utf-8-string-p"); + + DEFSYM (Qjson_error, "json-error"); + DEFSYM (Qjson_out_of_memory, "json-out-of-memory"); + DEFSYM (Qjson_parse_error, "json-parse-error"); + DEFSYM (Qjson_end_of_file, "json-end-of-file"); + DEFSYM (Qjson_trailing_content, "json-trailing-content"); + DEFSYM (Qjson_object_too_deep, "json-object-too-deep"); + define_error (Qjson_error, "generic JSON error", Qerror); + define_error (Qjson_out_of_memory, + "not enough memory for creating JSON object", Qjson_error); + define_error (Qjson_parse_error, "could not parse JSON stream", + Qjson_error); + define_error (Qjson_end_of_file, "end of JSON stream", Qjson_parse_error); + define_error (Qjson_trailing_content, "trailing content after JSON stream", + Qjson_parse_error); + define_error (Qjson_object_too_deep, + "object cyclic or Lisp evaluation too deep", Qjson_error); + + DEFSYM (Qpure, "pure"); + DEFSYM (Qside_effect_free, "side-effect-free"); + + DEFSYM (Qjson_serialize, "json-serialize"); + DEFSYM (Qjson_parse_string, "json-parse-string"); + Fput (Qjson_serialize, Qpure, Qt); + Fput (Qjson_serialize, Qside_effect_free, Qt); + Fput (Qjson_parse_string, Qpure, Qt); + Fput (Qjson_parse_string, Qside_effect_free, Qt); + + DEFSYM (QCobject_type, ":object-type"); + DEFSYM (Qalist, "alist"); + + defsubr (&Sjson_serialize); + defsubr (&Sjson_insert); + defsubr (&Sjson_parse_string); + defsubr (&Sjson_parse_buffer); +} diff --git a/src/keyboard.c b/src/keyboard.c index e62dd0ec489..9b8d275d0fd 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -43,6 +43,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "systime.h" #include "atimer.h" #include "process.h" +#include "menu.h" #include <errno.h> #ifdef HAVE_PTHREAD @@ -1365,6 +1366,7 @@ command_loop_1 (void) Vthis_command_keys_shift_translated = Qnil; /* Read next key sequence; i gets its length. */ + raw_keybuf_count = 0; i = read_key_sequence (keybuf, ARRAYELTS (keybuf), Qnil, 0, 1, 1, 0); @@ -1869,6 +1871,7 @@ int poll_suppress_count; static struct atimer *poll_timer; +#if defined CYGWIN || defined DOS_NT /* Poll for input, so that we catch a C-g if it comes in. */ void poll_for_input_1 (void) @@ -1877,6 +1880,7 @@ poll_for_input_1 (void) && !waiting_for_input) gobble_input (); } +#endif /* Timer callback function for poll_timer. TIMER is equal to poll_timer. */ @@ -1928,20 +1932,22 @@ start_polling (void) #endif } +#if defined CYGWIN || defined DOS_NT /* True if we are using polling to handle input asynchronously. */ bool input_polling_used (void) { -#ifdef POLL_FOR_INPUT +# ifdef POLL_FOR_INPUT /* XXX This condition was (read_socket_hook && !interrupt_input), but read_socket_hook is not global anymore. Let's pretend that it's always set. */ return !interrupt_input; -#else - return 0; -#endif +# else + return false; +# endif } +#endif /* Turn off polling. */ @@ -2809,6 +2815,9 @@ read_char (int commandflag, Lisp_Object map, if (EQ (c, make_number (-2))) return c; + + if (CONSP (c) && EQ (XCAR (c), Qt)) + c = XCDR (c); } non_reread: @@ -3727,7 +3736,7 @@ kbd_buffer_events_waiting (void) /* Clear input event EVENT. */ static void -clear_event (union buffered_input_event *event) +clear_event (struct input_event *event) { event->kind = NO_EVENT; } @@ -3864,8 +3873,10 @@ kbd_buffer_get_event (KBOARD **kbp, /* These two kinds of events get special handling and don't actually appear to the command loop. We return nil for them. */ - if (event->kind == SELECTION_REQUEST_EVENT - || event->kind == SELECTION_CLEAR_EVENT) + switch (event->kind) + { + case SELECTION_REQUEST_EVENT: + case SELECTION_CLEAR_EVENT: { #ifdef HAVE_X11 /* Remove it from the buffer before processing it, @@ -3881,202 +3892,58 @@ kbd_buffer_get_event (KBOARD **kbp, emacs_abort (); #endif } + break; -#if defined (HAVE_NS) - else if (event->kind == NS_TEXT_EVENT) - { - if (event->ie.code == KEY_NS_PUT_WORKING_TEXT) - obj = list1 (intern ("ns-put-working-text")); - else - obj = list1 (intern ("ns-unput-working-text")); - kbd_fetch_ptr = event + 1; - if (used_mouse_menu) - *used_mouse_menu = true; - } -#endif - -#if defined (HAVE_X11) || defined (HAVE_NTGUI) \ - || defined (HAVE_NS) - else if (event->kind == DELETE_WINDOW_EVENT) - { - /* Make an event (delete-frame (FRAME)). */ - obj = list2 (Qdelete_frame, list1 (event->ie.frame_or_window)); - kbd_fetch_ptr = event + 1; - } -#endif - -#ifdef HAVE_NTGUI - else if (event->kind == END_SESSION_EVENT) - { - /* Make an event (end-session). */ - obj = list1 (Qend_session); - kbd_fetch_ptr = event + 1; - } -#endif - -#if defined (HAVE_X11) || defined (HAVE_NTGUI) \ - || defined (HAVE_NS) - else if (event->kind == ICONIFY_EVENT) - { - /* Make an event (iconify-frame (FRAME)). */ - obj = list2 (Qiconify_frame, list1 (event->ie.frame_or_window)); - kbd_fetch_ptr = event + 1; - } - else if (event->kind == DEICONIFY_EVENT) - { - /* Make an event (make-frame-visible (FRAME)). */ - obj = list2 (Qmake_frame_visible, list1 (event->ie.frame_or_window)); - kbd_fetch_ptr = event + 1; - } -#endif - else if (event->kind == BUFFER_SWITCH_EVENT) - { - /* The value doesn't matter here; only the type is tested. */ - XSETBUFFER (obj, current_buffer); - kbd_fetch_ptr = event + 1; - } #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \ || defined (HAVE_NS) || defined (USE_GTK) - else if (event->kind == MENU_BAR_ACTIVATE_EVENT) + case MENU_BAR_ACTIVATE_EVENT: { kbd_fetch_ptr = event + 1; input_pending = readable_events (0); if (FRAME_LIVE_P (XFRAME (event->ie.frame_or_window))) x_activate_menubar (XFRAME (event->ie.frame_or_window)); } + break; +#endif +#if defined (HAVE_NS) + case NS_TEXT_EVENT: + if (used_mouse_menu) + *used_mouse_menu = true; + FALLTHROUGH; #endif #ifdef HAVE_NTGUI - else if (event->kind == LANGUAGE_CHANGE_EVENT) - { - /* Make an event (language-change FRAME CODEPAGE LANGUAGE-ID). */ - obj = list4 (Qlanguage_change, - event->ie.frame_or_window, - make_number (event->ie.code), - make_number (event->ie.modifiers)); - kbd_fetch_ptr = event + 1; - } + case END_SESSION_EVENT: + case LANGUAGE_CHANGE_EVENT: #endif -#ifdef USE_FILE_NOTIFY - else if (event->kind == FILE_NOTIFY_EVENT) - { -#ifdef HAVE_W32NOTIFY - /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */ - obj = list3 (Qfile_notify, event->ie.arg, event->ie.frame_or_window); -#else - obj = make_lispy_event (&event->ie); +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (HAVE_NS) + case DELETE_WINDOW_EVENT: + case ICONIFY_EVENT: + case DEICONIFY_EVENT: + case MOVE_FRAME_EVENT: #endif - kbd_fetch_ptr = event + 1; - } -#endif /* USE_FILE_NOTIFY */ - else if (event->kind == SAVE_SESSION_EVENT) - { - obj = list2 (Qsave_session, event->ie.arg); - kbd_fetch_ptr = event + 1; - } - /* Just discard these, by returning nil. - With MULTI_KBOARD, these events are used as placeholders - when we need to randomly delete events from the queue. - (They shouldn't otherwise be found in the buffer, - but on some machines it appears they do show up - even without MULTI_KBOARD.) */ - /* On Windows NT/9X, NO_EVENT is used to delete extraneous - mouse events during a popup-menu call. */ - else if (event->kind == NO_EVENT) - kbd_fetch_ptr = event + 1; - else if (event->kind == HELP_EVENT) - { - Lisp_Object object, position, help, frame, window; - - frame = event->ie.frame_or_window; - object = event->ie.arg; - position = make_number (Time_to_position (event->ie.timestamp)); - window = event->ie.x; - help = event->ie.y; - clear_event (event); - - kbd_fetch_ptr = event + 1; - if (!WINDOWP (window)) - window = Qnil; - obj = Fcons (Qhelp_echo, - list5 (frame, help, window, object, position)); - } - else if (event->kind == FOCUS_IN_EVENT) - { - /* Notification of a FocusIn event. The frame receiving the - focus is in event->frame_or_window. Generate a - switch-frame event if necessary. */ - Lisp_Object frame, focus; - - frame = event->ie.frame_or_window; - focus = FRAME_FOCUS_FRAME (XFRAME (frame)); - if (FRAMEP (focus)) - frame = focus; - - if ( -#ifdef HAVE_X11 - ! NILP (event->ie.arg) - && +#ifdef USE_FILE_NOTIFY + case FILE_NOTIFY_EVENT: #endif - !EQ (frame, internal_last_event_frame) - && !EQ (frame, selected_frame)) - obj = make_lispy_switch_frame (frame); - else - obj = make_lispy_focus_in (frame); - - internal_last_event_frame = frame; - kbd_fetch_ptr = event + 1; - } - else if (event->kind == FOCUS_OUT_EVENT) - { -#ifdef HAVE_WINDOW_SYSTEM - - Display_Info *di; - Lisp_Object frame = event->ie.frame_or_window; - bool focused = false; - - for (di = x_display_list; di && ! focused; di = di->next) - focused = di->x_highlight_frame != 0; - - if (!focused) - obj = make_lispy_focus_out (frame); - -#endif /* HAVE_WINDOW_SYSTEM */ - - kbd_fetch_ptr = event + 1; - } #ifdef HAVE_DBUS - else if (event->kind == DBUS_EVENT) - { - obj = make_lispy_event (&event->ie); - kbd_fetch_ptr = event + 1; - } -#endif -#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (HAVE_NS) - else if (event->kind == MOVE_FRAME_EVENT) - { - /* Make an event (move-frame (FRAME)). */ - obj = list2 (Qmove_frame, list1 (event->ie.frame_or_window)); - kbd_fetch_ptr = event + 1; - } + case DBUS_EVENT: #endif #ifdef HAVE_XWIDGETS - else if (event->kind == XWIDGET_EVENT) - { - obj = make_lispy_event (&event->ie); - kbd_fetch_ptr = event + 1; - } + case XWIDGET_EVENT: #endif - else if (event->kind == CONFIG_CHANGED_EVENT) - { - obj = make_lispy_event (&event->ie); - kbd_fetch_ptr = event + 1; - } - else if (event->kind == SELECT_WINDOW_EVENT) - { - obj = list2 (Qselect_window, list1 (event->ie.frame_or_window)); - kbd_fetch_ptr = event + 1; - } - else + case BUFFER_SWITCH_EVENT: + case SAVE_SESSION_EVENT: + case NO_EVENT: + case HELP_EVENT: + case FOCUS_IN_EVENT: + case CONFIG_CHANGED_EVENT: + case FOCUS_OUT_EVENT: + case SELECT_WINDOW_EVENT: + { + obj = make_lispy_event (&event->ie); + kbd_fetch_ptr = event + 1; + } + break; + default: { /* If this event is on a different frame, return a switch-frame this time, and leave the event in the queue for next time. */ @@ -4126,10 +3993,11 @@ kbd_buffer_get_event (KBOARD **kbp, #endif /* Wipe out this event, to catch bugs. */ - clear_event (event); + clear_event (&event->ie); kbd_fetch_ptr = event + 1; } } + } } /* Try generating a mouse motion event. */ else if (!NILP (do_mouse_tracking) && some_mouse_moved ()) @@ -5439,7 +5307,101 @@ make_lispy_event (struct input_event *event) switch (event->kind) { - /* A simple keystroke. */ +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (HAVE_NS) + case DELETE_WINDOW_EVENT: + /* Make an event (delete-frame (FRAME)). */ + return list2 (Qdelete_frame, list1 (event->frame_or_window)); + + case ICONIFY_EVENT: + /* Make an event (iconify-frame (FRAME)). */ + return list2 (Qiconify_frame, list1 (event->frame_or_window)); + + case DEICONIFY_EVENT: + /* Make an event (make-frame-visible (FRAME)). */ + return list2 (Qmake_frame_visible, list1 (event->frame_or_window)); + + case MOVE_FRAME_EVENT: + /* Make an event (move-frame (FRAME)). */ + return list2 (Qmove_frame, list1 (event->frame_or_window)); +#endif + + case BUFFER_SWITCH_EVENT: + { + /* The value doesn't matter here; only the type is tested. */ + Lisp_Object obj; + XSETBUFFER (obj, current_buffer); + return obj; + } + + /* Just discard these, by returning nil. + With MULTI_KBOARD, these events are used as placeholders + when we need to randomly delete events from the queue. + (They shouldn't otherwise be found in the buffer, + but on some machines it appears they do show up + even without MULTI_KBOARD.) */ + /* On Windows NT/9X, NO_EVENT is used to delete extraneous + mouse events during a popup-menu call. */ + case NO_EVENT: + return Qnil; + + case HELP_EVENT: + { + Lisp_Object frame = event->frame_or_window; + Lisp_Object object = event->arg; + Lisp_Object position + = make_number (Time_to_position (event->timestamp)); + Lisp_Object window = event->x; + Lisp_Object help = event->y; + clear_event (event); + + if (!WINDOWP (window)) + window = Qnil; + return Fcons (Qhelp_echo, + list5 (frame, help, window, object, position)); + } + + case FOCUS_IN_EVENT: + { + /* Notification of a FocusIn event. The frame receiving the + focus is in event->frame_or_window. Generate a + switch-frame event if necessary. */ + + Lisp_Object frame = event->frame_or_window; + Lisp_Object focus = FRAME_FOCUS_FRAME (XFRAME (frame)); + if (FRAMEP (focus)) + frame = focus; + bool switching + = ( +#ifdef HAVE_X11 + ! NILP (event->arg) + && +#endif + !EQ (frame, internal_last_event_frame) + && !EQ (frame, selected_frame)); + internal_last_event_frame = frame; + + return (switching ? make_lispy_switch_frame (frame) + : make_lispy_focus_in (frame)); + } + + case FOCUS_OUT_EVENT: + { +#ifdef HAVE_WINDOW_SYSTEM + + Display_Info *di; + Lisp_Object frame = event->frame_or_window; + bool focused = false; + + for (di = x_display_list; di && ! focused; di = di->next) + focused = di->x_highlight_frame != 0; + + return focused ? Qnil + : make_lispy_focus_out (frame); + +#endif /* HAVE_WINDOW_SYSTEM */ + } + + /* A simple keystroke. */ case ASCII_KEYSTROKE_EVENT: case MULTIBYTE_CHAR_KEYSTROKE_EVENT: { @@ -5503,6 +5465,11 @@ make_lispy_event (struct input_event *event) } #ifdef HAVE_NS + case NS_TEXT_EVENT: + return list1 (intern (event->code == KEY_NS_PUT_WORKING_TEXT + ? "ns-put-working-text" + : "ns-unput-working-text")); + /* NS_NONKEY_EVENTs are just like NON_ASCII_KEYSTROKE_EVENTs, except that they are non-key events (last-nonmenu-event is nil). */ case NS_NONKEY_EVENT: @@ -5565,6 +5532,17 @@ make_lispy_event (struct input_event *event) PTRDIFF_MAX); #ifdef HAVE_NTGUI + case END_SESSION_EVENT: + /* Make an event (end-session). */ + return list1 (Qend_session); + + case LANGUAGE_CHANGE_EVENT: + /* Make an event (language-change FRAME CODEPAGE LANGUAGE-ID). */ + return list4 (Qlanguage_change, + event->frame_or_window, + make_number (event->code), + make_number (event->modifiers)); + case MULTIMEDIA_KEY_EVENT: if (event->code < ARRAYELTS (lispy_multimedia_keys) && event->code > 0 && lispy_multimedia_keys[event->code]) @@ -6058,7 +6036,7 @@ make_lispy_event (struct input_event *event) } case SAVE_SESSION_EVENT: - return Qsave_session; + return list2 (Qsave_session, event->arg); #ifdef HAVE_DBUS case DBUS_EVENT: @@ -6074,12 +6052,15 @@ make_lispy_event (struct input_event *event) } #endif -#if defined HAVE_INOTIFY || defined HAVE_KQUEUE || defined HAVE_GFILENOTIFY +#ifdef USE_FILE_NOTIFY case FILE_NOTIFY_EVENT: - { - return Fcons (Qfile_notify, event->arg); - } -#endif /* HAVE_INOTIFY || HAVE_KQUEUE || HAVE_GFILENOTIFY */ +#ifdef HAVE_W32NOTIFY + /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */ + return list3 (Qfile_notify, event->arg, event->frame_or_window); +#else + return Fcons (Qfile_notify, event->arg); +#endif +#endif /* USE_FILE_NOTIFY */ case CONFIG_CHANGED_EVENT: return list3 (Qconfig_changed_event, @@ -8450,7 +8431,7 @@ read_char_x_menu_prompt (Lisp_Object map, /* Display the menu and get the selection. */ Lisp_Object value; - value = Fx_popup_menu (prev_event, get_keymap (map, 0, 1)); + value = x_popup_menu_1 (prev_event, get_keymap (map, 0, 1)); if (CONSP (value)) { Lisp_Object tem; @@ -8860,6 +8841,11 @@ test_undefined (Lisp_Object binding) && EQ (Fcommand_remapping (binding, Qnil, Qnil), Qundefined))); } +void init_raw_keybuf_count (void) +{ + raw_keybuf_count = 0; +} + /* Read a sequence of keys that ends with a non prefix character, storing it in KEYBUF, a buffer of size BUFSIZE. Prompt with PROMPT. @@ -8916,7 +8902,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, ptrdiff_t keys_start; Lisp_Object current_binding = Qnil; - Lisp_Object first_event = Qnil; /* Index of the first key that has no binding. It is useless to try fkey.start larger than that. */ @@ -8971,7 +8956,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, /* List of events for which a fake prefix key has been generated. */ Lisp_Object fake_prefixed_keys = Qnil; - raw_keybuf_count = 0; + /* raw_keybuf_count is now initialized in (most of) the callers of + read_key_sequence. This is so that in a recursive call (for + mouse menus) a spurious initialization doesn't erase the contents + of raw_keybuf created by the outer call. */ + /* raw_keybuf_count = 0; */ last_nonmenu_event = Qnil; @@ -9026,6 +9015,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, starting_buffer = current_buffer; first_unbound = bufsize + 1; + Lisp_Object first_event = mock_input > 0 ? keybuf[0] : Qnil; /* Build our list of keymaps. If we recognize a function key and replace its escape sequence in @@ -9343,6 +9333,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, && BUFFERP (XWINDOW (window)->contents) && XBUFFER (XWINDOW (window)->contents) != current_buffer) { + GROW_RAW_KEYBUF; ASET (raw_keybuf, raw_keybuf_count, key); raw_keybuf_count++; keybuf[t] = key; @@ -9837,6 +9828,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo, cancel_hourglass (); #endif + raw_keybuf_count = 0; i = read_key_sequence (keybuf, ARRAYELTS (keybuf), prompt, ! NILP (dont_downcase_last), ! NILP (can_return_switch_frame), 0, 0); @@ -10294,7 +10286,7 @@ stuff_buffered_input (Lisp_Object stuffstring) if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT) stuff_char (kbd_fetch_ptr->ie.code); - clear_event (kbd_fetch_ptr); + clear_event (&kbd_fetch_ptr->ie); } input_pending = false; diff --git a/src/keyboard.h b/src/keyboard.h index 9106646ced2..cae949893f4 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -438,6 +438,7 @@ extern unsigned int timers_run; extern bool menu_separator_name_p (const char *); extern bool parse_menu_item (Lisp_Object, int); +extern void init_raw_keybuf_count (void); extern KBOARD *allocate_kboard (Lisp_Object); extern void delete_kboard (KBOARD *); extern void not_single_kboard_state (KBOARD *); diff --git a/src/kqueue.c b/src/kqueue.c index 69d5269d302..7a4f6a471c4 100644 --- a/src/kqueue.c +++ b/src/kqueue.c @@ -24,7 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> -#include <sys/file.h> +#include <fcntl.h> #include "lisp.h" #include "keyboard.h" #include "process.h" diff --git a/src/lastfile.c b/src/lastfile.c index fe8ac85a320..ec5311158e5 100644 --- a/src/lastfile.c +++ b/src/lastfile.c @@ -49,9 +49,6 @@ char my_edata[] = "End of Emacs initialized data"; isn't always a separate section in NT executables). */ char my_endbss[1]; -/* The Alpha MSVC linker globally segregates all static and public bss - data, so we must take both into account to determine the true extent - of the bss area used by Emacs. */ static char _my_endbss[1]; char * my_endbss_static = _my_endbss; diff --git a/src/lisp.h b/src/lisp.h index 57e4f4b9853..a7f0a1d78ff 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -277,6 +277,18 @@ DEFINE_GDB_SYMBOL_END (VALMASK) error !; #endif +/* Lisp_Word is a scalar word suitable for holding a tagged pointer or + integer. Usually it is a pointer to a deliberately-incomplete type + 'union Lisp_X'. However, it is EMACS_INT when Lisp_Objects and + pointers differ in width. */ + +#define LISP_WORDS_ARE_POINTERS (EMACS_INT_MAX == INTPTR_MAX) +#if LISP_WORDS_ARE_POINTERS +typedef union Lisp_X *Lisp_Word; +#else +typedef EMACS_INT Lisp_Word; +#endif + /* Some operations are so commonly executed that they are implemented as macros, not functions, because otherwise runtime performance would suffer too much when compiling with GCC without optimization. @@ -302,16 +314,37 @@ error !; functions, once "gcc -Og" (new to GCC 4.8) works well enough for Emacs developers. Maybe in the year 2020. See Bug#11935. - Commentary for these macros can be found near their corresponding - functions, below. */ - -#if CHECK_LISP_OBJECT_TYPE -# define lisp_h_XLI(o) ((o).i) -# define lisp_h_XIL(i) ((Lisp_Object) { i }) + For the macros that have corresponding functions (defined later), + see these functions for commentary. */ + +/* Convert among the various Lisp-related types: I for EMACS_INT, L + for Lisp_Object, P for void *. */ +#if !CHECK_LISP_OBJECT_TYPE +# if LISP_WORDS_ARE_POINTERS +# define lisp_h_XLI(o) ((EMACS_INT) (o)) +# define lisp_h_XIL(i) ((Lisp_Object) (i)) +# define lisp_h_XLP(o) ((void *) (o)) +# define lisp_h_XPL(p) ((Lisp_Object) (p)) +# else +# define lisp_h_XLI(o) (o) +# define lisp_h_XIL(i) (i) +# define lisp_h_XLP(o) ((void *) (uintptr_t) (o)) +# define lisp_h_XPL(p) ((Lisp_Object) (uintptr_t) (p)) +# endif #else -# define lisp_h_XLI(o) (o) -# define lisp_h_XIL(i) (i) +# if LISP_WORDS_ARE_POINTERS +# define lisp_h_XLI(o) ((EMACS_INT) (o).i) +# define lisp_h_XIL(i) ((Lisp_Object) {(Lisp_Word) (i)}) +# define lisp_h_XLP(o) ((void *) (o).i) +# define lisp_h_XPL(p) lisp_h_XIL (p) +# else +# define lisp_h_XLI(o) ((o).i) +# define lisp_h_XIL(i) ((Lisp_Object) {i}) +# define lisp_h_XLP(o) ((void *) (uintptr_t) (o).i) +# define lisp_h_XPL(p) ((Lisp_Object) {(uintptr_t) (p)}) +# endif #endif + #define lisp_h_CHECK_NUMBER(x) CHECK_TYPE (INTEGERP (x), Qintegerp, x) #define lisp_h_CHECK_SYMBOL(x) CHECK_TYPE (SYMBOLP (x), Qsymbolp, x) #define lisp_h_CHECK_TYPE(ok, predicate, x) \ @@ -346,14 +379,21 @@ error !; XIL ((EMACS_INT) (((EMACS_UINT) (n) << INTTYPEBITS) + Lisp_Int0)) # define lisp_h_XFASTINT(a) XINT (a) # define lisp_h_XINT(a) (XLI (a) >> INTTYPEBITS) -# define lisp_h_XSYMBOL(a) \ +# ifdef __CHKP__ +# define lisp_h_XSYMBOL(a) \ + (eassert (SYMBOLP (a)), \ + (struct Lisp_Symbol *) ((char *) XUNTAG (a, Lisp_Symbol) \ + + (intptr_t) lispsym)) +# else + /* If !__CHKP__ this is equivalent, and is a bit faster as of GCC 7. */ +# define lisp_h_XSYMBOL(a) \ (eassert (SYMBOLP (a)), \ (struct Lisp_Symbol *) ((intptr_t) XLI (a) - Lisp_Symbol \ + (char *) lispsym)) +# endif # define lisp_h_XTYPE(a) ((enum Lisp_Type) (XLI (a) & ~VALMASK)) # define lisp_h_XUNTAG(a, type) \ - __builtin_assume_aligned ((void *) (intptr_t) (XLI (a) - (type)), \ - GCALIGNMENT) + __builtin_assume_aligned ((char *) XLP (a) - (type), GCALIGNMENT) #endif /* When compiling via gcc -O0, define the key operations as macros, as @@ -370,6 +410,8 @@ error !; #if DEFINE_KEY_OPS_AS_MACROS # define XLI(o) lisp_h_XLI (o) # define XIL(i) lisp_h_XIL (i) +# define XLP(o) lisp_h_XLP (o) +# define XPL(p) lisp_h_XPL (p) # define CHECK_NUMBER(x) lisp_h_CHECK_NUMBER (x) # define CHECK_SYMBOL(x) lisp_h_CHECK_SYMBOL (x) # define CHECK_TYPE(ok, predicate, x) lisp_h_CHECK_TYPE (ok, predicate, x) @@ -416,9 +458,8 @@ error !; #define case_Lisp_Int case Lisp_Int0: case Lisp_Int1 /* Idea stolen from GDB. Pedantic GCC complains about enum bitfields, - MSVC doesn't support them, and xlc and Oracle Studio c99 complain - vociferously about them. */ -#if (defined __STRICT_ANSI__ || defined _MSC_VER || defined __IBMC__ \ + and xlc and Oracle Studio c99 complain vociferously about them. */ +#if (defined __STRICT_ANSI__ || defined __IBMC__ \ || (defined __SUNPRO_C && __STDC__)) #define ENUM_BF(TYPE) unsigned int #else @@ -542,24 +583,29 @@ enum Lisp_Fwd_Type resources allocated for it that are not Lisp objects. You can even make a pointer to the function that frees the resources a slot in your object -- this way, the same object could be used to represent - several disparate C structures. */ + several disparate C structures. -#ifdef CHECK_LISP_OBJECT_TYPE - -typedef struct Lisp_Object { EMACS_INT i; } Lisp_Object; + You also need to add the new type to the constant + `cl--typeof-types' in lisp/emacs-lisp/cl-preloaded.el. */ -#define LISP_INITIALLY(i) {i} -#undef CHECK_LISP_OBJECT_TYPE -enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = true }; -#else /* CHECK_LISP_OBJECT_TYPE */ +/* A Lisp_Object is a tagged pointer or integer. Ordinarily it is a + Lisp_Word. However, if CHECK_LISP_OBJECT_TYPE, it is a wrapper + around Lisp_Word, to help catch thinkos like 'Lisp_Object x = 0;'. -/* If a struct type is not wanted, define Lisp_Object as just a number. */ + LISP_INITIALLY (W) initializes a Lisp object with a tagged value + that is a Lisp_Word W. It can be used in a static initializer. */ -typedef EMACS_INT Lisp_Object; -#define LISP_INITIALLY(i) (i) +#ifdef CHECK_LISP_OBJECT_TYPE +typedef struct Lisp_Object { Lisp_Word i; } Lisp_Object; +# define LISP_INITIALLY(w) {w} +# undef CHECK_LISP_OBJECT_TYPE +enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = true }; +#else +typedef Lisp_Word Lisp_Object; +# define LISP_INITIALLY(w) (w) enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = false }; -#endif /* CHECK_LISP_OBJECT_TYPE */ +#endif /* Forward declarations. */ @@ -591,8 +637,10 @@ extern double extract_float (Lisp_Object); /* Low-level conversion and type checking. */ -/* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa. - At the machine level, these operations are no-ops. */ +/* Convert among various types use to implement Lisp_Object. At the + machine level, these operations may widen or narrow their arguments + if pointers differ in width from EMACS_INT; otherwise they are + no-ops. */ INLINE EMACS_INT (XLI) (Lisp_Object o) @@ -606,6 +654,18 @@ INLINE Lisp_Object return lisp_h_XIL (i); } +INLINE void * +(XLP) (Lisp_Object o) +{ + return lisp_h_XLP (o); +} + +INLINE Lisp_Object +(XPL) (void *p) +{ + return lisp_h_XPL (p); +} + /* Extract A's type. */ INLINE enum Lisp_Type @@ -633,8 +693,9 @@ INLINE void * #if USE_LSB_TAG return lisp_h_XUNTAG (a, type); #else - intptr_t i = USE_LSB_TAG ? XLI (a) - type : XLI (a) & VALMASK; - return (void *) i; + EMACS_UINT utype = type; + char *p = XLP (a); + return p - (utype << (USE_LSB_TAG ? 0 : VALBITS)); #endif } @@ -745,35 +806,46 @@ verify (alignof (struct Lisp_Symbol) % GCALIGNMENT == 0); #define DEFUN_ARGS_8 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, \ Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object) -/* Yield a signed integer that contains TAG along with PTR. +/* Typedefs useful for implementing TAG_PTR. untagged_ptr represents + a pointer before tagging, and Lisp_Word_tag contains a + possibly-shifted tag to be added to an untagged_ptr to convert it + to a Lisp_Word. */ +#if LISP_WORDS_ARE_POINTERS +/* untagged_ptr is a pointer so that the compiler knows that TAG_PTR + yields a pointer; this can help with gcc -fcheck-pointer-bounds. + It is char * so that adding a tag uses simple machine addition. */ +typedef char *untagged_ptr; +typedef uintptr_t Lisp_Word_tag; +#else +/* untagged_ptr is an unsigned integer instead of a pointer, so that + it can be added to the possibly-wider Lisp_Word_tag type without + losing information. */ +typedef uintptr_t untagged_ptr; +typedef EMACS_UINT Lisp_Word_tag; +#endif - Sign-extend pointers when USE_LSB_TAG (this simplifies emacs-module.c), - and zero-extend otherwise (that’s a bit faster here). - Sign extension matters only when EMACS_INT is wider than a pointer. */ +/* An initializer for a Lisp_Object that contains TAG along with PTR. */ #define TAG_PTR(tag, ptr) \ - (USE_LSB_TAG \ - ? (intptr_t) (ptr) + (tag) \ - : (EMACS_INT) (((EMACS_UINT) (tag) << VALBITS) + (uintptr_t) (ptr))) - -/* Yield an integer that contains a symbol tag along with OFFSET. - OFFSET should be the offset in bytes from 'lispsym' to the symbol. */ -#define TAG_SYMOFFSET(offset) TAG_PTR (Lisp_Symbol, offset) - -/* XLI_BUILTIN_LISPSYM (iQwhatever) is equivalent to - XLI (builtin_lisp_symbol (Qwhatever)), - except the former expands to an integer constant expression. */ -#define XLI_BUILTIN_LISPSYM(iname) TAG_SYMOFFSET ((iname) * sizeof *lispsym) + LISP_INITIALLY ((Lisp_Word) \ + ((untagged_ptr) (ptr) \ + + ((Lisp_Word_tag) (tag) << (USE_LSB_TAG ? 0 : VALBITS)))) /* LISPSYM_INITIALLY (Qfoo) is equivalent to Qfoo except it is designed for use as an initializer, even for a constant initializer. */ -#define LISPSYM_INITIALLY(name) LISP_INITIALLY (XLI_BUILTIN_LISPSYM (i##name)) +#define LISPSYM_INITIALLY(name) \ + TAG_PTR (Lisp_Symbol, (char *) (intptr_t) ((i##name) * sizeof *lispsym)) /* Declare extern constants for Lisp symbols. These can be helpful when using a debugger like GDB, on older platforms where the debug - format does not represent C macros. */ -#define DEFINE_LISP_SYMBOL(name) \ - DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \ - DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name)) + format does not represent C macros. However, they are unbounded + and would just be asking for trouble if checking pointer bounds. */ +#ifdef __CHKP__ +# define DEFINE_LISP_SYMBOL(name) +#else +# define DEFINE_LISP_SYMBOL(name) \ + DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \ + DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name)) +#endif /* The index of the C-defined Lisp symbol SYM. This can be used in a static initializer. */ @@ -837,6 +909,11 @@ INLINE struct Lisp_Symbol * eassert (SYMBOLP (a)); intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol); void *p = (char *) lispsym + i; +# ifdef __CHKP__ + /* Bypass pointer checking. Although this could be improved it is + probably not worth the trouble. */ + p = __builtin___bnd_set_ptr_bounds (p, sizeof (struct Lisp_Symbol)); +# endif return p; #endif } @@ -844,7 +921,20 @@ INLINE struct Lisp_Symbol * INLINE Lisp_Object make_lisp_symbol (struct Lisp_Symbol *sym) { - Lisp_Object a = XIL (TAG_SYMOFFSET ((char *) sym - (char *) lispsym)); +#ifdef __CHKP__ + /* Although '__builtin___bnd_narrow_ptr_bounds (sym, sym, sizeof *sym)' + should be more efficient, it runs afoul of GCC bug 83251 + <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83251>. + Also, attempting to call __builtin___bnd_chk_ptr_bounds (sym, sizeof *sym) + here seems to trigger a GCC bug, as yet undiagnosed. */ + char *addr = __builtin___bnd_set_ptr_bounds (sym, sizeof *sym); + char *symoffset = addr - (intptr_t) lispsym; +#else + /* If !__CHKP__, GCC 7 x86-64 generates faster code if lispsym is + cast to char * rather than to intptr_t. */ + char *symoffset = (char *) ((char *) sym - (char *) lispsym); +#endif + Lisp_Object a = TAG_PTR (Lisp_Symbol, symoffset); eassert (XSYMBOL (a) == sym); return a; } @@ -1062,7 +1152,7 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper) INLINE Lisp_Object make_lisp_ptr (void *ptr, enum Lisp_Type type) { - Lisp_Object a = XIL (TAG_PTR (type, ptr)); + Lisp_Object a = TAG_PTR (type, ptr); eassert (XTYPE (a) == type && XUNTAG (a, type) == ptr); return a; } @@ -1133,7 +1223,7 @@ XINTPTR (Lisp_Object a) INLINE Lisp_Object make_pointer_integer (void *p) { - Lisp_Object a = XIL (TAG_PTR (Lisp_Int0, p)); + Lisp_Object a = TAG_PTR (Lisp_Int0, p); eassert (INTEGERP (a) && XINTPTR (a) == p); return a; } @@ -1645,8 +1735,10 @@ gc_aset (Lisp_Object array, ptrdiff_t idx, Lisp_Object val) /* True, since Qnil's representation is zero. Every place in the code that assumes Qnil is zero should verify (NIL_IS_ZERO), to make it easy - to find such assumptions later if we change Qnil to be nonzero. */ -enum { NIL_IS_ZERO = XLI_BUILTIN_LISPSYM (iQnil) == 0 }; + to find such assumptions later if we change Qnil to be nonzero. + Test iQnil and Lisp_Symbol instead of Qnil directly, since the latter + is not suitable for use in an integer constant expression. */ +enum { NIL_IS_ZERO = iQnil == 0 && Lisp_Symbol == 0 }; /* Clear the object addressed by P, with size NBYTES, so that all its bytes are zero and all its Lisp values are nil. */ @@ -2960,23 +3052,12 @@ CHECK_NUMBER_CDR (Lisp_Object x) /* This version of DEFUN declares a function prototype with the right arguments, so we can catch errors with maxargs at compile-time. */ -#ifdef _MSC_VER -#define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \ - Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \ - static struct Lisp_Subr sname = \ - { { (PVEC_SUBR << PSEUDOVECTOR_AREA_BITS) \ - | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)) }, \ - { (Lisp_Object (__cdecl *)(void))fnname }, \ - minargs, maxargs, lname, intspec, 0}; \ - Lisp_Object fnname -#else /* not _MSC_VER */ #define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \ static struct Lisp_Subr sname = \ { { PVEC_SUBR << PSEUDOVECTOR_AREA_BITS }, \ { .a ## maxargs = fnname }, \ minargs, maxargs, lname, intspec, 0}; \ Lisp_Object fnname -#endif /* defsubr (Sname); is how we define the symbol for function `name' at start-up time. */ @@ -3464,6 +3545,12 @@ extern int x_bitmap_mask (struct frame *, ptrdiff_t); extern void reset_image_types (void); extern void syms_of_image (void); +#ifdef HAVE_JSON +/* Defined in json.c. */ +extern void init_json (void); +extern void syms_of_json (void); +#endif + /* Defined in insdel.c. */ extern void move_gap_both (ptrdiff_t, ptrdiff_t); extern _Noreturn void buffer_overflow (void); @@ -3887,6 +3974,7 @@ extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp extern Lisp_Object internal_condition_case_n (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); +extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (Lisp_Object)); extern struct handler *push_handler (Lisp_Object, enum handlertype); extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); extern void specbind (Lisp_Object, Lisp_Object); @@ -4042,7 +4130,7 @@ extern _Noreturn void report_file_error (const char *, Lisp_Object); extern _Noreturn void report_file_notify_error (const char *, Lisp_Object); extern bool internal_delete_file (Lisp_Object); extern Lisp_Object emacs_readlinkat (int, const char *); -extern bool file_directory_p (const char *); +extern bool file_directory_p (Lisp_Object); extern bool file_accessible_directory_p (Lisp_Object); extern void init_fileio (void); extern void syms_of_fileio (void); @@ -4397,6 +4485,11 @@ extern void syms_of_gfilenotify (void); extern void syms_of_w32notify (void); #endif +#if defined HAVE_NTGUI || defined CYGWIN +/* Defined in w32cygwinx.c. */ +extern void syms_of_w32cygwinx (void); +#endif + /* Defined in xfaces.c. */ extern Lisp_Object Vface_alternative_font_family_alist; extern Lisp_Object Vface_alternative_font_registry_alist; @@ -4422,9 +4515,9 @@ extern void syms_of_xterm (void); extern char *x_get_keysym_name (int); #endif /* HAVE_WINDOW_SYSTEM */ -#ifdef HAVE_LIBXML2 /* Defined in xml.c. */ extern void syms_of_xml (void); +#ifdef HAVE_LIBXML2 extern void xml_cleanup_parser (void); #endif diff --git a/src/lread.c b/src/lread.c index 3104c441ecf..0ea7677300b 100644 --- a/src/lread.c +++ b/src/lread.c @@ -147,10 +147,10 @@ static ptrdiff_t prev_saved_doc_string_length; /* This is the file position that string came from. */ static file_offset prev_saved_doc_string_position; -/* True means inside a new-style backquote - with no surrounding parentheses. - Fread initializes this to false, so we need not specbind it - or worry about what happens to it when there is an error. */ +/* True means inside a new-style backquote with no surrounding + parentheses. Fread initializes this to the value of + `force_new_style_backquotes', so we need not specbind it or worry + about what happens to it when there is an error. */ static bool new_backquote_flag; /* A list of file names for files being loaded in Fload. Used to @@ -164,6 +164,8 @@ static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), static void readevalloop (Lisp_Object, struct infile *, Lisp_Object, bool, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); + +static void build_load_history (Lisp_Object, bool); /* Functions that read one byte from the current source READCHARFUN or unreads one byte. If the integer argument C is -1, it returns @@ -1003,13 +1005,15 @@ load_error_handler (Lisp_Object data) return Qnil; } -static void -load_warn_old_style_backquotes (Lisp_Object file) +static _Noreturn void +load_error_old_style_backquotes (void) { - if (!NILP (Vlread_old_style_backquotes)) + if (NILP (Vload_file_name)) + xsignal1 (Qerror, build_string ("Old-style backquotes detected!")); + else { AUTO_STRING (format, "Loading `%s': old-style backquotes detected!"); - CALLN (Fmessage, format, file); + xsignal1 (Qerror, CALLN (Fformat_message, format, Vload_file_name)); } } @@ -1119,7 +1123,7 @@ Return t if the file exists and loads successfully. */) (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage, Lisp_Object nosuffix, Lisp_Object must_suffix) { - FILE *stream; + FILE *stream UNINIT; int fd; int fd_index UNINIT; ptrdiff_t count = SPECPDL_INDEX (); @@ -1244,8 +1248,9 @@ Return t if the file exists and loads successfully. */) } #ifdef HAVE_MODULES - if (suffix_p (found, MODULES_SUFFIX)) - return unbind_to (count, Fmodule_load (found)); + bool is_module = suffix_p (found, MODULES_SUFFIX); +#else + bool is_module = false; #endif /* Check if we're stuck in a recursive load cycle. @@ -1282,10 +1287,6 @@ Return t if the file exists and loads successfully. */) version = -1; - /* Check for the presence of old-style quotes and warn about them. */ - specbind (Qlread_old_style_backquotes, Qnil); - record_unwind_protect (load_warn_old_style_backquotes, file); - /* Check for the presence of unescaped character literals and warn about them. */ specbind (Qlread_unescaped_character_literals, Qnil); @@ -1350,7 +1351,7 @@ Return t if the file exists and loads successfully. */) } /* !load_prefer_newer */ } } - else + else if (!is_module) { /* We are loading a source file (*.el). */ if (!NILP (Vload_source_file_function)) @@ -1377,7 +1378,7 @@ Return t if the file exists and loads successfully. */) stream = NULL; errno = EINVAL; } - else + else if (!is_module) { #ifdef WINDOWSNT emacs_close (fd); @@ -1388,9 +1389,23 @@ Return t if the file exists and loads successfully. */) stream = fdopen (fd, fmode); #endif } - if (! stream) - report_file_error ("Opening stdio stream", file); - set_unwind_protect_ptr (fd_index, close_infile_unwind, stream); + + if (is_module) + { + /* `module-load' uses the file name, so we can close the stream + now. */ + if (fd >= 0) + { + emacs_close (fd); + clear_unwind_protect (fd_index); + } + } + else + { + if (! stream) + report_file_error ("Opening stdio stream", file); + set_unwind_protect_ptr (fd_index, close_infile_unwind, stream); + } if (! NILP (Vpurify_flag)) Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); @@ -1400,6 +1415,8 @@ Return t if the file exists and loads successfully. */) if (!safe_p) message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...", file, 1); + else if (is_module) + message_with_string ("Loading %s (module)...", file, 1); else if (!compiled) message_with_string ("Loading %s (source)...", file, 1); else if (newer) @@ -1413,24 +1430,39 @@ Return t if the file exists and loads successfully. */) specbind (Qinhibit_file_name_operation, Qnil); specbind (Qload_in_progress, Qt); - struct infile input; - input.stream = stream; - input.lookahead = 0; - infile = &input; - - if (lisp_file_lexically_bound_p (Qget_file_char)) - Fset (Qlexical_binding, Qt); - - if (! version || version >= 22) - readevalloop (Qget_file_char, &input, hist_file_name, - 0, Qnil, Qnil, Qnil, Qnil); + if (is_module) + { +#ifdef HAVE_MODULES + specbind (Qcurrent_load_list, Qnil); + LOADHIST_ATTACH (found); + Fmodule_load (found); + build_load_history (found, true); +#else + /* This cannot happen. */ + emacs_abort (); +#endif + } else { - /* We can't handle a file which was compiled with - byte-compile-dynamic by older version of Emacs. */ - specbind (Qload_force_doc_strings, Qt); - readevalloop (Qget_emacs_mule_file_char, &input, hist_file_name, - 0, Qnil, Qnil, Qnil, Qnil); + struct infile input; + input.stream = stream; + input.lookahead = 0; + infile = &input; + + if (lisp_file_lexically_bound_p (Qget_file_char)) + Fset (Qlexical_binding, Qt); + + if (! version || version >= 22) + readevalloop (Qget_file_char, &input, hist_file_name, + 0, Qnil, Qnil, Qnil, Qnil); + else + { + /* We can't handle a file which was compiled with + byte-compile-dynamic by older version of Emacs. */ + specbind (Qload_force_doc_strings, Qt); + readevalloop (Qget_emacs_mule_file_char, &input, hist_file_name, + 0, Qnil, Qnil, Qnil, Qnil); + } } unbind_to (count, Qnil); @@ -1451,6 +1483,8 @@ Return t if the file exists and loads successfully. */) if (!safe_p) message_with_string ("Loading %s (compiled; note unsafe, not compiled in Emacs)...done", file, 1); + else if (is_module) + message_with_string ("Loading %s (module)...done", file, 1); else if (!compiled) message_with_string ("Loading %s (source)...done", file, 1); else if (newer) @@ -1668,7 +1702,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, AT_EACCESS) == 0) { - if (file_directory_p (pfn)) + if (file_directory_p (encoded_fn)) last_errno = EISDIR; else fd = 1; @@ -2194,7 +2228,7 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end) Lisp_Object retval; readchar_count = 0; - new_backquote_flag = 0; + new_backquote_flag = force_new_style_backquotes; /* We can get called from readevalloop which may have set these already. */ if (! HASH_TABLE_P (read_objects_map) @@ -2269,7 +2303,7 @@ read0 (Lisp_Object readcharfun) return val; xsignal1 (Qinvalid_read_syntax, - Fmake_string (make_number (1), make_number (c))); + Fmake_string (make_number (1), make_number (c), Qnil)); } /* Grow a read buffer BUF that contains OFFSET useful bytes of data, @@ -3178,10 +3212,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) first_in_list exception (old-style can still be obtained via "(\`" anyway). */ if (!new_backquote_flag && first_in_list && next_char == ' ') - { - Vlread_old_style_backquotes = Qt; - goto default_label; - } + load_error_old_style_backquotes (); else { Lisp_Object value; @@ -3232,10 +3263,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) return list2 (comma_type, value); } else - { - Vlread_old_style_backquotes = Qt; - goto default_label; - } + load_error_old_style_backquotes (); } case '?': { @@ -3423,7 +3451,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) row. */ FALLTHROUGH; default: - default_label: if (c <= 040) goto retry; if (c == NO_BREAK_SPACE) goto retry; @@ -3479,6 +3506,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) if (! NILP (result)) return unbind_to (count, result); } + if (!quoted && multibyte) + { + int ch = STRING_CHAR ((unsigned char *) read_buffer); + if (confusable_symbol_character_p (ch)) + xsignal2 (Qinvalid_read_syntax, build_string ("strange quote"), + CALLN (Fstring, make_number (ch))); + } { Lisp_Object result; ptrdiff_t nbytes = p - read_buffer; @@ -4888,7 +4922,7 @@ directory. These file names are converted to absolute at startup. */); If the file loaded had extension `.elc', and the corresponding source file exists, this variable contains the name of source file, suitable for use by functions like `custom-save-all' which edit the init file. -While Emacs loads and evaluates the init file, value is the real name +While Emacs loads and evaluates any init file, value is the real name of the file, regardless of whether or not it has the `.elc' extension. */); Vuser_init_file = Qnil; @@ -4978,12 +5012,6 @@ variables, this must be set in the first line of a file. */); doc: /* List of buffers being read from by calls to `eval-buffer' and `eval-region'. */); Veval_buffer_list = Qnil; - DEFVAR_LISP ("lread--old-style-backquotes", Vlread_old_style_backquotes, - doc: /* Set to non-nil when `read' encounters an old-style backquote. -For internal use only. */); - Vlread_old_style_backquotes = Qnil; - DEFSYM (Qlread_old_style_backquotes, "lread--old-style-backquotes"); - DEFVAR_LISP ("lread--unescaped-character-literals", Vlread_unescaped_character_literals, doc: /* List of deprecated unescaped character literals encountered by `read'. @@ -5008,6 +5036,17 @@ Note that if you customize this, obviously it will not affect files that are loaded before your customizations are read! */); load_prefer_newer = 0; + DEFVAR_BOOL ("force-new-style-backquotes", force_new_style_backquotes, + doc: /* Non-nil means to always use the current syntax for backquotes. +If nil, `load' and `read' raise errors when encountering some +old-style variants of backquote and comma. If non-nil, these +constructs are always interpreted as described in the Info node +`(elisp)Backquotes', even if that interpretation is incompatible with +previous versions of Emacs. Setting this variable to non-nil makes +Emacs compatible with the behavior planned for Emacs 28. In Emacs 28, +this variable will become obsolete. */); + force_new_style_backquotes = false; + /* Vsource_directory was initialized in init_lread. */ DEFSYM (Qcurrent_load_list, "current-load-list"); diff --git a/src/macfont.m b/src/macfont.m index dd7c50f2719..817071fa44f 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -1441,8 +1441,6 @@ macfont_get_glyph_for_character (struct font *font, UTF32Char c) CGGlyph *glyphs; int i, len; int nrows; - dispatch_queue_t queue; - dispatch_group_t group = NULL; int nkeys; if (row != 0) diff --git a/src/menu.c b/src/menu.c index d5e1638b7cd..93e793a5d91 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1112,51 +1112,8 @@ into menu items. */) return Qnil; } - -DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, - doc: /* Pop up a deck-of-cards menu and return user's selection. -POSITION is a position specification. This is either a mouse button event -or a list ((XOFFSET YOFFSET) WINDOW) -where XOFFSET and YOFFSET are positions in pixels from the top left -corner of WINDOW. (WINDOW may be a window or a frame object.) -This controls the position of the top left of the menu as a whole. -If POSITION is t, it means to use the current mouse position. - -MENU is a specifier for a menu. For the simplest case, MENU is a keymap. -The menu items come from key bindings that have a menu string as well as -a definition; actually, the "definition" in such a key binding looks like -\(STRING . REAL-DEFINITION). To give the menu a title, put a string into -the keymap as a top-level element. - -If REAL-DEFINITION is nil, that puts a nonselectable string in the menu. -Otherwise, REAL-DEFINITION should be a valid key binding definition. - -You can also use a list of keymaps as MENU. - Then each keymap makes a separate pane. - -When MENU is a keymap or a list of keymaps, the return value is the -list of events corresponding to the user's choice. Note that -`x-popup-menu' does not actually execute the command bound to that -sequence of events. - -Alternatively, you can specify a menu of multiple panes - with a list of the form (TITLE PANE1 PANE2...), -where each pane is a list of form (TITLE ITEM1 ITEM2...). -Each ITEM is normally a cons cell (STRING . VALUE); -but a string can appear as an item--that makes a nonselectable line -in the menu. -With this form of menu, the return value is VALUE from the chosen item. - -If POSITION is nil, don't display the menu at all, just precalculate the -cached information about equivalent key sequences. - -If the user gets rid of the menu without making a valid choice, for -instance by clicking the mouse away from a valid choice or by typing -keyboard input, then this normally results in a quit and -`x-popup-menu' does not return. But if POSITION is a mouse button -event (indicating that the user invoked the menu with the mouse) then -no quit occurs and `x-popup-menu' returns nil. */) - (Lisp_Object position, Lisp_Object menu) +Lisp_Object +x_popup_menu_1 (Lisp_Object position, Lisp_Object menu) { Lisp_Object keymap, tem, tem2; int xpos = 0, ypos = 0; @@ -1443,6 +1400,55 @@ no quit occurs and `x-popup-menu' returns nil. */) return selection; } +DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, + doc: /* Pop up a deck-of-cards menu and return user's selection. +POSITION is a position specification. This is either a mouse button event +or a list ((XOFFSET YOFFSET) WINDOW) +where XOFFSET and YOFFSET are positions in pixels from the top left +corner of WINDOW. (WINDOW may be a window or a frame object.) +This controls the position of the top left of the menu as a whole. +If POSITION is t, it means to use the current mouse position. + +MENU is a specifier for a menu. For the simplest case, MENU is a keymap. +The menu items come from key bindings that have a menu string as well as +a definition; actually, the "definition" in such a key binding looks like +\(STRING . REAL-DEFINITION). To give the menu a title, put a string into +the keymap as a top-level element. + +If REAL-DEFINITION is nil, that puts a nonselectable string in the menu. +Otherwise, REAL-DEFINITION should be a valid key binding definition. + +You can also use a list of keymaps as MENU. + Then each keymap makes a separate pane. + +When MENU is a keymap or a list of keymaps, the return value is the +list of events corresponding to the user's choice. Note that +`x-popup-menu' does not actually execute the command bound to that +sequence of events. + +Alternatively, you can specify a menu of multiple panes + with a list of the form (TITLE PANE1 PANE2...), +where each pane is a list of form (TITLE ITEM1 ITEM2...). +Each ITEM is normally a cons cell (STRING . VALUE); +but a string can appear as an item--that makes a nonselectable line +in the menu. +With this form of menu, the return value is VALUE from the chosen item. + +If POSITION is nil, don't display the menu at all, just precalculate the +cached information about equivalent key sequences. + +If the user gets rid of the menu without making a valid choice, for +instance by clicking the mouse away from a valid choice or by typing +keyboard input, then this normally results in a quit and +`x-popup-menu' does not return. But if POSITION is a mouse button +event (indicating that the user invoked the menu with the mouse) then +no quit occurs and `x-popup-menu' returns nil. */) + (Lisp_Object position, Lisp_Object menu) +{ + init_raw_keybuf_count (); + return x_popup_menu_1 (position, menu); +} + /* If F's terminal is not capable of displaying a popup dialog, emulate it with a menu. */ diff --git a/src/menu.h b/src/menu.h index 4c4ac83424f..104f6dc81d2 100644 --- a/src/menu.h +++ b/src/menu.h @@ -60,4 +60,5 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, int, extern Lisp_Object tty_menu_show (struct frame *, int, int, int, Lisp_Object, const char **); extern ptrdiff_t menu_item_width (const unsigned char *); +extern Lisp_Object x_popup_menu_1 (Lisp_Object position, Lisp_Object menu); #endif /* MENU_H */ diff --git a/src/minibuf.c b/src/minibuf.c index cbb0898a9ab..95e62ceddab 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -325,19 +325,6 @@ If the current buffer is not a minibuffer, return its entire contents. */) return make_buffer_string (prompt_end, ZV, 0); } -DEFUN ("minibuffer-completion-contents", Fminibuffer_completion_contents, - Sminibuffer_completion_contents, 0, 0, 0, - doc: /* Return the user input in a minibuffer before point as a string. -That is what completion commands operate on. -If the current buffer is not a minibuffer, return its entire contents. */) - (void) -{ - ptrdiff_t prompt_end = XINT (Fminibuffer_prompt_end ()); - if (PT < prompt_end) - error ("Cannot do completion in the prompt"); - return make_buffer_string (prompt_end, PT, 1); -} - /* Read from the minibuffer using keymap MAP and initial contents INITIAL, putting point minus BACKUP_N bytes from the end of INITIAL, @@ -2127,7 +2114,6 @@ characters. This variable should never be set globally. */); defsubr (&Sminibuffer_prompt_end); defsubr (&Sminibuffer_contents); defsubr (&Sminibuffer_contents_no_properties); - defsubr (&Sminibuffer_completion_contents); defsubr (&Stry_completion); defsubr (&Sall_completions); diff --git a/src/msdos.c b/src/msdos.c index 94e975eaa21..eedbf7b1a6c 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -1791,7 +1791,7 @@ internal_terminal_init (void) } Vinitial_window_system = Qpc; - Vwindow_system_version = make_number (26); /* RE Emacs version */ + Vwindow_system_version = make_number (27); /* RE Emacs version */ tty->terminal->type = output_msdos_raw; /* If Emacs was dumped on DOS/V machine, forget the stale VRAM diff --git a/src/nsfns.m b/src/nsfns.m index 7f2f060dda8..6407560d89e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -61,7 +61,6 @@ static int as_status; static ptrdiff_t image_cache_refcount; static struct ns_display_info *ns_display_info_for_name (Lisp_Object); -static void ns_set_name_as_filename (struct frame *); /* ========================================================================== @@ -483,17 +482,10 @@ x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { NSTRACE ("x_implicitly_set_name"); - Lisp_Object frame_title = buffer_local_value - (Qframe_title_format, XWINDOW (f->selected_window)->contents); - Lisp_Object icon_title = buffer_local_value - (Qicon_title_format, XWINDOW (f->selected_window)->contents); + if (ns_use_proxy_icon) + ns_set_represented_filename (f); - /* Deal with NS specific format t. */ - if (FRAME_NS_P (f) && ((FRAME_ICONIFIED_P (f) && EQ (icon_title, Qt)) - || EQ (frame_title, Qt))) - ns_set_name_as_filename (f); - else - ns_set_name (f, arg, 0); + ns_set_name (f, arg, 0); } @@ -520,78 +512,6 @@ x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name) ns_set_name_internal (f, name); } - -static void -ns_set_name_as_filename (struct frame *f) -{ - NSView *view; - Lisp_Object name, filename; - Lisp_Object buf = XWINDOW (f->selected_window)->contents; - const char *title; - NSAutoreleasePool *pool; - Lisp_Object encoded_name, encoded_filename; - NSString *str; - NSTRACE ("ns_set_name_as_filename"); - - if (f->explicit_name || ! NILP (f->title)) - return; - - block_input (); - pool = [[NSAutoreleasePool alloc] init]; - filename = BVAR (XBUFFER (buf), filename); - name = BVAR (XBUFFER (buf), name); - - if (NILP (name)) - { - if (! NILP (filename)) - name = Ffile_name_nondirectory (filename); - else - name = build_string ([ns_app_name UTF8String]); - } - - encoded_name = ENCODE_UTF_8 (name); - - view = FRAME_NS_VIEW (f); - - title = FRAME_ICONIFIED_P (f) ? [[[view window] miniwindowTitle] UTF8String] - : [[[view window] title] UTF8String]; - - if (title && (! strcmp (title, SSDATA (encoded_name)))) - { - [pool release]; - unblock_input (); - return; - } - - str = [NSString stringWithUTF8String: SSDATA (encoded_name)]; - if (str == nil) str = @"Bad coding"; - - if (FRAME_ICONIFIED_P (f)) - [[view window] setMiniwindowTitle: str]; - else - { - NSString *fstr; - - if (! NILP (filename)) - { - encoded_filename = ENCODE_UTF_8 (filename); - - fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)]; - if (fstr == nil) fstr = @""; - } - else - fstr = @""; - - ns_set_represented_filename (fstr, f); - [[view window] setTitle: str]; - fset_name (f, name); - } - - [pool release]; - unblock_input (); -} - - void ns_set_doc_edited (void) { @@ -1078,15 +998,7 @@ get_geometry_from_preferences (struct ns_display_info *dpyinfo, DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1, 1, 0, - doc: /* Make a new Nextstep window, called a "frame" in Emacs terms. -Return an Emacs frame object. -PARMS is an alist of frame parameters. -If the parameters specify that the frame should not have a minibuffer, -and do not specify a specific minibuffer window to use, -then `default-minibuffer-frame' must be a frame whose minibuffer can -be shared by the new frame. - -This function is an internal primitive--use `make-frame' instead. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object parms) { struct frame *f; @@ -1782,7 +1694,7 @@ If VALUE is nil, the default is removed. */) DEFUN ("x-server-max-request-size", Fx_server_max_request_size, Sx_server_max_request_size, 0, 1, 0, - doc: /* This function is a no-op. It is only present for completeness. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -1793,12 +1705,7 @@ DEFUN ("x-server-max-request-size", Fx_server_max_request_size, DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, - doc: /* Return the "vendor ID" string of Nextstep display server TERMINAL. -\(Labeling every distributor as a "vendor" embodies the false assumption -that operating systems cannot be developed and distributed noncommercially.) -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -1811,14 +1718,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, - doc: /* Return the version numbers of the server of display TERMINAL. -The value is a list of three integers: the major and minor -version numbers of the X Protocol in use, and the distributor-specific release -number. See also the function `x-server-vendor'. - -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -1833,14 +1733,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, - doc: /* Return the number of screens on Nextstep display server TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -Note: "screen" here is not in Nextstep terminology but in X11's. For -the number of physical monitors, use `(length -\(display-monitor-attributes-list TERMINAL))' instead. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -1849,14 +1742,7 @@ the number of physical monitors, use `(length DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, - doc: /* Return the height in millimeters of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the height in millimeters for -all physical monitors associated with TERMINAL. To get information -for each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { struct ns_display_info *dpyinfo = check_ns_display_info (terminal); @@ -1866,14 +1752,7 @@ for each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, - doc: /* Return the width in millimeters of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the width in millimeters for -all physical monitors associated with TERMINAL. To get information -for each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { struct ns_display_info *dpyinfo = check_ns_display_info (terminal); @@ -1884,22 +1763,21 @@ for each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store, 0, 1, 0, - doc: /* Return an indication of whether the Nextstep display TERMINAL does backing store. -The value may be `buffered', `retained', or `non-retained'. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); + /* Note that the xfns.c version has different return values. */ switch ([ns_get_window (terminal) backingType]) { case NSBackingStoreBuffered: return intern ("buffered"); +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 case NSBackingStoreRetained: return intern ("retained"); case NSBackingStoreNonretained: return intern ("non-retained"); +#endif default: error ("Strange value for backingType parameter of frame"); } @@ -1909,13 +1787,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-visual-class", Fx_display_visual_class, Sx_display_visual_class, 0, 1, 0, - doc: /* Return the visual class of the Nextstep display TERMINAL. -The value is one of the symbols `static-gray', `gray-scale', -`static-color', `pseudo-color', `true-color', or `direct-color'. - -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { NSWindowDepth depth; @@ -1941,10 +1813,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-save-under", Fx_display_save_under, Sx_display_save_under, 0, 1, 0, - doc: /* Return t if TERMINAL supports the save-under feature. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -1953,9 +1822,11 @@ If omitted or nil, that stands for the selected frame's display. */) case NSBackingStoreBuffered: return Qt; +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 case NSBackingStoreRetained: case NSBackingStoreNonretained: return Qnil; +#endif default: error ("Strange value for backingType parameter of frame"); @@ -1966,12 +1837,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, 1, 3, 0, - doc: /* Open a connection to a display server. -DISPLAY is the name of the display to connect to. -Optional second arg XRM-STRING is a string of resources in xrdb format. -If the optional third arg MUST-SUCCEED is non-nil, -terminate Emacs if we can't open the connection. -\(In the Nextstep version, the last two arguments are currently ignored.) */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed) { struct ns_display_info *dpyinfo; @@ -1996,10 +1862,7 @@ terminate Emacs if we can't open the connection. DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0, - doc: /* Close the connection to TERMINAL's Nextstep display server. -For TERMINAL, specify a terminal object, a frame or a display name (a -string). If TERMINAL is nil, that stands for the selected frame's -terminal. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -2009,7 +1872,7 @@ terminal. */) DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, - doc: /* Return the list of display names that Emacs has connections to. */) + doc: /* SKIP: real doc in xfns.c. */) (void) { Lisp_Object result = Qnil; @@ -2382,8 +2245,7 @@ x_get_focus_frame (struct frame *frame) DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, - doc: /* Internal function called by `color-defined-p', which see. -\(Note that the Nextstep version of this function ignores FRAME.) */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object color, Lisp_Object frame) { NSColor * col; @@ -2393,7 +2255,7 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, - doc: /* Internal function called by `color-values', which see. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object color, Lisp_Object frame) { NSColor * col; @@ -2418,7 +2280,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, - doc: /* Internal function called by `display-color-p', which see. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { NSWindowDepth depth; @@ -2436,11 +2298,7 @@ DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, 0, 1, 0, - doc: /* Return t if the Nextstep display supports shades of gray. -Note that color displays do support shades of gray. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { NSWindowDepth depth; @@ -2454,14 +2312,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, 0, 1, 0, - doc: /* Return the width in pixels of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the pixel width for all -physical monitors associated with TERMINAL. To get information for -each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { struct ns_display_info *dpyinfo = check_ns_display_info (terminal); @@ -2472,14 +2323,7 @@ each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_height, 0, 1, 0, - doc: /* Return the height in pixels of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the pixel height for all -physical monitors associated with TERMINAL. To get information for -each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { struct ns_display_info *dpyinfo = check_ns_display_info (terminal); @@ -2724,10 +2568,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, 0, 1, 0, - doc: /* Return the number of bitplanes of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { check_ns_display_info (terminal); @@ -2738,10 +2579,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, 0, 1, 0, - doc: /* Returns the number of color cells of the Nextstep display TERMINAL. -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { struct ns_display_info *dpyinfo = check_ns_display_info (terminal); @@ -2749,10 +2587,6 @@ If omitted or nil, that stands for the selected frame's display. */) return make_number (1 << min (dpyinfo->n_planes, 24)); } - -/* Unused dummy def needed for compatibility. */ -Lisp_Object tip_frame; - /* TODO: move to xdisp or similar */ static void compute_tip_xy (struct frame *f, @@ -2833,35 +2667,7 @@ compute_tip_xy (struct frame *f, DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, - doc: /* Show STRING in a \"tooltip\" window on frame FRAME. -A tooltip window is a small window displaying a string. - -This is an internal function; Lisp code should call `tooltip-show'. - -FRAME nil or omitted means use the selected frame. - -PARMS is an optional list of frame parameters which can be used to -change the tooltip's appearance. - -Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil -means use the default timeout of 5 seconds. - -If the list of frame parameters PARMS contains a `left' parameter, -display the tooltip at that x-position. If the list of frame parameters -PARMS contains no `left' but a `right' parameter, display the tooltip -right-adjusted at that x-position. Otherwise display it at the -x-position of the mouse, with offset DX added (default is 5 if DX isn't -specified). - -Likewise for the y-position: If a `top' frame parameter is specified, it -determines the position of the upper edge of the tooltip window. If a -`bottom' parameter but no `top' frame parameter is specified, it -determines the position of the lower edge of the tooltip window. -Otherwise display the tooltip window at the y-position of the mouse, -with offset DY added (default is -10). - -A tooltip's maximum size is specified by `x-max-tooltip-size'. -Text larger than the specified size is clipped. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { int root_x, root_y; @@ -2869,6 +2675,8 @@ Text larger than the specified size is clipped. */) struct frame *f; char *str; NSSize size; + NSColor *color; + Lisp_Object t; specbind (Qinhibit_redisplay, Qt); @@ -2896,6 +2704,14 @@ Text larger than the specified size is clipped. */) else Fx_hide_tip (); + t = x_get_arg (NULL, parms, Qbackground_color, NULL, NULL, RES_TYPE_STRING); + if (ns_lisp_to_color (t, &color) == 0) + [ns_tooltip setBackgroundColor: color]; + + t = x_get_arg (NULL, parms, Qforeground_color, NULL, NULL, RES_TYPE_STRING); + if (ns_lisp_to_color (t, &color) == 0) + [ns_tooltip setForegroundColor: color]; + [ns_tooltip setText: str]; size = [ns_tooltip frame].size; @@ -2912,8 +2728,7 @@ Text larger than the specified size is clipped. */) DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, - doc: /* Hide the current tooltip window, if there is any. -Value is t if tooltip was open, nil otherwise. */) + doc: /* SKIP: real doc in xfns.c. */) (void) { if (ns_tooltip == nil || ![ns_tooltip isActive]) @@ -3121,6 +2936,19 @@ position (0, 0) of the selected frame's terminal. */) (pt.y - screen.frame.origin.y))); } +DEFUN ("ns-show-character-palette", + Fns_show_character_palette, + Sns_show_character_palette, 0, 0, 0, + doc: /* Show the macOS character palette. */) + (void) +{ + struct frame *f = SELECTED_FRAME (); + EmacsView *view = FRAME_NS_VIEW (f); + [NSApp orderFrontCharacterPalette:view]; + + return Qnil; +} + /* ========================================================================== Class implementations @@ -3288,6 +3116,11 @@ be used as the image of the icon representing the frame. */); doc: /* Toolkit version for NS Windowing. */); Vns_version_string = ns_appkit_version_str (); + DEFVAR_BOOL ("ns-use-proxy-icon", ns_use_proxy_icon, + doc: /* When non-nil display a proxy icon in the titlebar. +Default is t. */); + ns_use_proxy_icon = true; + defsubr (&Sns_read_file_name); defsubr (&Sns_get_resource); defsubr (&Sns_set_resource); @@ -3312,6 +3145,7 @@ be used as the image of the icon representing the frame. */); defsubr (&Sns_frame_restack); defsubr (&Sns_set_mouse_absolute_pixel_position); defsubr (&Sns_mouse_absolute_pixel_position); + defsubr (&Sns_show_character_palette); defsubr (&Sx_display_mm_width); defsubr (&Sx_display_mm_height); defsubr (&Sx_display_screens); diff --git a/src/nsimage.m b/src/nsimage.m index 6bce61626ff..e9af58b8afa 100644 --- a/src/nsimage.m +++ b/src/nsimage.m @@ -76,8 +76,9 @@ ns_load_image (struct frame *f, struct image *img, { EmacsImage *eImg = nil; NSSize size; - Lisp_Object lisp_index; + Lisp_Object lisp_index, lisp_rotation; unsigned int index; + double rotation; NSTRACE ("ns_load_image"); @@ -86,6 +87,9 @@ ns_load_image (struct frame *f, struct image *img, lisp_index = Fplist_get (XCDR (img->spec), QCindex); index = INTEGERP (lisp_index) ? XFASTINT (lisp_index) : 0; + lisp_rotation = Fplist_get (XCDR (img->spec), QCrotation); + rotation = NUMBERP (lisp_rotation) ? XFLOATINT (lisp_rotation) : 0; + if (STRINGP (spec_file)) { eImg = [EmacsImage allocInitFromFile: spec_file]; @@ -113,6 +117,17 @@ ns_load_image (struct frame *f, struct image *img, return 0; } + img->lisp_data = [eImg getMetadata]; + + if (rotation != 0) + { + EmacsImage *temp = [eImg rotate:rotation]; + [eImg release]; + eImg = temp; + } + + [eImg setSizeFromSpec:XCDR (img->spec)]; + size = [eImg size]; img->width = size.width; img->height = size.height; @@ -120,7 +135,6 @@ ns_load_image (struct frame *f, struct image *img, /* 4) set img->pixmap = emacsimage */ img->pixmap = eImg; - img->lisp_data = [eImg getMetadata]; return 1; } @@ -510,4 +524,102 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) return YES; } +- (void)setSizeFromSpec: (Lisp_Object) spec +{ + NSSize size = [self size]; + Lisp_Object value; + double scale = 1, aspect = size.width / size.height; + double width = -1, height = -1, max_width = -1, max_height = -1; + + value = Fplist_get (spec, QCscale); + if (NUMBERP (value)) + scale = XFLOATINT (value) ; + + value = Fplist_get (spec, QCmax_width); + if (NUMBERP (value)) + max_width = XFLOATINT (value); + + value = Fplist_get (spec, QCmax_height); + if (NUMBERP (value)) + max_height = XFLOATINT (value); + + value = Fplist_get (spec, QCwidth); + if (NUMBERP (value)) + { + width = XFLOATINT (value) * scale; + /* :width overrides :max-width. */ + max_width = -1; + } + + value = Fplist_get (spec, QCheight); + if (NUMBERP (value)) + { + height = XFLOATINT (value) * scale; + /* :height overrides :max-height. */ + max_height = -1; + } + + if (width <= 0 && height <= 0) + { + width = size.width * scale; + height = size.height * scale; + } + else if (width > 0 && height <= 0) + height = width / aspect; + else if (height > 0 && width <= 0) + width = height * aspect; + + if (max_width > 0 && width > max_width) + { + width = max_width; + height = max_width / aspect; + } + + if (max_height > 0 && height > max_height) + { + height = max_height; + width = max_height * aspect; + } + + [self setSize:NSMakeSize(width, height)]; +} + +- (instancetype)rotate: (double)rotation +{ + EmacsImage *new_image; + NSPoint new_origin; + NSSize new_size, size = [self size]; + NSRect rect = { NSZeroPoint, [self size] }; + + /* Create a bezier path of the outline of the image and do the + * rotation on it. */ + NSBezierPath *bounds_path = [NSBezierPath bezierPathWithRect:rect]; + NSAffineTransform *transform = [NSAffineTransform transform]; + [transform rotateByDegrees: rotation * -1]; + [bounds_path transformUsingAffineTransform:transform]; + + /* Now we can find out how large the rotated image needs to be. */ + new_size = [bounds_path bounds].size; + new_image = [[EmacsImage alloc] initWithSize:new_size]; + + new_origin = NSMakePoint((new_size.width - size.width)/2, + (new_size.height - size.height)/2); + + [new_image lockFocus]; + + /* Create the final transform. */ + transform = [NSAffineTransform transform]; + [transform translateXBy:new_size.width/2 yBy:new_size.height/2]; + [transform rotateByDegrees: rotation * -1]; + [transform translateXBy:-new_size.width/2 yBy:-new_size.height/2]; + + [transform concat]; + [self drawAtPoint:new_origin fromRect:NSZeroRect + operation:NSCompositingOperationCopy fraction:1]; + + [new_image unlockFocus]; + + return new_image; +} + @end diff --git a/src/nsmenu.m b/src/nsmenu.m index 604adcf40b5..29b0f99e642 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -1373,6 +1373,16 @@ update_frame_tool_bar (struct frame *f) [textField setFrame: r]; } +- (void) setBackgroundColor: (NSColor *)col +{ + [textField setBackgroundColor: col]; +} + +- (void) setForegroundColor: (NSColor *)col +{ + [textField setTextColor: col]; +} + - (void) showAtX: (int)x Y: (int)y for: (int)seconds { NSRect wr = [win frame]; @@ -1864,7 +1874,7 @@ DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0, DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, - doc: /* Return t if a menu or popup dialog is active. */) + doc: /* SKIP: real doc in xmenu.c. */) (void) { return popup_activated () ? Qt : Qnil; diff --git a/src/nsselect.m b/src/nsselect.m index bee628b7576..d8b4e2c7af8 100644 --- a/src/nsselect.m +++ b/src/nsselect.m @@ -36,7 +36,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) static Lisp_Object Vselection_alist; -/* NSGeneralPboard is pretty much analogous to X11 CLIPBOARD */ +/* NSPasteboardNameGeneral is pretty much analogous to X11 CLIPBOARD */ static NSString *NXPrimaryPboard; static NSString *NXSecondaryPboard; @@ -54,7 +54,7 @@ static NSString * symbol_to_nsstring (Lisp_Object sym) { CHECK_SYMBOL (sym); - if (EQ (sym, QCLIPBOARD)) return NSGeneralPboard; + if (EQ (sym, QCLIPBOARD)) return NSPasteboardNameGeneral; if (EQ (sym, QPRIMARY)) return NXPrimaryPboard; if (EQ (sym, QSECONDARY)) return NXSecondaryPboard; if (EQ (sym, QTEXT)) return NSStringPboardType; @@ -70,7 +70,7 @@ ns_symbol_to_pb (Lisp_Object symbol) static Lisp_Object ns_string_to_symbol (NSString *t) { - if ([t isEqualToString: NSGeneralPboard]) + if ([t isEqualToString: NSPasteboardNameGeneral]) return QCLIPBOARD; if ([t isEqualToString: NXPrimaryPboard]) return QPRIMARY; @@ -469,7 +469,7 @@ nxatoms_of_nsselect (void) pasteboard_changecount = [[NSMutableDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithLong:0], NSGeneralPboard, + [NSNumber numberWithLong:0], NSPasteboardNameGeneral, [NSNumber numberWithLong:0], NXPrimaryPboard, [NSNumber numberWithLong:0], NXSecondaryPboard, [NSNumber numberWithLong:0], NSStringPboardType, diff --git a/src/nsterm.h b/src/nsterm.h index 588b9fc6443..8b985930ecb 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -585,6 +585,8 @@ typedef id instancetype; } - (instancetype) init; - (void) setText: (char *)text; +- (void) setBackgroundColor: (NSColor *)col; +- (void) setForegroundColor: (NSColor *)col; - (void) showAtX: (int)x Y: (int)y for: (int)seconds; - (void) hide; - (BOOL) isActive; @@ -646,6 +648,8 @@ typedef id instancetype; - (NSColor *)stippleMask; - (Lisp_Object)getMetadata; - (BOOL)setFrame: (unsigned int) index; +- (void)setSizeFromSpec: (Lisp_Object) spec; +- (instancetype)rotate: (double)rotation; @end @@ -1233,7 +1237,7 @@ extern void ns_finish_events (void); #ifdef __OBJC__ /* Needed in nsfns.m. */ extern void -ns_set_represented_filename (NSString *fstr, struct frame *f); +ns_set_represented_filename (struct frame *f); #endif @@ -1306,6 +1310,7 @@ extern char gnustep_base_version[]; /* version tracking */ #define NSWindowStyleMaskUtilityWindow NSUtilityWindowMask #define NSAlertStyleCritical NSCriticalAlertStyle #define NSControlSizeRegular NSRegularControlSize +#define NSCompositingOperationCopy NSCompositeCopy /* And adds NSWindowStyleMask. */ #ifdef __OBJC__ @@ -1319,5 +1324,10 @@ enum NSWindowTabbingMode NSWindowTabbingModePreferred, NSWindowTabbingModeDisallowed }; +#endif /* !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_12) */ + +#if !defined (NS_IMPL_COCOA) || !defined (MAC_OS_X_VERSION_10_13) +/* Deprecated in macOS 10.13. */ +#define NSPasteboardNameGeneral NSGeneralPboard #endif #endif /* HAVE_NS */ diff --git a/src/nsterm.m b/src/nsterm.m index 3d58cd5ec64..75e0b837c67 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -37,6 +37,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) #include <time.h> #include <signal.h> #include <unistd.h> +#include <stdbool.h> #include <c-ctype.h> #include <c-strcase.h> @@ -66,6 +67,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) #ifdef NS_IMPL_COCOA #include "macfont.h" +#include <Carbon/Carbon.h> #endif static EmacsMenu *dockMenu; @@ -351,31 +353,56 @@ static CGPoint menu_mouse_point; #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand) #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption) #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption) -#define EV_MODIFIERS2(flags) \ - (((flags & NSEventModifierFlagHelp) ? \ - hyper_modifier : 0) \ - | (!EQ (ns_right_alternate_modifier, Qleft) && \ - ((flags & NSRightAlternateKeyMask) \ - == NSRightAlternateKeyMask) ? \ - parse_solitary_modifier (ns_right_alternate_modifier) : 0) \ - | ((flags & NSEventModifierFlagOption) ? \ - parse_solitary_modifier (ns_alternate_modifier) : 0) \ - | ((flags & NSEventModifierFlagShift) ? \ - shift_modifier : 0) \ - | (!EQ (ns_right_control_modifier, Qleft) && \ - ((flags & NSRightControlKeyMask) \ - == NSRightControlKeyMask) ? \ - parse_solitary_modifier (ns_right_control_modifier) : 0) \ - | ((flags & NSEventModifierFlagControl) ? \ - parse_solitary_modifier (ns_control_modifier) : 0) \ - | ((flags & NS_FUNCTION_KEY_MASK) ? \ - parse_solitary_modifier (ns_function_modifier) : 0) \ - | (!EQ (ns_right_command_modifier, Qleft) && \ - ((flags & NSRightCommandKeyMask) \ - == NSRightCommandKeyMask) ? \ - parse_solitary_modifier (ns_right_command_modifier) : 0) \ - | ((flags & NSEventModifierFlagCommand) ? \ - parse_solitary_modifier (ns_command_modifier):0)) + +static unsigned int +ev_modifiers_helper (unsigned int flags, unsigned int left_mask, + unsigned int right_mask, unsigned int either_mask, + Lisp_Object left_modifier, Lisp_Object right_modifier) +{ + unsigned int modifiers = 0; + + if (flags & either_mask) + { + BOOL left_key = (flags & left_mask) == left_mask; + BOOL right_key = (flags & right_mask) == right_mask + && ! EQ (right_modifier, Qleft); + + if (right_key) + modifiers |= parse_solitary_modifier (right_modifier); + + /* GNUstep (and possibly macOS in certain circumstances) doesn't + differentiate between the left and right keys, so if we can't + identify which key it is, we use the left key setting. */ + if (left_key || ! right_key) + modifiers |= parse_solitary_modifier (left_modifier); + } + + return modifiers; +} + +#define EV_MODIFIERS2(flags) \ + (((flags & NSEventModifierFlagHelp) ? \ + hyper_modifier : 0) \ + | ((flags & NSEventModifierFlagShift) ? \ + shift_modifier : 0) \ + | ((flags & NS_FUNCTION_KEY_MASK) ? \ + parse_solitary_modifier (ns_function_modifier) : 0) \ + | ev_modifiers_helper (flags, NSLeftControlKeyMask, \ + NSRightControlKeyMask, \ + NSEventModifierFlagControl, \ + ns_control_modifier, \ + ns_right_control_modifier) \ + | ev_modifiers_helper (flags, NSLeftCommandKeyMask, \ + NSRightCommandKeyMask, \ + NSEventModifierFlagCommand, \ + ns_command_modifier, \ + ns_right_command_modifier) \ + | ev_modifiers_helper (flags, NSLeftAlternateKeyMask, \ + NSRightAlternateKeyMask, \ + NSEventModifierFlagOption, \ + ns_alternate_modifier, \ + ns_right_alternate_modifier)) + #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags]) #define EV_UDMODIFIERS(e) \ @@ -443,10 +470,37 @@ static void ns_judge_scroll_bars (struct frame *f); ========================================================================== */ void -ns_set_represented_filename (NSString *fstr, struct frame *f) +ns_set_represented_filename (struct frame *f) { + Lisp_Object filename, encoded_filename; + Lisp_Object buf = XWINDOW (f->selected_window)->contents; + NSAutoreleasePool *pool; + NSString *fstr; + + NSTRACE ("ns_set_represented_filename"); + + if (f->explicit_name || ! NILP (f->title)) + return; + + block_input (); + pool = [[NSAutoreleasePool alloc] init]; + filename = BVAR (XBUFFER (buf), filename); + + if (! NILP (filename)) + { + encoded_filename = ENCODE_UTF_8 (filename); + + fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)]; + if (fstr == nil) fstr = @""; + } + else + fstr = @""; + represented_filename = [fstr retain]; represented_frame = f; + + [pool release]; + unblock_input (); } void @@ -1735,7 +1789,6 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_grav) -------------------------------------------------------------------------- */ { NSView *view = FRAME_NS_VIEW (f); - NSArray *screens = [NSScreen screens]; NSScreen *screen = [[view window] screen]; NSTRACE ("x_set_offset"); @@ -2627,7 +2680,78 @@ x_get_keysym_name (int keysym) return value; } +#ifdef NS_IMPL_COCOA +static UniChar +ns_get_shifted_character (NSEvent *event) +/* Look up the character corresponding to the key pressed on the + current keyboard layout and the currently configured shift-like + modifiers. This ignores the control-like modifiers that cause + [event characters] to give us the wrong result. + + Although UCKeyTranslate doesn't require the Carbon framework, some + of the surrounding paraphernalia does, so this function makes + Carbon a requirement. */ +{ + static UInt32 dead_key_state; + + /* UCKeyTranslate may return up to 255 characters. If the buffer + isn't large enough then it produces an error. What kind of + keyboard inputs 255 characters in a single keypress? */ + UniChar buf[255]; + UniCharCount max_string_length = 255; + UniCharCount actual_string_length = 0; + OSStatus result; + + CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty + (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData); + UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref); + + UInt32 flags = [event modifierFlags]; + UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0; + + NSTRACE ("ns_get_shifted_character"); + + if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask + && (EQ (ns_right_alternate_modifier, Qnone) + || (EQ (ns_right_alternate_modifier, Qleft) + && EQ (ns_alternate_modifier, Qnone)))) + modifiers |= rightOptionKey; + + if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask + && EQ (ns_alternate_modifier, Qnone)) + modifiers |= optionKey; + + if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask + && (EQ (ns_right_command_modifier, Qnone) + || (EQ (ns_right_command_modifier, Qleft) + && EQ (ns_command_modifier, Qnone)))) + /* Carbon doesn't differentiate between left and right command + keys. */ + modifiers |= cmdKey; + + if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask + && EQ (ns_command_modifier, Qnone)) + modifiers |= cmdKey; + + result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown, + (modifiers >> 8) & 0xFF, LMGetKbdType (), + kUCKeyTranslateNoDeadKeysBit, &dead_key_state, + max_string_length, &actual_string_length, buf); + + if (result != 0) + { + NSLog(@"Failed to translate character '%@' with modifiers %x", + [event characters], modifiers); + return 0; + } + + /* FIXME: What do we do if more than one code unit is returned? */ + if (actual_string_length > 0) + return buf[0]; + return 0; +} +#endif /* NS_IMPL_COCOA */ /* ========================================================================== @@ -3363,23 +3487,38 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, { struct font *font = font_for_underline_metrics (s); unsigned long descent = s->y + s->height - s->ybase; + unsigned long minimum_offset; + BOOL underline_at_descent_line, use_underline_position_properties; + Lisp_Object val = buffer_local_value (Qunderline_minimum_offset, + s->w->contents); + if (INTEGERP (val)) + minimum_offset = XFASTINT (val); + else + minimum_offset = 1; + val = buffer_local_value (Qx_underline_at_descent_line, + s->w->contents); + underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound)); + val = buffer_local_value (Qx_use_underline_position_properties, + s->w->contents); + use_underline_position_properties = + !(NILP (val) || EQ (val, Qunbound)); /* Use underline thickness of font, defaulting to 1. */ thickness = (font && font->underline_thickness > 0) ? font->underline_thickness : 1; /* Determine the offset of underlining from the baseline. */ - if (x_underline_at_descent_line) + if (underline_at_descent_line) position = descent - thickness; - else if (x_use_underline_position_properties + else if (use_underline_position_properties && font && font->underline_position >= 0) position = font->underline_position; else if (font) position = lround (font->descent / 2); else - position = underline_minimum_offset; + position = minimum_offset; - position = max (position, underline_minimum_offset); + position = max (position, minimum_offset); /* Ensure underlining is not cropped. */ if (descent <= position) @@ -5945,7 +6084,6 @@ not_in_argv (NSString *arg) @end /* EmacsApp */ - /* ========================================================================== EmacsView implementation @@ -6030,7 +6168,13 @@ not_in_argv (NSString *arg) if (!NSIsEmptyRect (visible)) [self addCursorRect: visible cursor: currentCursor]; - [currentCursor setOnMouseEntered: YES]; + +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if ([currentCursor respondsToSelector: @selector(setOnMouseEntered)]) +#endif + [currentCursor setOnMouseEntered: YES]; +#endif } @@ -6045,7 +6189,6 @@ not_in_argv (NSString *arg) int code; unsigned fnKeysym = 0; static NSMutableArray *nsEvArray; - int left_is_none; unsigned int flags = [theEvent modifierFlags]; NSTRACE ("[EmacsView keyDown:]"); @@ -6087,15 +6230,11 @@ not_in_argv (NSString *arg) if (!processingCompose) { - /* When using screen sharing, no left or right information is sent, - so use Left key in those cases. */ - int is_left_key, is_right_key; - + /* FIXME: What should happen for key sequences with more than + one character? */ code = ([[theEvent charactersIgnoringModifiers] length] == 0) ? 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0]; - /* (Carbon way: [theEvent keyCode]) */ - /* is it a "function key"? */ /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad flag set (this is probably a bug in the OS). @@ -6128,142 +6267,65 @@ not_in_argv (NSString *arg) code = fnKeysym; } - /* are there modifiers? */ - emacs_event->modifiers = 0; - - if (flags & NSEventModifierFlagHelp) - emacs_event->modifiers |= hyper_modifier; - - if (flags & NSEventModifierFlagShift) - emacs_event->modifiers |= shift_modifier; - - is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask; - is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask - || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand); - - if (is_right_key) - emacs_event->modifiers |= parse_solitary_modifier - (EQ (ns_right_command_modifier, Qleft) - ? ns_command_modifier - : ns_right_command_modifier); - - if (is_left_key) - { - emacs_event->modifiers |= parse_solitary_modifier - (ns_command_modifier); - - /* if super (default), take input manager's word so things like - dvorak / qwerty layout work */ - if (EQ (ns_command_modifier, Qsuper) - && !fnKeysym - && [[theEvent characters] length] != 0) - { - /* XXX: the code we get will be unshifted, so if we have - a shift modifier, must convert ourselves */ - if (!(flags & NSEventModifierFlagShift)) - code = [[theEvent characters] characterAtIndex: 0]; -#if 0 - /* this is ugly and also requires linking w/Carbon framework - (for LMGetKbdType) so for now leave this rare (?) case - undealt with.. in future look into CGEvent methods */ - else - { - long smv = GetScriptManagerVariable (smKeyScript); - Handle uchrHandle = GetResource - ('uchr', GetScriptVariable (smv, smScriptKeys)); - UInt32 dummy = 0; - UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle, - [[theEvent characters] characterAtIndex: 0], - kUCKeyActionDisplay, - (flags & ~NSEventModifierFlagCommand) >> 8, - LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask, - &dummy, 1, &dummy, &code); - code &= 0xFF; - } -#endif - } - } - - is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask; - is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask - || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl); - - if (is_right_key) - emacs_event->modifiers |= parse_solitary_modifier - (EQ (ns_right_control_modifier, Qleft) - ? ns_control_modifier - : ns_right_control_modifier); - - if (is_left_key) - emacs_event->modifiers |= parse_solitary_modifier - (ns_control_modifier); - - if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym) - emacs_event->modifiers |= - parse_solitary_modifier (ns_function_modifier); - - left_is_none = NILP (ns_alternate_modifier) - || EQ (ns_alternate_modifier, Qnone); - - is_right_key = (flags & NSRightAlternateKeyMask) - == NSRightAlternateKeyMask; - is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask - || (! is_right_key - && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption); - - if (is_right_key) - { - if ((NILP (ns_right_alternate_modifier) - || EQ (ns_right_alternate_modifier, Qnone) - || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none)) - && !fnKeysym) - { /* accept pre-interp alt comb */ - if ([[theEvent characters] length] > 0) - code = [[theEvent characters] characterAtIndex: 0]; - /*HACK: clear lone shift modifier to stop next if from firing */ - if (emacs_event->modifiers == shift_modifier) - emacs_event->modifiers = 0; - } - else - emacs_event->modifiers |= parse_solitary_modifier - (EQ (ns_right_alternate_modifier, Qleft) - ? ns_alternate_modifier - : ns_right_alternate_modifier); - } - - if (is_left_key) /* default = meta */ - { - if (left_is_none && !fnKeysym) - { /* accept pre-interp alt comb */ - if ([[theEvent characters] length] > 0) - code = [[theEvent characters] characterAtIndex: 0]; - /*HACK: clear lone shift modifier to stop next if from firing */ - if (emacs_event->modifiers == shift_modifier) - emacs_event->modifiers = 0; - } - else - emacs_event->modifiers |= - parse_solitary_modifier (ns_alternate_modifier); - } - - if (NS_KEYLOG) - fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", - (unsigned) code, fnKeysym, flags, emacs_event->modifiers); - - /* if it was a function key or had modifiers, pass it directly to emacs */ + /* The ⌘ and ⌥ modifiers can be either shift-like (for alternate + character input) or control-like (as command prefix). If we + have only shift-like modifiers, then we should use the + translated characters (returned by the characters method); if + we have only control-like modifiers, then we should use the + untranslated characters (returned by the + charactersIgnoringModifiers method). An annoyance happens if + we have both shift-like and control-like modifiers because + the NSEvent API doesn’t let us ignore only some modifiers. + In that case we use UCKeyTranslate (ns_get_shifted_character) + to look up the correct character. */ + + /* EV_MODIFIERS2 uses parse_solitary_modifier on all known + modifier keys, which returns 0 for shift-like modifiers. + Therefore its return value is the set of control-like + modifiers. */ + emacs_event->modifiers = EV_MODIFIERS2 (flags); + + /* Function keys (such as the F-keys, arrow keys, etc.) set + modifiers as though the fn key has been pressed when it + hasn't. Also some combinations of fn and a function key + return a different key than was pressed (e.g. fn-<left> gives + <home>). We need to unset the fn modifier in these cases. + FIXME: Can we avoid setting it in the first place. */ + if (fnKeysym && (flags & NS_FUNCTION_KEY_MASK)) + emacs_event->modifiers ^= parse_solitary_modifier (ns_function_modifier); + + if (NS_KEYLOG) + fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", + code, fnKeysym, flags, emacs_event->modifiers); + + /* If it was a function key or had control-like modifiers, pass + it directly to Emacs. */ if (fnKeysym || (emacs_event->modifiers && (emacs_event->modifiers != shift_modifier) && [[theEvent charactersIgnoringModifiers] length] > 0)) -/*[[theEvent characters] length] */ { emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; + /* FIXME: What are the next four lines supposed to do? */ if (code < 0x20) code |= (1<<28)|(3<<16); else if (code == 0x7f) code |= (1<<28)|(3<<16); else if (!fnKeysym) - emacs_event->kind = code > 0xFF - ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; + { +#ifdef NS_IMPL_COCOA + /* We potentially have both shift- and control-like + modifiers in use, so find the correct character + ignoring any control-like ones. */ + code = ns_get_shifted_character (theEvent); +#endif + + /* FIXME: This seems wrong, characters in the range + [0x80, 0xFF] are not ASCII characters. Can’t we just + use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds + of characters? */ + emacs_event->kind = code > 0xFF + ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; + } emacs_event->code = code; EV_TRAILER (theEvent); @@ -6272,11 +6334,32 @@ not_in_argv (NSString *arg) } } + /* If we get here, a non-function key without control-like modifiers + was hit. Use interpretKeyEvents, which in turn will call + insertText; see + https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html. */ if (NS_KEYLOG && !processingCompose) fprintf (stderr, "keyDown: Begin compose sequence.\n"); + /* FIXME: interpretKeyEvents doesn’t seem to send insertText if ⌘ is + used as shift-like modifier, at least on El Capitan. Mask it + out. This shouldn’t be needed though; we should figure out what + the correct way of handling ⌘ is. */ + if ([theEvent modifierFlags] & NSEventModifierFlagCommand) + theEvent = [NSEvent keyEventWithType:[theEvent type] + location:[theEvent locationInWindow] + modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand + timestamp:[theEvent timestamp] + windowNumber:[theEvent windowNumber] + context:nil + characters:[theEvent characters] + charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers] + isARepeat:[theEvent isARepeat] + keyCode:[theEvent keyCode]]; + processingCompose = YES; + /* FIXME: Use [NSArray arrayWithObject:theEvent]? */ [nsEvArray addObject: theEvent]; [self interpretKeyEvents: nsEvArray]; [nsEvArray removeObject: theEvent]; @@ -6291,14 +6374,20 @@ not_in_argv (NSString *arg) by doCommandBySelector: deleteBackward: */ - (void)insertText: (id)aString { - int code; - int len = [(NSString *)aString length]; - int i; + NSString *s; + NSUInteger len; NSTRACE ("[EmacsView insertText:]"); + if ([aString isKindOfClass:[NSAttributedString class]]) + s = [aString string]; + else + s = aString; + + len = [s length]; + if (NS_KEYLOG) - NSLog (@"insertText '%@'\tlen = %d", aString, len); + NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len); processingCompose = NO; if (!emacs_event) @@ -6308,10 +6397,24 @@ not_in_argv (NSString *arg) if (workingText != nil) [self deleteWorkingText]; + /* It might be preferable to use getCharacters:range: below, + cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378. + However, we probably can't use SAFE_NALLOCA here because it might + exit nonlocally. */ + /* now insert the string as keystrokes */ - for (i =0; i<len; i++) + for (NSUInteger i = 0; i < len; i++) { - code = [aString characterAtIndex: i]; + NSUInteger code = [s characterAtIndex:i]; + if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1) + { + unichar low = [s characterAtIndex:i + 1]; + if (UTF_16_LOW_SURROGATE_P (low)) + { + code = surrogates_to_codepoint (low, code); + ++i; + } + } /* TODO: still need this? */ if (code == 0x2DC) code = '~'; /* 0x7E */ @@ -8760,7 +8863,14 @@ not_in_argv (NSString *arg) if (!NSIsEmptyRect (visible)) [self addCursorRect: visible cursor: [NSCursor arrowCursor]]; - [[NSCursor arrowCursor] setOnMouseEntered: YES]; + +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if ([[NSCursor arrowCursor] respondsToSelector: + @selector(setOnMouseEntered)]) +#endif + [[NSCursor arrowCursor] setOnMouseEntered: YES]; +#endif } @@ -9363,30 +9473,21 @@ This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); /* TODO: move to common code */ DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, - doc: /* Which toolkit scroll bars Emacs uses, if any. -A value of nil means Emacs doesn't use toolkit scroll bars. -With the X Window system, the value is a symbol describing the -X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. -With MS Windows or Nextstep, the value is t. */); + doc: /* SKIP: real doc in xterm.c. */); Vx_toolkit_scroll_bars = Qt; DEFVAR_BOOL ("x-use-underline-position-properties", x_use_underline_position_properties, - doc: /*Non-nil means make use of UNDERLINE_POSITION font properties. -A value of nil means ignore them. If you encounter fonts with bogus -UNDERLINE_POSITION font properties, for example 7x13 on XFree prior -to 4.1, set this to nil. */); + doc: /* SKIP: real doc in xterm.c. */); x_use_underline_position_properties = 0; + DEFSYM (Qx_use_underline_position_properties, + "x-use-underline-position-properties"); DEFVAR_BOOL ("x-underline-at-descent-line", x_underline_at_descent_line, - doc: /* Non-nil means to draw the underline at the same place as the descent line. -(If `line-spacing' is in effect, that moves the underline lower by -that many pixels.) -A value of nil means to draw the underline according to the value of the -variable `x-use-underline-position-properties', which is usually at the -baseline level. The default value is nil. */); + doc: /* SKIP: real doc in xterm.c. */); x_underline_at_descent_line = 0; + DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); /* Tell Emacs about this window system. */ Fprovide (Qns, Qnil); diff --git a/src/print.c b/src/print.c index af1e85f6e7b..a8bbb9d37a1 100644 --- a/src/print.c +++ b/src/print.c @@ -313,6 +313,25 @@ printchar (unsigned int ch, Lisp_Object fun) } } +/* Output an octal escape for C. If C is less than '\100' consult the + following character (if any) to see whether to use three octal + digits to avoid misinterpretation of the next character. The next + character after C will be taken from DATA, starting at byte + location I, if I is less than SIZE. Use PRINTCHARFUN to output + each character. */ + +static void +octalout (unsigned char c, unsigned char *data, ptrdiff_t i, ptrdiff_t size, + Lisp_Object printcharfun) +{ + int digits = (c > '\77' || (i < size && '0' <= data[i] && data[i] <= '7') + ? 3 + : c > '\7' ? 2 : 1); + printchar ('\\', printcharfun); + do + printchar ('0' + ((c >> (3 * --digits)) & 7), printcharfun); + while (digits != 0); +} /* Output SIZE characters, SIZE_BYTE bytes from string PTR using method PRINTCHARFUN. PRINTCHARFUN nil means output to @@ -1367,32 +1386,33 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, case PVEC_BOOL_VECTOR: { EMACS_INT size = bool_vector_size (obj); - ptrdiff_t size_in_chars = bool_vector_bytes (size); - ptrdiff_t real_size_in_chars = size_in_chars; + ptrdiff_t size_in_bytes = bool_vector_bytes (size); + ptrdiff_t real_size_in_bytes = size_in_bytes; + unsigned char *data = bool_vector_uchar_data (obj); int len = sprintf (buf, "#&%"pI"d\"", size); strout (buf, len, len, printcharfun); - /* Don't print more characters than the specified maximum. + /* Don't print more bytes than the specified maximum. Negative values of print-length are invalid. Treat them like a print-length of nil. */ if (NATNUMP (Vprint_length) - && XFASTINT (Vprint_length) < size_in_chars) - size_in_chars = XFASTINT (Vprint_length); + && XFASTINT (Vprint_length) < size_in_bytes) + size_in_bytes = XFASTINT (Vprint_length); - for (ptrdiff_t i = 0; i < size_in_chars; i++) + for (ptrdiff_t i = 0; i < size_in_bytes; i++) { maybe_quit (); - unsigned char c = bool_vector_uchar_data (obj)[i]; + unsigned char c = data[i]; if (c == '\n' && print_escape_newlines) print_c_string ("\\n", printcharfun); else if (c == '\f' && print_escape_newlines) print_c_string ("\\f", printcharfun); - else if (c > '\177') + else if (c > '\177' + || (print_escape_control_characters && c_iscntrl (c))) { /* Use octal escapes to avoid encoding issues. */ - int len = sprintf (buf, "\\%o", c); - strout (buf, len, len, printcharfun); + octalout (c, data, i + 1, size_in_bytes, printcharfun); } else { @@ -1402,7 +1422,7 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, } } - if (size_in_chars < real_size_in_chars) + if (size_in_bytes < real_size_in_bytes) print_c_string (" ...", printcharfun); printchar ('\"', printcharfun); } @@ -1854,9 +1874,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) (when requested) a non-ASCII character in a unibyte buffer, print single-byte non-ASCII string chars using octal escapes. */ - char outbuf[5]; - int len = sprintf (outbuf, "\\%03o", c + 0u); - strout (outbuf, len, len, printcharfun); + octalout (c, SDATA (obj), i_byte, size_byte, printcharfun); need_nonhex = false; } else if (multibyte @@ -1870,7 +1888,6 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) } else { - bool still_need_nonhex = false; /* If we just had a hex escape, and this character could be taken as part of it, output `\ ' to prevent that. */ @@ -1884,22 +1901,16 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) ? (c = 'n', true) : c == '\f' && print_escape_newlines ? (c = 'f', true) - : c == '\0' && print_escape_control_characters - ? (c = '0', still_need_nonhex = true) : c == '\"' || c == '\\') { printchar ('\\', printcharfun); printchar (c, printcharfun); } else if (print_escape_control_characters && c_iscntrl (c)) - { - char outbuf[1 + 3 + 1]; - int len = sprintf (outbuf, "\\%03o", c + 0u); - strout (outbuf, len, len, printcharfun); - } + octalout (c, SDATA (obj), i_byte, size_byte, printcharfun); else printchar (c, printcharfun); - need_nonhex = still_need_nonhex; + need_nonhex = false; } } printchar ('\"', printcharfun); @@ -1971,7 +1982,8 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) || c == ';' || c == '#' || c == '(' || c == ')' || c == ',' || c == '.' || c == '`' || c == '[' || c == ']' || c == '?' || c <= 040 - || confusing) + || confusing + || (i == 1 && confusable_symbol_character_p (c))) { printchar ('\\', printcharfun); confusing = false; @@ -2366,7 +2378,7 @@ This affects only `prin1'. */); DEFVAR_BOOL ("print-quoted", print_quoted, doc: /* Non-nil means print quoted forms with reader syntax. I.e., (quote foo) prints as \\='foo, (function foo) as #\\='foo. */); - print_quoted = 0; + print_quoted = true; DEFVAR_LISP ("print-gensym", Vprint_gensym, doc: /* Non-nil means print uninterned symbols so they will read as uninterned. diff --git a/src/process.c b/src/process.c index bccc3ac3992..6ba27a33f4d 100644 --- a/src/process.c +++ b/src/process.c @@ -160,6 +160,18 @@ static bool kbd_is_on_hold; when exiting. */ bool inhibit_sentinels; +union u_sockaddr +{ + struct sockaddr sa; + struct sockaddr_in in; +#ifdef AF_INET6 + struct sockaddr_in6 in6; +#endif +#ifdef HAVE_LOCAL_SOCKETS + struct sockaddr_un un; +#endif +}; + #ifdef subprocesses #ifndef SOCK_CLOEXEC @@ -1248,10 +1260,7 @@ passed to the filter. The filter gets two arguments: the process and the string of output. The string argument is normally a multibyte string, except: - if the process's input coding system is no-conversion or raw-text, - it is a unibyte string (the non-converted input), or else -- if `default-enable-multibyte-characters' is nil, it is a unibyte - string (the result of converting the decoded input multibyte - string to unibyte with `string-make-unibyte'). */) + it is a unibyte string (the non-converted input). */) (Lisp_Object process, Lisp_Object filter) { CHECK_PROCESS (process); @@ -3759,8 +3768,7 @@ The stopped state is cleared by `continue-process' and set by :filter-multibyte BOOL -- If BOOL is non-nil, strings given to the process filter are multibyte, otherwise they are unibyte. -If this keyword is not specified, the strings are multibyte if -the default value of `enable-multibyte-characters' is non-nil. +If this keyword is not specified, the strings are multibyte. :sentinel SENTINEL -- Install SENTINEL as the process sentinel. @@ -3837,7 +3845,6 @@ usage: (make-network-process &rest ARGS) */) Lisp_Object contact; struct Lisp_Process *p; const char *portstring UNINIT; - ptrdiff_t portstringlen ATTRIBUTE_UNUSED; char portbuf[INT_BUFSIZE_BOUND (EMACS_INT)]; #ifdef HAVE_LOCAL_SOCKETS struct sockaddr_un address_un; @@ -3984,6 +3991,8 @@ usage: (make-network-process &rest ARGS) */) if (!NILP (host)) { + ptrdiff_t portstringlen ATTRIBUTE_UNUSED; + /* SERVICE can either be a string or int. Convert to a C string for later use by getaddrinfo. */ if (EQ (service, Qt)) @@ -4002,37 +4011,38 @@ usage: (make-network-process &rest ARGS) */) portstring = SSDATA (service); portstringlen = SBYTES (service); } - } #ifdef HAVE_GETADDRINFO_A - if (!NILP (host) && !NILP (Fplist_get (contact, QCnowait))) - { - ptrdiff_t hostlen = SBYTES (host); - struct req - { - struct gaicb gaicb; - struct addrinfo hints; - char str[FLEXIBLE_ARRAY_MEMBER]; - } *req = xmalloc (FLEXSIZEOF (struct req, str, - hostlen + 1 + portstringlen + 1)); - dns_request = &req->gaicb; - dns_request->ar_name = req->str; - dns_request->ar_service = req->str + hostlen + 1; - dns_request->ar_request = &req->hints; - dns_request->ar_result = NULL; - memset (&req->hints, 0, sizeof req->hints); - req->hints.ai_family = family; - req->hints.ai_socktype = socktype; - strcpy (req->str, SSDATA (host)); - strcpy (req->str + hostlen + 1, portstring); - - int ret = getaddrinfo_a (GAI_NOWAIT, &dns_request, 1, NULL); - if (ret) - error ("%s/%s getaddrinfo_a error %d", SSDATA (host), portstring, ret); - - goto open_socket; - } + if (!NILP (Fplist_get (contact, QCnowait))) + { + ptrdiff_t hostlen = SBYTES (host); + struct req + { + struct gaicb gaicb; + struct addrinfo hints; + char str[FLEXIBLE_ARRAY_MEMBER]; + } *req = xmalloc (FLEXSIZEOF (struct req, str, + hostlen + 1 + portstringlen + 1)); + dns_request = &req->gaicb; + dns_request->ar_name = req->str; + dns_request->ar_service = req->str + hostlen + 1; + dns_request->ar_request = &req->hints; + dns_request->ar_result = NULL; + memset (&req->hints, 0, sizeof req->hints); + req->hints.ai_family = family; + req->hints.ai_socktype = socktype; + strcpy (req->str, SSDATA (host)); + strcpy (req->str + hostlen + 1, portstring); + + int ret = getaddrinfo_a (GAI_NOWAIT, &dns_request, 1, NULL); + if (ret) + error ("%s/%s getaddrinfo_a error %d", + SSDATA (host), portstring, ret); + + goto open_socket; + } #endif /* HAVE_GETADDRINFO_A */ + } /* If we have a host, use getaddrinfo to resolve both host and service. Otherwise, use getservbyname to lookup the service. */ @@ -4675,16 +4685,7 @@ server_accept_connection (Lisp_Object server, int channel) struct Lisp_Process *ps = XPROCESS (server); struct Lisp_Process *p; int s; - union u_sockaddr { - struct sockaddr sa; - struct sockaddr_in in; -#ifdef AF_INET6 - struct sockaddr_in6 in6; -#endif -#ifdef HAVE_LOCAL_SOCKETS - struct sockaddr_un un; -#endif - } saddr; + union u_sockaddr saddr; socklen_t len = sizeof saddr; ptrdiff_t count; @@ -5005,6 +5006,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct timespec got_output_end_time = invalid_timespec (); enum { MINIMUM = -1, TIMEOUT, INFINITY } wait; int got_some_output = -1; + uintmax_t prev_wait_proc_nbytes_read = wait_proc ? wait_proc->nbytes_read : 0; #if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS bool retry_for_async; #endif @@ -5459,6 +5461,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, if (nfds == 0) { /* Exit the main loop if we've passed the requested timeout, + or have read some bytes from our wait_proc (either directly + in this call or indirectly through timers / process filters), or aren't skipping processes and got some output and haven't lowered our timeout due to timers or SIGIO and have waited a long amount of time due to repeated @@ -5466,7 +5470,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct timespec huge_timespec = make_timespec (TYPE_MAXIMUM (time_t), 2 * TIMESPEC_RESOLUTION); struct timespec cmp_time = huge_timespec; - if (wait < TIMEOUT) + if (wait < TIMEOUT + || (wait_proc + && wait_proc->nbytes_read != prev_wait_proc_nbytes_read)) break; if (wait == TIMEOUT) cmp_time = end_time; @@ -5627,16 +5633,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, } else if (nread == -1 && would_block (errno)) ; -#ifdef WINDOWSNT - /* FIXME: Is this special case still needed? */ - /* Note that we cannot distinguish between no input - available now and a closed pipe. - With luck, a closed pipe will be accompanied by - subprocess termination and SIGCHLD. */ - else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc) - && !PIPECONN_P (proc)) - ; -#endif #ifdef HAVE_PTYS /* On some OSs with ptys, when the process on one end of a pty exits, the other end gets an error reading with @@ -5781,6 +5777,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, maybe_quit (); } + /* Timers and/or process filters that we have run could have themselves called + `accept-process-output' (and by that indirectly this function), thus + possibly reading some (or all) output of wait_proc without us noticing it. + This could potentially lead to an endless wait (dealt with earlier in the + function) and/or a wrong return value (dealt with here). */ + if (wait_proc && wait_proc->nbytes_read != prev_wait_proc_nbytes_read) + got_some_output = min (INT_MAX, (wait_proc->nbytes_read + - prev_wait_proc_nbytes_read)); + return got_some_output; } @@ -5899,6 +5904,9 @@ read_process_output (Lisp_Object proc, int channel) coding->mode |= CODING_MODE_LAST_BLOCK; } + /* Ignore carryover, it's been added by a previous iteration already. */ + p->nbytes_read += nbytes; + /* Now set NBYTES how many bytes we must decode. */ nbytes += carryover; @@ -8022,6 +8030,18 @@ init_process_emacs (int sockfd) #endif external_sock_fd = sockfd; + Lisp_Object sockname = Qnil; +# if HAVE_GETSOCKNAME + if (0 <= sockfd) + { + union u_sockaddr sa; + socklen_t salen = sizeof sa; + if (getsockname (sockfd, &sa.sa, &salen) == 0) + sockname = conv_sockaddr_to_lisp (&sa.sa, salen); + } +# endif + Vinternal__daemon_sockname = sockname; + max_desc = -1; memset (fd_callback_info, 0, sizeof (fd_callback_info)); @@ -8214,6 +8234,10 @@ These functions are called in the order of the list, until one of them returns non-`nil'. */); Vinterrupt_process_functions = list1 (Qinternal_default_interrupt_process); + DEFVAR_LISP ("internal--daemon-sockname", Vinternal__daemon_sockname, + doc: /* Name of external socket passed to Emacs, or nil if none. */); + Vinternal__daemon_sockname = Qnil; + DEFSYM (Qinternal_default_interrupt_process, "internal-default-interrupt-process"); DEFSYM (Qinterrupt_process_functions, "interrupt-process-functions"); diff --git a/src/process.h b/src/process.h index ab468b18c56..6464a8cc61a 100644 --- a/src/process.h +++ b/src/process.h @@ -129,6 +129,8 @@ struct Lisp_Process pid_t pid; /* Descriptor by which we read from this process. */ int infd; + /* Byte-count modulo (UINTMAX_MAX + 1) for process output read from `infd'. */ + uintmax_t nbytes_read; /* Descriptor by which we write to this process. */ int outfd; /* Descriptors that were created for this process and that need diff --git a/src/ptr-bounds.h b/src/ptr-bounds.h new file mode 100644 index 00000000000..8cbd58d72b0 --- /dev/null +++ b/src/ptr-bounds.h @@ -0,0 +1,79 @@ +/* Pointer bounds checking for GNU Emacs + +Copyright 2017-2018 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ + +/* Pointer bounds checking is a no-op unless running on hardware + supporting Intel MPX (Intel Skylake or better). Also, it requires + GCC 5 and Linux kernel 3.19, or later. Configure with + CFLAGS='-fcheck-pointer-bounds -mmpx', perhaps with + -fchkp-first-field-has-own-bounds thrown in. + + Although pointer bounds checking can help during debugging, it is + disabled by default because it hurts performance significantly. + The checking does not detect all pointer errors. For example, a + dumped Emacs might not detect a bounds violation of a pointer that + was created before Emacs was dumped. */ + +#ifndef PTR_BOUNDS_H +#define PTR_BOUNDS_H + +#include <stddef.h> + +/* When not checking pointer bounds, the following macros simply + return their first argument. These macros return either void *, or + the same type as their first argument. */ + +INLINE_HEADER_BEGIN + +/* Return a copy of P, with bounds narrowed to [P, P + N). */ +#ifdef __CHKP__ +INLINE void * +ptr_bounds_clip (void const *p, size_t n) +{ + return __builtin___bnd_narrow_ptr_bounds (p, p, n); +} +#else +# define ptr_bounds_clip(p, n) ((void) (size_t) {n}, p) +#endif + +/* Return a copy of P, but with the bounds of Q. */ +#ifdef __CHKP__ +# define ptr_bounds_copy(p, q) __builtin___bnd_copy_ptr_bounds (p, q) +#else +# define ptr_bounds_copy(p, q) ((void) (void const *) {q}, p) +#endif + +/* Return a copy of P, but with infinite bounds. + This is a loophole in pointer bounds checking. */ +#ifdef __CHKP__ +# define ptr_bounds_init(p) __builtin___bnd_init_ptr_bounds (p) +#else +# define ptr_bounds_init(p) (p) +#endif + +/* Return a copy of P, but with bounds [P, P + N). + This is a loophole in pointer bounds checking. */ +#ifdef __CHKP__ +# define ptr_bounds_set(p, n) __builtin___bnd_set_ptr_bounds (p, n) +#else +# define ptr_bounds_set(p, n) ((void) (size_t) {n}, p) +#endif + +INLINE_HEADER_END + +#endif /* PTR_BOUNDS_H */ diff --git a/src/regex.c b/src/regex.c index e8b99f6f023..a4e6441cce3 100644 --- a/src/regex.c +++ b/src/regex.c @@ -519,13 +519,7 @@ ptrdiff_t emacs_re_safe_alloca = MAX_ALLOCA; #endif /* Type of source-pattern and string chars. */ -#ifdef _MSC_VER -typedef unsigned char re_char; -typedef const re_char const_re_char; -#else typedef const unsigned char re_char; -typedef re_char const_re_char; -#endif typedef char boolean; @@ -1200,7 +1194,8 @@ static const char *re_error_msgid[] = gettext_noop ("Premature end of regular expression"), /* REG_EEND */ gettext_noop ("Regular expression too big"), /* REG_ESIZE */ gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */ - gettext_noop ("Range striding over charsets") /* REG_ERANGEX */ + gettext_noop ("Range striding over charsets"), /* REG_ERANGEX */ + gettext_noop ("Invalid content of \\{\\}, repetitions too big") /* REG_ESIZEBR */ }; /* Whether to allocate memory during matching. */ @@ -1921,7 +1916,7 @@ struct range_table_work_area if (num < 0) \ num = 0; \ if (RE_DUP_MAX / 10 - (RE_DUP_MAX % 10 < c - '0') < num) \ - FREE_STACK_RETURN (REG_BADBR); \ + FREE_STACK_RETURN (REG_ESIZEBR); \ num = num * 10 + c - '0'; \ if (p == pend) \ FREE_STACK_RETURN (REG_EBRACE); \ @@ -2403,7 +2398,7 @@ do { \ } while (0) static reg_errcode_t -regex_compile (const_re_char *pattern, size_t size, +regex_compile (re_char *pattern, size_t size, #ifdef emacs # define syntax RE_SYNTAX_EMACS bool posix_backtracking, @@ -3728,7 +3723,7 @@ insert_op2 (re_opcode_t op, unsigned char *loc, int arg1, int arg2, unsigned cha least one character before the ^. */ static boolean -at_begline_loc_p (const_re_char *pattern, const_re_char *p, reg_syntax_t syntax) +at_begline_loc_p (re_char *pattern, re_char *p, reg_syntax_t syntax) { re_char *prev = p - 2; boolean odd_backslashes; @@ -3769,7 +3764,7 @@ at_begline_loc_p (const_re_char *pattern, const_re_char *p, reg_syntax_t syntax) at least one character after the $, i.e., `P < PEND'. */ static boolean -at_endline_loc_p (const_re_char *p, const_re_char *pend, reg_syntax_t syntax) +at_endline_loc_p (re_char *p, re_char *pend, reg_syntax_t syntax) { re_char *next = p; boolean next_backslash = *next == '\\'; @@ -3813,7 +3808,7 @@ group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum) Return -1 if fastmap was not updated accurately. */ static int -analyze_first (const_re_char *p, const_re_char *pend, char *fastmap, +analyze_first (re_char *p, re_char *pend, char *fastmap, const int multibyte) { int j, k; @@ -4555,7 +4550,7 @@ static int bcmp_translate (re_char *s1, re_char *s2, /* If the operation is a match against one or more chars, return a pointer to the next operation, else return NULL. */ static re_char * -skip_one_char (const_re_char *p) +skip_one_char (re_char *p) { switch (*p++) { @@ -4597,7 +4592,7 @@ skip_one_char (const_re_char *p) /* Jump over non-matching operations. */ static re_char * -skip_noops (const_re_char *p, const_re_char *pend) +skip_noops (re_char *p, re_char *pend) { int mcnt; while (p < pend) @@ -4628,7 +4623,7 @@ skip_noops (const_re_char *p, const_re_char *pend) character (i.e. without any translations). UNIBYTE denotes whether c is unibyte or multibyte character. */ static bool -execute_charset (const_re_char **pp, unsigned c, unsigned corig, bool unibyte) +execute_charset (re_char **pp, unsigned c, unsigned corig, bool unibyte) { re_char *p = *pp, *rtp = NULL; bool not = (re_opcode_t) *p == charset_not; @@ -4692,8 +4687,8 @@ execute_charset (const_re_char **pp, unsigned c, unsigned corig, bool unibyte) /* Non-zero if "p1 matches something" implies "p2 fails". */ static int -mutually_exclusive_p (struct re_pattern_buffer *bufp, const_re_char *p1, - const_re_char *p2) +mutually_exclusive_p (struct re_pattern_buffer *bufp, re_char *p1, + re_char *p2) { re_opcode_t op2; const boolean multibyte = RE_MULTIBYTE_P (bufp); @@ -4931,8 +4926,8 @@ WEAK_ALIAS (__re_match_2, re_match_2) /* This is a separate function so that we can force an alloca cleanup afterwards. */ static regoff_t -re_match_2_internal (struct re_pattern_buffer *bufp, const_re_char *string1, - size_t size1, const_re_char *string2, size_t size2, +re_match_2_internal (struct re_pattern_buffer *bufp, re_char *string1, + size_t size1, re_char *string2, size_t size2, ssize_t pos, struct re_registers *regs, ssize_t stop) { /* General temporaries. */ @@ -6222,10 +6217,10 @@ re_match_2_internal (struct re_pattern_buffer *bufp, const_re_char *string1, bytes; nonzero otherwise. */ static int -bcmp_translate (const_re_char *s1, const_re_char *s2, register ssize_t len, +bcmp_translate (re_char *s1, re_char *s2, ssize_t len, RE_TRANSLATE_TYPE translate, const int target_multibyte) { - register re_char *p1 = s1, *p2 = s2; + re_char *p1 = s1, *p2 = s2; re_char *p1_end = s1 + len; re_char *p2_end = s2 + len; diff --git a/src/regex.h b/src/regex.h index b4aad6daac9..6974951f575 100644 --- a/src/regex.h +++ b/src/regex.h @@ -270,8 +270,10 @@ extern ptrdiff_t emacs_re_safe_alloca; #ifdef RE_DUP_MAX # undef RE_DUP_MAX #endif -/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ -#define RE_DUP_MAX (0x7fff) +/* Repeat counts are stored in opcodes as 2 byte integers. This was + previously limited to 7fff because the parsing code uses signed + ints. But Emacs only runs on 32 bit platforms anyway. */ +#define RE_DUP_MAX (0xffff) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ @@ -337,7 +339,8 @@ typedef enum REG_EEND, /* Premature end. */ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN, /* Unmatched ) or \); not returned from regcomp. */ - REG_ERANGEX /* Range striding over charsets. */ + REG_ERANGEX, /* Range striding over charsets. */ + REG_ESIZEBR /* n or m too big in \{n,m\} */ } reg_errcode_t; /* This data structure represents a compiled pattern. Before calling diff --git a/src/sound.c b/src/sound.c index ce1a11e3863..b149acd7528 100644 --- a/src/sound.c +++ b/src/sound.c @@ -2,6 +2,8 @@ Copyright (C) 1998-1999, 2001-2018 Free Software Foundation, Inc. +Author: Gerd Moellmann <gerd@gnu.org> + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify @@ -17,8 +19,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ -/* Written by Gerd Moellmann <gerd@gnu.org>. Tested with Luigi's - driver on FreeBSD 2.2.7 with a SoundBlaster 16. */ +/* Tested with Luigi's driver on FreeBSD 2.2.7 with a SoundBlaster 16. */ /* Modified by Ben Key <Bkey1@tampabay.rr.com> to add a partial diff --git a/src/syntax.c b/src/syntax.c index 378064611cc..20c607420c1 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -605,6 +605,26 @@ find_defun_start (ptrdiff_t pos, ptrdiff_t pos_byte) && MODIFF == find_start_modiff) return find_start_value; + if (!NILP (Vcomment_use_syntax_ppss)) + { + EMACS_INT modiffs = CHARS_MODIFF; + Lisp_Object ppss = call1 (Qsyntax_ppss, make_number (pos)); + if (modiffs != CHARS_MODIFF) + error ("syntax-ppss modified the buffer!"); + TEMP_SET_PT_BOTH (opoint, opoint_byte); + Lisp_Object boc = Fnth (make_number (8), ppss); + if (NUMBERP (boc)) + { + find_start_value = XINT (boc); + find_start_value_byte = CHAR_TO_BYTE (find_start_value); + } + else + { + find_start_value = pos; + find_start_value_byte = pos_byte; + } + goto found; + } if (!open_paren_in_column_0_is_defun_start) { find_start_value = BEGV; @@ -874,6 +894,7 @@ back_comment (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t stop, case Sopen: /* Assume a defun-start point is outside of strings. */ if (open_paren_in_column_0_is_defun_start + && NILP (Vcomment_use_syntax_ppss) && (from == stop || (temp_byte = dec_bytepos (from_byte), FETCH_CHAR (temp_byte) == '\n'))) @@ -3694,6 +3715,11 @@ void syms_of_syntax (void) { DEFSYM (Qsyntax_table_p, "syntax-table-p"); + DEFSYM (Qsyntax_ppss, "syntax-ppss"); + DEFVAR_LISP ("comment-use-syntax-ppss", + Vcomment_use_syntax_ppss, + doc: /* Non-nil means `forward-comment' can use `syntax-ppss' internally. */); + Vcomment_use_syntax_ppss = Qt; staticpro (&Vsyntax_code_object); diff --git a/src/sysdep.c b/src/sysdep.c index 34bff23386d..1eaf648ea78 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1671,7 +1671,7 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler) } #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD -pthread_t main_thread_id; +static pthread_t main_thread_id; #endif /* SIG has arrived at the current process. Deliver it to the main @@ -2554,6 +2554,22 @@ emacs_close (int fd) #define MAX_RW_COUNT (INT_MAX >> 18 << 18) #endif +/* Verify that MAX_RW_COUNT fits in the relevant standard types. */ +#ifndef SSIZE_MAX +# define SSIZE_MAX TYPE_MAXIMUM (ssize_t) +#endif +verify (MAX_RW_COUNT <= PTRDIFF_MAX); +verify (MAX_RW_COUNT <= SIZE_MAX); +verify (MAX_RW_COUNT <= SSIZE_MAX); + +#ifdef WINDOWSNT +/* Verify that Emacs read requests cannot cause trouble, even in + 64-bit builds. The last argument of 'read' is 'unsigned int', and + the return value's type (see 'sys_read') is 'int'. */ +verify (MAX_RW_COUNT <= INT_MAX); +verify (MAX_RW_COUNT <= UINT_MAX); +#endif + /* Read from FD to a buffer BUF with size NBYTE. If interrupted, process any quits and pending signals immediately if INTERRUPTIBLE, and then retry the read unless quitting. @@ -2562,10 +2578,11 @@ emacs_close (int fd) static ptrdiff_t emacs_intr_read (int fd, void *buf, ptrdiff_t nbyte, bool interruptible) { + /* No caller should ever pass a too-large size to emacs_read. */ + eassert (nbyte <= MAX_RW_COUNT); + ssize_t result; - /* There is no need to check against MAX_RW_COUNT, since no caller ever - passes a size that large to emacs_read. */ do { if (interruptible) @@ -2989,7 +3006,11 @@ list_system_processes (void) for (tail = proclist; CONSP (tail); tail = next) { next = XCDR (tail); - XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); + Lisp_Object pidstring = XCAR (tail); + Lisp_Object pid = Fstring_to_number (pidstring, Qnil); + if (!INTEGERP (pid) || XINT (pid) <= 0) + xsignal1 (Qoverflow_error, pidstring); + XSETCAR (tail, pid); } /* directory_files_internal returns the files in reverse order; undo diff --git a/src/syssignal.h b/src/syssignal.h index 4f6da845ad1..0887eacb05d 100644 --- a/src/syssignal.h +++ b/src/syssignal.h @@ -32,7 +32,6 @@ extern void unblock_tty_out_signal (sigset_t const *); #ifdef HAVE_PTHREAD #include <pthread.h> -extern pthread_t main_thread_id; /* If defined, asynchronous signals delivered to a non-main thread are forwarded to the main thread. */ #define FORWARD_SIGNAL_TO_MAIN_THREAD diff --git a/src/systhread.c b/src/systhread.c index c4dcc4e9069..e972ed398ac 100644 --- a/src/systhread.c +++ b/src/systhread.c @@ -74,6 +74,12 @@ sys_thread_self (void) return 0; } +bool +sys_thread_equal (sys_thread_t t, sys_thread_t u) +{ + return t == u; +} + int sys_thread_create (sys_thread_t *t, const char *name, thread_creation_function *func, void *datum) @@ -155,6 +161,12 @@ sys_thread_self (void) return pthread_self (); } +bool +sys_thread_equal (sys_thread_t t, sys_thread_t u) +{ + return pthread_equal (t, u); +} + int sys_thread_create (sys_thread_t *thread_ptr, const char *name, thread_creation_function *func, void *arg) @@ -165,14 +177,12 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, if (pthread_attr_init (&attr)) return 0; -#ifdef DARWIN_OS /* Avoid crash on macOS with deeply nested GC (Bug#30364). */ size_t stack_size; size_t required_stack_size = sizeof (void *) * 1024 * 1024; if (pthread_attr_getstacksize (&attr, &stack_size) == 0 && stack_size < required_stack_size) pthread_attr_setstacksize (&attr, required_stack_size); -#endif if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) { @@ -332,6 +342,12 @@ sys_thread_self (void) return (sys_thread_t) GetCurrentThreadId (); } +bool +sys_thread_equal (sys_thread_t t, sys_thread_t u) +{ + return t == u; +} + static thread_creation_function *thread_start_address; /* _beginthread wants a void function, while we are passed a function diff --git a/src/systhread.h b/src/systhread.h index 4745d220654..5dbb12dffb6 100644 --- a/src/systhread.h +++ b/src/systhread.h @@ -100,6 +100,7 @@ extern void sys_cond_broadcast (sys_cond_t *); extern void sys_cond_destroy (sys_cond_t *); extern sys_thread_t sys_thread_self (void); +extern bool sys_thread_equal (sys_thread_t, sys_thread_t); extern int sys_thread_create (sys_thread_t *, const char *, thread_creation_function *, diff --git a/src/term.c b/src/term.c index b3707da70a2..8be5fb319b0 100644 --- a/src/term.c +++ b/src/term.c @@ -1591,13 +1591,13 @@ produce_glyphs (struct it *it) + it->continuation_lines_width); int x0 = absolute_x; /* Adjust for line numbers. */ - if (!NILP (Vdisplay_line_numbers)) + if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p) absolute_x -= it->lnum_pixel_width; int next_tab_x = (((1 + absolute_x + it->tab_width - 1) / it->tab_width) * it->tab_width); - if (!NILP (Vdisplay_line_numbers)) + if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p) next_tab_x += it->lnum_pixel_width; int nspaces; @@ -4144,10 +4144,10 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ tty->TN_max_colors = tgetnum ("Co"); #ifdef TERMINFO - /* Non-standard support for 24-bit colors. */ { const char *fg = tigetstr ("setf24"); const char *bg = tigetstr ("setb24"); + /* Non-standard support for 24-bit colors. */ if (fg && bg && fg != (char *) (intptr_t) -1 && bg != (char *) (intptr_t) -1) @@ -4156,6 +4156,14 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ tty->TS_set_background = bg; tty->TN_max_colors = 16777216; } + /* Standard support for 24-bit colors. */ + else if (tigetflag ("RGB") > 0) + { + /* If the used Terminfo library supports only 16-bit + signed values, tgetnum("Co") and tigetnum("colors") + could return 32767. */ + tty->TN_max_colors = 16777216; + } } #endif diff --git a/src/thread.c b/src/thread.c index 60902b252b4..f11e3e5addb 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1022,6 +1022,14 @@ main_thread_p (void *ptr) return ptr == &main_thread; } +bool +in_current_thread (void) +{ + if (current_thread == NULL) + return false; + return sys_thread_equal (sys_thread_self (), current_thread->thread_id); +} + void init_threads_once (void) { diff --git a/src/thread.h b/src/thread.h index 5746512b799..5ab5e90c70d 100644 --- a/src/thread.h +++ b/src/thread.h @@ -303,6 +303,7 @@ extern void init_threads_once (void); extern void init_threads (void); extern void syms_of_threads (void); extern bool main_thread_p (void *); +extern bool in_current_thread (void); typedef int select_func (int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *); diff --git a/src/tparam.h b/src/tparam.h index f8fb9e08690..3a3cb52c178 100644 --- a/src/tparam.h +++ b/src/tparam.h @@ -37,7 +37,8 @@ extern char *BC; extern char *UP; #ifdef TERMINFO -char *tigetstr(const char *); +int tigetflag (const char *); +char *tigetstr (const char *); #endif #endif /* EMACS_TPARAM_H */ diff --git a/src/w16select.c b/src/w16select.c index ed3d041f2df..5a80d1cba63 100644 --- a/src/w16select.c +++ b/src/w16select.c @@ -2,6 +2,8 @@ Copyright (C) 1996-1997, 2001-2018 Free Software Foundation, Inc. +Author: Dale P. Smith <dpsm@en.com> + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify @@ -22,7 +24,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ "old" (character-mode) application access to Dynamic Data Exchange, menus, and the Windows clipboard. */ -/* Written by Dale P. Smith <dpsm@en.com> */ /* Adapted to DJGPP by Eli Zaretskii <eliz@gnu.org> */ #ifdef MSDOS @@ -678,43 +679,11 @@ syms_of_win16select (void) defsubr (&Sw16_selection_exists_p); DEFVAR_LISP ("selection-coding-system", Vselection_coding_system, - doc: /* Coding system for communicating with other programs. - -For MS-Windows and MS-DOS: -When sending or receiving text via selection and clipboard, the text -is encoded or decoded by this coding system. The default value is -the current system default encoding on 9x/Me, `utf-16le-dos' -\(Unicode) on NT/W2K/XP, and `iso-latin-1-dos' on MS-DOS. - -For X Windows: -When sending text via selection and clipboard, if the target -data-type matches with the type of this coding system, it is used -for encoding the text. Otherwise (including the case that this -variable is nil), a proper coding system is used as below: - -data-type coding system ---------- ------------- -UTF8_STRING utf-8 -COMPOUND_TEXT compound-text-with-extensions -STRING iso-latin-1 -C_STRING no-conversion - -When receiving text, if this coding system is non-nil, it is used -for decoding regardless of the data-type. If this is nil, a -proper coding system is used according to the data-type as above. - -See also the documentation of the variable `x-select-request-type' how -to control which data-type to request for receiving text. - -The default value is nil. */); + doc: /* SKIP: real doc in select.el. */); Vselection_coding_system = intern ("iso-latin-1-dos"); DEFVAR_LISP ("next-selection-coding-system", Vnext_selection_coding_system, - doc: /* Coding system for the next communication with other programs. -Usually, `selection-coding-system' is used for communicating with -other programs (X Windows clients or MS Windows programs). But, if this -variable is set, it is used for the next communication only. -After the communication, this variable is set to nil. */); + doc: /* SKIP: real doc in select.el. */); Vnext_selection_coding_system = Qnil; DEFSYM (QCLIPBOARD, "CLIPBOARD"); diff --git a/src/w32cygwinx.c b/src/w32cygwinx.c new file mode 100644 index 00000000000..8d3ae164cf6 --- /dev/null +++ b/src/w32cygwinx.c @@ -0,0 +1,140 @@ +/* Common functions for the Microsoft Windows and Cygwin builds. + +Copyright (C) 2018 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <stdio.h> + +#include "lisp.h" +#include "w32common.h" + +DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0, + doc: /* Get power status information from Windows system. + +The following %-sequences are provided: +%L AC line status (verbose) +%B Battery status (verbose) +%b Battery status, empty means high, `-' means low, + `!' means critical, and `+' means charging +%p Battery load percentage +%s Remaining time (to charge or discharge) in seconds +%m Remaining time (to charge or discharge) in minutes +%h Remaining time (to charge or discharge) in hours +%t Remaining time (to charge or discharge) in the form `h:min' */) + (void) +{ + Lisp_Object status = Qnil; + + SYSTEM_POWER_STATUS system_status; + if (GetSystemPowerStatus (&system_status)) + { + Lisp_Object line_status, battery_status, battery_status_symbol; + Lisp_Object load_percentage, seconds, minutes, hours, remain; + + long seconds_left = (long) system_status.BatteryLifeTime; + + if (system_status.ACLineStatus == 0) + line_status = build_string ("off-line"); + else if (system_status.ACLineStatus == 1) + line_status = build_string ("on-line"); + else + line_status = build_string ("N/A"); + + if (system_status.BatteryFlag & 128) + { + battery_status = build_string ("N/A"); + battery_status_symbol = empty_unibyte_string; + } + else if (system_status.BatteryFlag & 8) + { + battery_status = build_string ("charging"); + battery_status_symbol = build_string ("+"); + if (system_status.BatteryFullLifeTime != -1L) + seconds_left = system_status.BatteryFullLifeTime - seconds_left; + } + else if (system_status.BatteryFlag & 4) + { + battery_status = build_string ("critical"); + battery_status_symbol = build_string ("!"); + } + else if (system_status.BatteryFlag & 2) + { + battery_status = build_string ("low"); + battery_status_symbol = build_string ("-"); + } + else if (system_status.BatteryFlag & 1) + { + battery_status = build_string ("high"); + battery_status_symbol = empty_unibyte_string; + } + else + { + battery_status = build_string ("medium"); + battery_status_symbol = empty_unibyte_string; + } + + if (system_status.BatteryLifePercent > 100) + load_percentage = build_string ("N/A"); + else + { + char buffer[16]; + snprintf (buffer, 16, "%d", system_status.BatteryLifePercent); + load_percentage = build_string (buffer); + } + + if (seconds_left < 0) + seconds = minutes = hours = remain = build_string ("N/A"); + else + { + long m; + double h; + char buffer[16]; + snprintf (buffer, 16, "%ld", seconds_left); + seconds = build_string (buffer); + + m = seconds_left / 60; + snprintf (buffer, 16, "%ld", m); + minutes = build_string (buffer); + + h = seconds_left / 3600.0; + snprintf (buffer, 16, "%3.1f", h); + hours = build_string (buffer); + + snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60); + remain = build_string (buffer); + } + + status = listn (CONSTYPE_HEAP, 8, + Fcons (make_number ('L'), line_status), + Fcons (make_number ('B'), battery_status), + Fcons (make_number ('b'), battery_status_symbol), + Fcons (make_number ('p'), load_percentage), + Fcons (make_number ('s'), seconds), + Fcons (make_number ('m'), minutes), + Fcons (make_number ('h'), hours), + Fcons (make_number ('t'), remain)); + } + return status; +} + +void +syms_of_w32cygwinx (void) +{ + defsubr (&Sw32_battery_status); +} diff --git a/src/w32fns.c b/src/w32fns.c index e50b7d5c3c3..2b920f29c65 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -5670,15 +5670,7 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms) DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1, 1, 0, - doc: /* Make a new window, which is called a \"frame\" in Emacs terms. -Return an Emacs frame object. -PARAMETERS is an alist of frame parameters. -If the parameters specify that the frame should not have a minibuffer, -and do not specify a specific minibuffer window to use, -then `default-minibuffer-frame' must be a frame whose minibuffer can -be shared by the new frame. - -This function is an internal primitive--use `make-frame' instead. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object parameters) { struct frame *f; @@ -6097,8 +6089,7 @@ x_get_focus_frame (struct frame *frame) } DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, - doc: /* Internal function called by `color-defined-p', which see. -\(Note that the Nextstep version of this function ignores FRAME.) */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object color, Lisp_Object frame) { XColor foo; @@ -6113,7 +6104,7 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, } DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, - doc: /* Internal function called by `color-values', which see. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object color, Lisp_Object frame) { XColor foo; @@ -6130,7 +6121,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, } DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, - doc: /* Internal function called by `display-color-p', which see. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6143,11 +6134,7 @@ DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, 0, 1, 0, - doc: /* Return t if DISPLAY supports shades of gray. -Note that color displays do support shades of gray. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6160,14 +6147,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, 0, 1, 0, - doc: /* Return the width in pixels of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the pixel width for all -physical monitors associated with DISPLAY. To get information for -each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6177,14 +6157,7 @@ each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_height, 0, 1, 0, - doc: /* Return the height in pixels of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the pixel height for all -physical monitors associated with DISPLAY. To get information for -each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6194,10 +6167,7 @@ each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, 0, 1, 0, - doc: /* Return the number of bitplanes of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6207,10 +6177,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, 0, 1, 0, - doc: /* Return the number of color cells of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6228,57 +6195,28 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-server-max-request-size", Fx_server_max_request_size, Sx_server_max_request_size, 0, 1, 0, - doc: /* Return the maximum request size of the server of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { return make_number (1); } DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, - doc: /* Return the "vendor ID" string of the GUI software on TERMINAL. - -\(Labeling every distributor as a "vendor" embodies the false assumption -that operating systems cannot be developed and distributed noncommercially.) - -For GNU and Unix systems, this queries the X server software; for -MS-Windows, this queries the OS. - -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { return build_string ("Microsoft Corp."); } DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, - doc: /* Return the version numbers of the GUI software on TERMINAL. -The value is a list of three integers specifying the version of the GUI -software in use. - -For GNU and Unix system, the first 2 numbers are the version of the X -Protocol used on TERMINAL and the 3rd number is the distributor-specific -release number. For MS-Windows, the 3 numbers report the version and -the build number of the OS. - -See also the function `x-server-vendor'. - -The optional argument TERMINAL specifies which display to ask about. -TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object terminal) { return list3i (w32_major_version, w32_minor_version, w32_build_number); } DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, - doc: /* Return the number of screens on the server of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { return make_number (1); @@ -6286,14 +6224,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, - doc: /* Return the height in millimeters of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the height in millimeters for -all physical monitors associated with DISPLAY. To get information -for each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6309,14 +6240,7 @@ for each physical monitor, use `display-monitor-attributes-list'. */) } DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, - doc: /* Return the width in millimeters of DISPLAY. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. - -On \"multi-monitor\" setups this refers to the width in millimeters for -all physical monitors associated with TERMINAL. To get information -for each physical monitor, use `display-monitor-attributes-list'. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6333,11 +6257,7 @@ for each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store, 0, 1, 0, - doc: /* Return an indication of whether DISPLAY does backing store. -The value may be `always', `when-mapped', or `not-useful'. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { return intern ("not-useful"); @@ -6345,13 +6265,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-visual-class", Fx_display_visual_class, Sx_display_visual_class, 0, 1, 0, - doc: /* Return the visual class of DISPLAY. -The value is one of the symbols `static-gray', `gray-scale', -`static-color', `pseudo-color', `true-color', or `direct-color'. - -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6360,7 +6274,7 @@ If omitted or nil, that stands for the selected frame's display. */) if (dpyinfo->has_palette) result = intern ("pseudo-color"); else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1) - result = intern ("static-grey"); + result = intern ("static-gray"); else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4) result = intern ("static-color"); else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8) @@ -6371,10 +6285,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-display-save-under", Fx_display_save_under, Sx_display_save_under, 0, 1, 0, - doc: /* Return t if DISPLAY supports the save-under feature. -The optional argument DISPLAY specifies which display to ask about. -DISPLAY should be either a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { return Qnil; @@ -6423,7 +6334,7 @@ w32_display_monitor_attributes_list (void) { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) + if (FRAME_W32_P (f) && !FRAME_TOOLTIP_P (f)) { HMONITOR monitor = monitor_from_window_fn (FRAME_W32_WINDOW (f), @@ -6510,7 +6421,7 @@ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo) { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) + if (FRAME_W32_P (f) && !FRAME_TOOLTIP_P (f)) frames = Fcons (frame, frames); } attributes = Fcons (Fcons (Qframes, frames), attributes); @@ -6639,12 +6550,7 @@ x_display_info_for_name (Lisp_Object name) } DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, - 1, 3, 0, doc: /* Open a connection to a display server. -DISPLAY is the name of the display to connect to. -Optional second arg XRM-STRING is a string of resources in xrdb format. -If the optional third arg MUST-SUCCEED is non-nil, -terminate Emacs if we can't open the connection. -\(In the Nextstep version, the last two arguments are currently ignored.) */) + 1, 3, 0, doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display, Lisp_Object xrm_string, Lisp_Object must_succeed) { char *xrm_option; @@ -6726,9 +6632,7 @@ terminate Emacs if we can't open the connection. DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0, - doc: /* Close the connection to DISPLAY's server. -For DISPLAY, specify either a frame or a display name (a string). -If DISPLAY is nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object display) { struct w32_display_info *dpyinfo = check_x_display_info (display); @@ -6746,7 +6650,7 @@ If DISPLAY is nil, that stands for the selected frame's display. */) } DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, - doc: /* Return the list of display names that Emacs has connections to. */) + doc: /* SKIP: real doc in xfns.c. */) (void) { Lisp_Object result = Qnil; @@ -6759,17 +6663,7 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, } DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0, - doc: /* If ON is non-nil, report X errors as soon as the erring request is made. -This function only has an effect on X Windows. With MS Windows, it is -defined but does nothing. - -If ON is nil, allow buffering of requests. -Turning on synchronization prohibits the Xlib routines from buffering -requests and seriously degrades performance, but makes debugging much -easier. -The optional second argument TERMINAL specifies which display to act on. -TERMINAL should be a terminal object, a frame or a display name (a string). -If TERMINAL is omitted or nil, that stands for the selected frame's display. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object on, Lisp_Object display) { return Qnil; @@ -6785,21 +6679,7 @@ If TERMINAL is omitted or nil, that stands for the selected frame's display. */ DEFUN ("x-change-window-property", Fx_change_window_property, Sx_change_window_property, 2, 6, 0, - doc: /* Change window property PROP to VALUE on the X window of FRAME. -PROP must be a string. VALUE may be a string or a list of conses, -numbers and/or strings. If an element in the list is a string, it is -converted to an atom and the value of the Atom is used. If an element -is a cons, it is converted to a 32 bit number where the car is the 16 -top bits and the cdr is the lower 16 bits. - -FRAME nil or omitted means use the selected frame. -If TYPE is given and non-nil, it is the name of the type of VALUE. -If TYPE is not given or nil, the type is STRING. -FORMAT gives the size in bits of each element if VALUE is a list. -It must be one of 8, 16 or 32. -If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8. -If OUTER-P is non-nil, the property is changed for the outer X window of -FRAME. Default is to change on the edit X window. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object prop, Lisp_Object value, Lisp_Object frame, Lisp_Object type, Lisp_Object format, Lisp_Object outer_p) { @@ -6825,8 +6705,7 @@ FRAME. Default is to change on the edit X window. */) DEFUN ("x-delete-window-property", Fx_delete_window_property, Sx_delete_window_property, 1, 2, 0, - doc: /* Remove window property PROP from X window of FRAME. -FRAME nil or omitted means use the selected frame. Value is PROP. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object prop, Lisp_Object frame) { struct frame *f = decode_window_system_frame (frame); @@ -6847,21 +6726,7 @@ FRAME nil or omitted means use the selected frame. Value is PROP. */) DEFUN ("x-window-property", Fx_window_property, Sx_window_property, 1, 6, 0, - doc: /* Value is the value of window property PROP on FRAME. -If FRAME is nil or omitted, use the selected frame. - -On X Windows, the following optional arguments are also accepted: -If TYPE is nil or omitted, get the property as a string. -Otherwise TYPE is the name of the atom that denotes the type expected. -If SOURCE is non-nil, get the property on that window instead of from -FRAME. The number 0 denotes the root window. -If DELETE-P is non-nil, delete the property after retrieving it. -If VECTOR-RET-P is non-nil, don't return a string but a vector of values. - -On MS Windows, this function accepts but ignores those optional arguments. - -Value is nil if FRAME hasn't a property with name PROP or if PROP has -no value of TYPE (always string in the MS Windows case). */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object prop, Lisp_Object frame, Lisp_Object type, Lisp_Object source, Lisp_Object delete_p, Lisp_Object vector_ret_p) { @@ -6916,20 +6781,25 @@ no value of TYPE (always string in the MS Windows case). */) static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, Lisp_Object, int, int, int *, int *); -/* The frame of a currently visible tooltip. */ - +/* The frame of the currently visible tooltip. */ Lisp_Object tip_frame; -/* If non-nil, a timer started that hides the last tooltip when it - fires. */ +/* The window-system window corresponding to the frame of the + currently visible tooltip. */ +Window tip_window; +/* A timer that hides or deletes the currently visible tooltip when it + fires. */ Lisp_Object tip_timer; -Window tip_window; -/* If non-nil, a vector of 3 elements containing the last args - with which x-show-tip was called. See there. */ +/* STRING argument of last `x-show-tip' call. */ +Lisp_Object tip_last_string; + +/* Normalized FRAME argument of last `x-show-tip' call. */ +Lisp_Object tip_last_frame; -Lisp_Object last_show_tip_args; +/* PARMS argument of last `x-show-tip' call. */ +Lisp_Object tip_last_parms; static void @@ -7002,6 +6872,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) FRAME_FONTSET (f) = -1; fset_icon_name (f, Qnil); + f->tooltip = true; #ifdef GLYPH_DEBUG image_cache_refcount = @@ -7261,7 +7132,17 @@ compute_tip_xy (struct frame *f, *root_x = min_x; } -/* Hide tooltip. Delete its frame if DELETE is true. */ +/** + * x_hide_tip: + * + * Hide currently visible tooltip and cancel its timer. + * + * This will try to make tooltip_frame invisible (if DELETE is false) + * or delete tooltip_frame (if DELETE is true). + * + * Return Qt if the tooltip was either deleted or made invisible, Qnil + * otherwise. + */ static Lisp_Object x_hide_tip (bool delete) { @@ -7286,15 +7167,20 @@ x_hide_tip (bool delete) if (FRAMEP (tip_frame)) { - if (delete) + if (FRAME_LIVE_P (XFRAME (tip_frame))) { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (XFRAME (tip_frame)); + + was_open = Qt; } else - x_make_frame_invisible (XFRAME (tip_frame)); - - was_open = Qt; + tip_frame = Qnil; } else tip_frame = Qnil; @@ -7305,36 +7191,9 @@ x_hide_tip (bool delete) DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, - doc: /* Show STRING in a \"tooltip\" window on frame FRAME. -A tooltip window is a small window displaying a string. - -This is an internal function; Lisp code should call `tooltip-show'. - -FRAME nil or omitted means use the selected frame. - -PARMS is an optional list of frame parameters which can be -used to change the tooltip's appearance. - -Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil -means use the default timeout of 5 seconds. - -If the list of frame parameters PARMS contains a `left' parameter, -display the tooltip at that x-position. If the list of frame parameters -PARMS contains no `left' but a `right' parameter, display the tooltip -right-adjusted at that x-position. Otherwise display it at the -x-position of the mouse, with offset DX added (default is 5 if DX isn't -specified). - -Likewise for the y-position: If a `top' frame parameter is specified, it -determines the position of the upper edge of the tooltip window. If a -`bottom' parameter but no `top' frame parameter is specified, it -determines the position of the lower edge of the tooltip window. -Otherwise display the tooltip window at the y-position of the mouse, -with offset DY added (default is -10). - -A tooltip's maximum size is specified by `x-max-tooltip-size'. -Text larger than the specified size is clipped. */) - (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) + doc: /* SKIP: real doc in xfns.c. */) + (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, + Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { struct frame *tip_f; struct window *w; @@ -7345,14 +7204,17 @@ Text larger than the specified size is clipped. */) int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size; - Lisp_Object tip_buf; + Lisp_Object window, size, tip_buf; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); CHECK_STRING (string); + + if (NILP (frame)) + frame = selected_frame; decode_window_system_frame (frame); + if (NILP (timeout)) timeout = make_number (5); else @@ -7368,19 +7230,12 @@ Text larger than the specified size is clipped. */) else CHECK_NUMBER (dy); - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (last_show_tip_args, 0); - Lisp_Object last_frame = AREF (last_show_tip_args, 1); - Lisp_Object last_parms = AREF (last_show_tip_args, 2); - if (FRAME_VISIBLE_P (XFRAME (tip_frame)) - && EQ (frame, last_frame) - && !NILP (Fequal_including_properties (last_string, string)) - && !NILP (Fequal (last_parms, parms))) + && EQ (frame, tip_last_frame) + && !NILP (Fequal_including_properties (string, tip_last_string)) + && !NILP (Fequal (parms, tip_last_parms))) { /* Only DX and DY have changed. */ tip_f = XFRAME (tip_frame); @@ -7414,14 +7269,14 @@ Text larger than the specified size is clipped. */) goto start_timer; } - else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) + else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) { bool delete = false; Lisp_Object tail, elt, parm, last; /* Check if every parameter in PARMS has the same value in - last_parms. This may destruct last_parms which, however, - will be recreated below. */ + tip_last_parms. This may destruct tip_last_parms + which, however, will be recreated below. */ for (tail = parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); @@ -7431,7 +7286,7 @@ Text larger than the specified size is clipped. */) if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) && !EQ (parm, Qbottom)) { - last = Fassq (parm, last_parms); + last = Fassq (parm, tip_last_parms); if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) { /* We lost, delete the old tooltip. */ @@ -7439,15 +7294,17 @@ Text larger than the specified size is clipped. */) break; } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } - /* Now check if there's a parameter left in last_parms with a + /* Now check if there's a parameter left in tip_last_parms with a non-nil value. */ - for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) + for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); parm = Fcar (elt); @@ -7468,9 +7325,9 @@ Text larger than the specified size is clipped. */) else x_hide_tip (true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + tip_last_frame = frame; + tip_last_string = string; + tip_last_parms = parms; /* Block input until the tip has been fully drawn, to avoid crashes when drawing tips in menus. */ @@ -7486,12 +7343,13 @@ Text larger than the specified size is clipped. */) if (NILP (Fassq (Qborder_width, parms))) parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); if (NILP (Fassq (Qborder_color, parms))) - parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); + parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), + parms); if (NILP (Fassq (Qbackground_color, parms))) parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), parms); - /* Create a frame for the tooltip, and record it in the global + /* Create a frame for the tooltip and record it in the global variable tip_frame. */ struct frame *f; /* The value is unused. */ if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) @@ -7612,8 +7470,7 @@ Text larger than the specified size is clipped. */) DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, - doc: /* Hide the current tooltip window, if there is any. -Value is t if tooltip was open, nil otherwise. */) + doc: /* SKIP: real doc in xfns.c. */) (void) { return x_hide_tip (!tooltip_reuse_hidden_frame); @@ -7744,18 +7601,7 @@ w32_dialog_in_progress (Lisp_Object in_progress) } DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, - doc: /* Read file name, prompting with PROMPT in directory DIR. -Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file -selection box, if specified. If MUSTMATCH is non-nil, the returned file -or directory must exist. - -This function is only defined on NS, MS Windows, and X Windows with the -Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. -Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. -On Windows 7 and later, the file selection dialog "remembers" the last -directory where the user selected a file, and will open that directory -instead of DIR on subsequent invocations of this function with the same -value of DIR as in previous invocations; this is standard Windows behavior. */) + doc: /* SKIP: real doc in xfns.c. */) (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p) { /* Filter index: 1: All Files, 2: Directories only */ @@ -9213,115 +9059,6 @@ The coordinates X and Y are interpreted in pixels relative to a position return Qnil; } -DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0, - doc: /* Get power status information from Windows system. - -The following %-sequences are provided: -%L AC line status (verbose) -%B Battery status (verbose) -%b Battery status, empty means high, `-' means low, - `!' means critical, and `+' means charging -%p Battery load percentage -%s Remaining time (to charge or discharge) in seconds -%m Remaining time (to charge or discharge) in minutes -%h Remaining time (to charge or discharge) in hours -%t Remaining time (to charge or discharge) in the form `h:min' */) - (void) -{ - Lisp_Object status = Qnil; - - SYSTEM_POWER_STATUS system_status; - if (GetSystemPowerStatus (&system_status)) - { - Lisp_Object line_status, battery_status, battery_status_symbol; - Lisp_Object load_percentage, seconds, minutes, hours, remain; - - long seconds_left = (long) system_status.BatteryLifeTime; - - if (system_status.ACLineStatus == 0) - line_status = build_string ("off-line"); - else if (system_status.ACLineStatus == 1) - line_status = build_string ("on-line"); - else - line_status = build_string ("N/A"); - - if (system_status.BatteryFlag & 128) - { - battery_status = build_string ("N/A"); - battery_status_symbol = empty_unibyte_string; - } - else if (system_status.BatteryFlag & 8) - { - battery_status = build_string ("charging"); - battery_status_symbol = build_string ("+"); - if (system_status.BatteryFullLifeTime != -1L) - seconds_left = system_status.BatteryFullLifeTime - seconds_left; - } - else if (system_status.BatteryFlag & 4) - { - battery_status = build_string ("critical"); - battery_status_symbol = build_string ("!"); - } - else if (system_status.BatteryFlag & 2) - { - battery_status = build_string ("low"); - battery_status_symbol = build_string ("-"); - } - else if (system_status.BatteryFlag & 1) - { - battery_status = build_string ("high"); - battery_status_symbol = empty_unibyte_string; - } - else - { - battery_status = build_string ("medium"); - battery_status_symbol = empty_unibyte_string; - } - - if (system_status.BatteryLifePercent > 100) - load_percentage = build_string ("N/A"); - else - { - char buffer[16]; - snprintf (buffer, 16, "%d", system_status.BatteryLifePercent); - load_percentage = build_string (buffer); - } - - if (seconds_left < 0) - seconds = minutes = hours = remain = build_string ("N/A"); - else - { - long m; - double h; - char buffer[16]; - snprintf (buffer, 16, "%ld", seconds_left); - seconds = build_string (buffer); - - m = seconds_left / 60; - snprintf (buffer, 16, "%ld", m); - minutes = build_string (buffer); - - h = seconds_left / 3600.0; - snprintf (buffer, 16, "%3.1f", h); - hours = build_string (buffer); - - snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60); - remain = build_string (buffer); - } - - status = listn (CONSTYPE_HEAP, 8, - Fcons (make_number ('L'), line_status), - Fcons (make_number ('B'), battery_status), - Fcons (make_number ('b'), battery_status_symbol), - Fcons (make_number ('p'), load_percentage), - Fcons (make_number ('s'), seconds), - Fcons (make_number ('m'), minutes), - Fcons (make_number ('h'), hours), - Fcons (make_number ('t'), remain)); - } - return status; -} - #ifdef WINDOWSNT typedef BOOL (WINAPI *GetDiskFreeSpaceExW_Proc) @@ -9330,11 +9067,7 @@ typedef BOOL (WINAPI *GetDiskFreeSpaceExA_Proc) (LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0, - doc: /* Return storage information about the file system FILENAME is on. -Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total -storage of the file system, FREE is the free storage, and AVAIL is the -storage available to a non-superuser. All 3 numbers are in bytes. -If the underlying system call fails, value is nil. */) + doc: /* SKIP: Real doc in fileio.c. */) (Lisp_Object filename) { Lisp_Object encoded, value; @@ -9343,6 +9076,17 @@ If the underlying system call fails, value is nil. */) filename = Fexpand_file_name (filename, Qnil); encoded = ENCODE_FILE (filename); + /* If the file name has special constructs in it, + call the corresponding file handler. */ + Lisp_Object handler = Ffind_file_name_handler (encoded, Qfile_system_info); + if (!NILP (handler)) + { + value = call2 (handler, Qfile_system_info, encoded); + if (CONSP (value) || NILP (value)) + return value; + error ("Invalid handler in `file-name-handler-alist'"); + } + value = Qnil; /* Determining the required information on Windows turns out, sadly, @@ -10413,6 +10157,7 @@ syms_of_w32fns (void) DEFSYM (Qserif, "serif"); DEFSYM (Qzlib, "zlib"); DEFSYM (Qlcms2, "lcms2"); + DEFSYM (Qjson, "json"); Fput (Qundefined_color, Qerror_conditions, listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror)); @@ -10605,9 +10350,7 @@ bass-down, bass-boost, bass-up, treble-down, treble-up */); #if 0 /* TODO: Mouse cursor customization. */ DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape, - doc: /* The shape of the pointer when over text. -Changing the value does not affect existing frames -unless you set the mouse color. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_pointer_shape = Qnil; Vx_nontext_pointer_shape = Qnil; @@ -10615,58 +10358,42 @@ unless you set the mouse color. */); Vx_mode_pointer_shape = Qnil; DEFVAR_LISP ("x-hourglass-pointer-shape", Vx_hourglass_pointer_shape, - doc: /* The shape of the pointer when Emacs is busy. -This variable takes effect when you create a new frame -or when you set the mouse color. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_hourglass_pointer_shape = Qnil; DEFVAR_LISP ("x-sensitive-text-pointer-shape", Vx_sensitive_text_pointer_shape, - doc: /* The shape of the pointer when over mouse-sensitive text. -This variable takes effect when you create a new frame -or when you set the mouse color. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_sensitive_text_pointer_shape = Qnil; DEFVAR_LISP ("x-window-horizontal-drag-cursor", Vx_window_horizontal_drag_shape, - doc: /* Pointer shape to use for indicating a window can be dragged horizontally. -This variable takes effect when you create a new frame -or when you set the mouse color. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_window_horizontal_drag_shape = Qnil; DEFVAR_LISP ("x-window-vertical-drag-cursor", Vx_window_vertical_drag_shape, - doc: /* Pointer shape to use for indicating a window can be dragged vertically. -This variable takes effect when you create a new frame -or when you set the mouse color. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_window_vertical_drag_shape = Qnil; #endif DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, - doc: /* A string indicating the foreground color of the cursor box. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_cursor_fore_pixel = Qnil; DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size, - doc: /* Maximum size for tooltips. -Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_max_tooltip_size = Fcons (make_number (80), make_number (40)); DEFVAR_LISP ("x-no-window-manager", Vx_no_window_manager, - doc: /* Non-nil if no window manager is in use. -Emacs doesn't try to figure this out; this is always nil -unless you set it to something else. */); + doc: /* SKIP: real doc in xfns.c. */); /* We don't have any way to find this out, so set it to nil and maybe the user would like to set it to t. */ Vx_no_window_manager = Qnil; DEFVAR_LISP ("x-pixel-size-width-font-regexp", Vx_pixel_size_width_font_regexp, - doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. - -Since Emacs gets width of a font matching with this regexp from -PIXEL_SIZE field of the name, font finding mechanism gets faster for -such a font. This is especially effective for such large fonts as -Chinese, Japanese, and Korean. */); + doc: /* SKIP: real doc in xfns.c. */); Vx_pixel_size_width_font_regexp = Qnil; DEFVAR_LISP ("w32-bdf-filename-alist", @@ -10774,7 +10501,6 @@ tip frame. */); defsubr (&Sw32_reconstruct_hot_key); defsubr (&Sw32_toggle_lock_key); defsubr (&Sw32_window_exists_p); - defsubr (&Sw32_battery_status); defsubr (&Sw32__menu_bar_in_use); #if defined WINDOWSNT && !defined HAVE_DBUS defsubr (&Sw32_notification_notify); @@ -10793,9 +10519,12 @@ tip frame. */); staticpro (&tip_timer); tip_frame = Qnil; staticpro (&tip_frame); - - last_show_tip_args = Qnil; - staticpro (&last_show_tip_args); + tip_last_frame = Qnil; + staticpro (&tip_last_frame); + tip_last_string = Qnil; + staticpro (&tip_last_string); + tip_last_parms = Qnil; + staticpro (&tip_last_parms); defsubr (&Sx_file_dialog); #ifdef WINDOWSNT diff --git a/src/w32menu.c b/src/w32menu.c index 0cd7284c9b0..30ad54db26d 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1571,7 +1571,7 @@ w32_free_menu_strings (HWND hwnd) /* The following is used by delayed window autoselection. */ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, - doc: /* Return t if a menu or popup dialog is active on selected frame. */) + doc: /* SKIP: real doc in xmenu.c. */) (void) { struct frame *f; diff --git a/src/w32notify.c b/src/w32notify.c index c16a8d11b65..5c1d2120543 100644 --- a/src/w32notify.c +++ b/src/w32notify.c @@ -1,5 +1,8 @@ /* Filesystem notifications support for GNU Emacs on the Microsoft Windows API. - Copyright (C) 2012-2018 Free Software Foundation, Inc. + +Copyright (C) 2012-2018 Free Software Foundation, Inc. + +Author: Eli Zaretskii <eliz@gnu.org> This file is part of GNU Emacs. @@ -16,9 +19,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ -/* Written by Eli Zaretskii <eliz@gnu.org>. - - Design overview: +/* Design overview: For each watch request, we launch a separate worker thread. The worker thread runs the watch_worker function, which issues an diff --git a/src/w32reg.c b/src/w32reg.c index df61847887a..4ddbaa3f268 100644 --- a/src/w32reg.c +++ b/src/w32reg.c @@ -1,6 +1,8 @@ /* Emulate the X Resource Manager through the registry. - Copyright (C) 1990, 1993-1994, 2001-2018 Free Software Foundation, - Inc. + +Copyright (C) 1990, 1993-1994, 2001-2018 Free Software Foundation, Inc. + +Author: Kevin Gallo This file is part of GNU Emacs. @@ -17,8 +19,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ -/* Written by Kevin Gallo */ - #include <config.h> #include "lisp.h" #include "w32term.h" /* for XrmDatabase, xrdb */ diff --git a/src/w32select.c b/src/w32select.c index c451b7ff933..a9df3f770b7 100644 --- a/src/w32select.c +++ b/src/w32select.c @@ -2,6 +2,9 @@ Copyright (C) 1993-1994, 2001-2018 Free Software Foundation, Inc. +Author: Kevin Gallo + Benjamin Riefenstahl + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify @@ -17,9 +20,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ -/* Written by Kevin Gallo, Benjamin Riefenstahl */ - - /* * Notes on usage of selection-coding-system and * next-selection-coding-system on MS Windows: @@ -1170,45 +1170,13 @@ syms_of_w32select (void) defsubr (&Sw32_selection_targets); DEFVAR_LISP ("selection-coding-system", Vselection_coding_system, - doc: /* Coding system for communicating with other programs. - -For MS-Windows and MS-DOS: -When sending or receiving text via selection and clipboard, the text -is encoded or decoded by this coding system. The default value is -the current system default encoding on 9x/Me, `utf-16le-dos' -\(Unicode) on NT/W2K/XP, and `iso-latin-1-dos' on MS-DOS. - -For X Windows: -When sending text via selection and clipboard, if the target -data-type matches with the type of this coding system, it is used -for encoding the text. Otherwise (including the case that this -variable is nil), a proper coding system is used as below: - -data-type coding system ---------- ------------- -UTF8_STRING utf-8 -COMPOUND_TEXT compound-text-with-extensions -STRING iso-latin-1 -C_STRING no-conversion - -When receiving text, if this coding system is non-nil, it is used -for decoding regardless of the data-type. If this is nil, a -proper coding system is used according to the data-type as above. - -See also the documentation of the variable `x-select-request-type' how -to control which data-type to request for receiving text. - -The default value is nil. */); + doc: /* SKIP: real doc in select.el. */); /* The actual value is set dynamically in the dumped Emacs, see below. */ Vselection_coding_system = Qnil; DEFVAR_LISP ("next-selection-coding-system", Vnext_selection_coding_system, - doc: /* Coding system for the next communication with other programs. -Usually, `selection-coding-system' is used for communicating with -other programs (X Windows clients or MS Windows programs). But, if this -variable is set, it is used for the next communication only. -After the communication, this variable is set to nil. */); + doc: /* SKIP: real doc in select.el. */); Vnext_selection_coding_system = Qnil; DEFSYM (QCLIPBOARD, "CLIPBOARD"); diff --git a/src/w32term.c b/src/w32term.c index 611b7c66e7a..24950dd25ec 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2475,31 +2475,52 @@ x_draw_glyph_string (struct glyph_string *s) else { struct font *font = font_for_underline_metrics (s); + unsigned long minimum_offset; + BOOL underline_at_descent_line; + BOOL use_underline_position_properties; + Lisp_Object val + = buffer_local_value (Qunderline_minimum_offset, + s->w->contents); + if (INTEGERP (val)) + minimum_offset = XFASTINT (val); + else + minimum_offset = 1; + val = buffer_local_value (Qx_underline_at_descent_line, + s->w->contents); + underline_at_descent_line + = !(NILP (val) || EQ (val, Qunbound)); + val + = buffer_local_value (Qx_use_underline_position_properties, + s->w->contents); + use_underline_position_properties + = !(NILP (val) || EQ (val, Qunbound)); /* Get the underline thickness. Default is 1 pixel. */ if (font && font->underline_thickness > 0) thickness = font->underline_thickness; else thickness = 1; - if (x_underline_at_descent_line || !font) + if (underline_at_descent_line + || !font) position = (s->height - thickness) - (s->ybase - s->y); else { - /* Get the underline position. This is the recommended - vertical offset in pixels from the baseline to the top of - the underline. This is a signed value according to the + /* Get the underline position. This is the + recommended vertical offset in pixels from + the baseline to the top of the underline. + This is a signed value according to the specs, and its default is ROUND ((maximum_descent) / 2), with ROUND (x) = floor (x + 0.5) */ - if (x_use_underline_position_properties + if (use_underline_position_properties && font->underline_position >= 0) position = font->underline_position; else position = (font->descent + 1) / 2; } - position = max (position, underline_minimum_offset); + position = max (position, minimum_offset); } /* Check the sanity of thickness and position. We should avoid drawing underline out of the current line area. */ @@ -5569,7 +5590,7 @@ w32_read_socket (struct terminal *terminal, struct frame *f = XFRAME (frame); /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED below. */ - if (EQ (frame, tip_frame)) + if (FRAME_TOOLTIP_P (f)) continue; /* Check "visible" frames and mark each as obscured or not. @@ -6046,7 +6067,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) /* Don't change the size of a tip frame; there's no point in doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ - if (NILP (tip_frame) || XFRAME (tip_frame) != f) + if (!FRAME_TOOLTIP_P (f)) adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont); @@ -7329,14 +7350,7 @@ syms_of_w32term (void) DEFSYM (Qrenamed_to, "renamed-to"); DEFVAR_LISP ("x-wait-for-event-timeout", Vx_wait_for_event_timeout, - doc: /* How long to wait for X events. - -Emacs will wait up to this many seconds to receive X events after -making changes which affect the state of the graphical interface. -Under some window managers this can take an indefinite amount of time, -so it is important to limit the wait. - -If set to a non-float value, there will be no wait at all. */); + doc: /* SKIP: real doc in xterm.c. */); Vx_wait_for_event_timeout = make_float (0.1); DEFVAR_INT ("w32-num-mouse-buttons", @@ -7390,30 +7404,19 @@ the cursor have no effect. */); from cus-start.el and other places, like "M-x set-variable". */ DEFVAR_BOOL ("x-use-underline-position-properties", x_use_underline_position_properties, - doc: /* Non-nil means make use of UNDERLINE_POSITION font properties. -A value of nil means ignore them. If you encounter fonts with bogus -UNDERLINE_POSITION font properties, for example 7x13 on XFree prior -to 4.1, set this to nil. You can also use `underline-minimum-offset' -to override the font's UNDERLINE_POSITION for small font display -sizes. */); + doc: /* SKIP: real doc in xterm.c. */); x_use_underline_position_properties = 0; + DEFSYM (Qx_use_underline_position_properties, + "x-use-underline-position-properties"); DEFVAR_BOOL ("x-underline-at-descent-line", x_underline_at_descent_line, - doc: /* Non-nil means to draw the underline at the same place as the descent line. -(If `line-spacing' is in effect, that moves the underline lower by -that many pixels.) -A value of nil means to draw the underline according to the value of the -variable `x-use-underline-position-properties', which is usually at the -baseline level. The default value is nil. */); + doc: /* SKIP: real doc in xterm.c. */); x_underline_at_descent_line = 0; + DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, - doc: /* Which toolkit scroll bars Emacs uses, if any. -A value of nil means Emacs doesn't use toolkit scroll bars. -With the X Window system, the value is a symbol describing the -X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. -With MS Windows or Nextstep, the value is t. */); + doc: /* SKIP: real doc in xterm.c. */); Vx_toolkit_scroll_bars = Qt; DEFVAR_BOOL ("w32-unicode-filenames", diff --git a/src/w32term.h b/src/w32term.h index e500b730ead..c69bebeebdd 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -817,6 +817,8 @@ extern struct window *w32_system_caret_window; extern int w32_system_caret_hdr_height; extern int w32_system_caret_mode_height; +extern Window tip_window; + #ifdef _MSC_VER #ifndef EnumSystemLocales /* MSVC headers define these only for _WIN32_WINNT >= 0x0500. */ diff --git a/src/window.h b/src/window.h index 629283ac40c..91ef7d90272 100644 --- a/src/window.h +++ b/src/window.h @@ -178,6 +178,9 @@ struct window /* An alist with parameters. */ Lisp_Object window_parameters; + /* The help echo text for this window. Qnil if there's none. */ + Lisp_Object mode_line_help_echo; + /* No Lisp data may follow below this point without changing mark_object in alloc.c. The member current_matrix must be the first non-Lisp member. */ @@ -445,6 +448,12 @@ wset_redisplay_end_trigger (struct window *w, Lisp_Object val) } INLINE void +wset_mode_line_help_echo (struct window *w, Lisp_Object val) +{ + w->mode_line_help_echo = val; +} + +INLINE void wset_new_pixel (struct window *w, Lisp_Object val) { w->new_pixel = val; diff --git a/src/xdisp.c b/src/xdisp.c index b003a2f9ccc..44eb1ebf059 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -440,10 +440,8 @@ static Lisp_Object default_invis_vector[3]; Lisp_Object echo_area_window; -/* List of pairs (MESSAGE . MULTIBYTE). The function save_message - pushes the current message and the value of - message_enable_multibyte on the stack, the function restore_message - pops the stack and displays MESSAGE again. */ +/* Stack of messages, which are pushed by push_message and popped and + displayed by restore_message. */ static Lisp_Object Vmessage_stack; @@ -8718,8 +8716,12 @@ move_it_in_display_line_to (struct it *it, if (it->hpos == 0) { - /* If line numbers are being displayed, produce a line number. */ - if (should_produce_line_number (it)) + /* If line numbers are being displayed, produce a line number. + But don't do that if we are to reach first_visible_x, because + line numbers are not relevant to stuff that is not visible on + display. */ + if (!((op && MOVE_TO_X) && to_x == it->first_visible_x) + && should_produce_line_number (it)) { if (it->current_x == it->first_visible_x) maybe_produce_line_number (it); @@ -8790,7 +8792,16 @@ move_it_in_display_line_to (struct it *it, if (it->line_wrap == TRUNCATE) { - if (BUFFER_POS_REACHED_P ()) + /* If it->pixel_width is zero, the last PRODUCE_GLYPHS call + produced something that doesn't consume any screen estate + in the text area, so we don't want to exit the loop at + TO_CHARPOS, before we produce the glyph for that buffer + position. This happens, e.g., when there's an overlay at + TO_CHARPOS that draws a fringe bitmap. */ + if (BUFFER_POS_REACHED_P () + && (it->pixel_width > 0 + || IT_CHARPOS (*it) > to_charpos + || it->area != TEXT_AREA)) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -10125,17 +10136,46 @@ include the height of both, if present, in the return value. */) itdata = bidi_shelve_cache (); SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start)); start_display (&it, w, startp); - - if (NILP (x_limit)) - x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y); - else + /* It makes no sense to measure dimensions of region of text that + crosses the point where bidi reordering changes scan direction. + By using unidirectional movement here we at least support the use + case of measuring regions of text that have a uniformly R2L + directionality, and regions that begin and end in text of the + same directionality. */ + it.bidi_p = false; + void *it2data = NULL; + struct it it2; + SAVE_IT (it2, it, it2data); + + int move_op = MOVE_TO_POS | MOVE_TO_Y; + int to_x = -1; + if (!NILP (x_limit)) { - it.last_visible_x = max_x; /* Actually, we never want move_it_to stop at to_x. But to make sure that move_it_in_display_line_to always moves far enough, - we set it to INT_MAX and specify MOVE_TO_X. */ - x = move_it_to (&it, end, INT_MAX, max_y, -1, - MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); + we set to_x to INT_MAX and specify MOVE_TO_X. */ + move_op |= MOVE_TO_X; + to_x = INT_MAX; + } + + x = move_it_to (&it, end, to_x, max_y, -1, move_op); + + /* We could have a display property at END, in which case asking + move_it_to to stop at END will overshoot and stop at position + after END. So we try again, stopping before END, and account for + the width of the last buffer position manually. */ + if (IT_CHARPOS (it) > end) + { + end--; + RESTORE_IT (&it, &it2, it2data); + x = move_it_to (&it, end, to_x, max_y, -1, move_op); + /* Add the width of the thing at TO, but only if we didn't + overshoot it; if we did, it is already accounted for. */ + if (IT_CHARPOS (it) == end) + x += it.pixel_width; + } + if (!NILP (x_limit)) + { /* Don't return more than X-LIMIT. */ if (x > max_x) x = max_x; @@ -10975,10 +11015,18 @@ setup_echo_area_for_printing (bool multibyte_p) } TEMP_SET_PT_BOTH (BEG, BEG_BYTE); - /* Set up the buffer for the multibyteness we need. */ - if (multibyte_p - != !NILP (BVAR (current_buffer, enable_multibyte_characters))) - Fset_buffer_multibyte (multibyte_p ? Qt : Qnil); + /* Set up the buffer for the multibyteness we need. We always + set it to be multibyte, except when + unibyte-display-via-language-environment is non-nil and the + buffer from which we are called is unibyte, because in that + case unibyte characters should not be displayed as octal + escapes. */ + if (unibyte_display_via_language_environment + && !multibyte_p + && !NILP (BVAR (current_buffer, enable_multibyte_characters))) + Fset_buffer_multibyte (Qnil); + else if (NILP (BVAR (current_buffer, enable_multibyte_characters))) + Fset_buffer_multibyte (Qt); /* Raise the frame containing the echo area. */ if (minibuffer_auto_raise) @@ -11424,10 +11472,17 @@ set_message_1 (ptrdiff_t a1, Lisp_Object string) { eassert (STRINGP (string)); - /* Change multibyteness of the echo buffer appropriately. */ - if (message_enable_multibyte - != !NILP (BVAR (current_buffer, enable_multibyte_characters))) - Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil); + /* Change multibyteness of the echo buffer appropriately. We always + set it to be multibyte, except when + unibyte-display-via-language-environment is non-nil and the + string to display is unibyte, because in that case unibyte + characters should not be displayed as octal escapes. */ + if (!message_enable_multibyte + && unibyte_display_via_language_environment + && !NILP (BVAR (current_buffer, enable_multibyte_characters))) + Fset_buffer_multibyte (Qnil); + else if (NILP (BVAR (current_buffer, enable_multibyte_characters))) + Fset_buffer_multibyte (Qt); bset_truncate_lines (current_buffer, message_truncate_lines ? Qt : Qnil); if (!NILP (BVAR (current_buffer, bidi_display_reordering))) @@ -11881,7 +11936,7 @@ x_consider_frame_title (Lisp_Object frame) if ((FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name) - && NILP (Fframe_parameter (frame, Qtooltip))) + && !FRAME_TOOLTIP_P (f)) { /* Do we have more than one visible frame on this X display? */ Lisp_Object tail, other_frame, fmt; @@ -11898,8 +11953,8 @@ x_consider_frame_title (Lisp_Object frame) if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f) && !FRAME_MINIBUF_ONLY_P (tf) - && !EQ (other_frame, tip_frame) && !FRAME_PARENT_FRAME (tf) + && !FRAME_TOOLTIP_P (tf) && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf))) break; } @@ -11968,13 +12023,6 @@ prepare_menu_bars (void) { bool all_windows = windows_or_buffers_changed || update_mode_lines; bool some_windows = REDISPLAY_SOME_P (); - Lisp_Object tooltip_frame; - -#ifdef HAVE_WINDOW_SYSTEM - tooltip_frame = tip_frame; -#else - tooltip_frame = Qnil; -#endif if (FUNCTIONP (Vpre_redisplay_function)) { @@ -12015,7 +12063,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - if (!EQ (frame, tooltip_frame) + if (!FRAME_TOOLTIP_P (f) && !FRAME_PARENT_FRAME (f) && (FRAME_ICONIFIED_P (f) || FRAME_VISIBLE_P (f) == 1 @@ -12053,7 +12101,7 @@ prepare_menu_bars (void) struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); /* Ignore tooltip frame. */ - if (EQ (frame, tooltip_frame)) + if (FRAME_TOOLTIP_P (f)) continue; if (some_windows @@ -12338,7 +12386,7 @@ build_desired_tool_bar_string (struct frame *f) /* Reuse f->desired_tool_bar_string, if possible. */ if (size < size_needed || NILP (f->desired_tool_bar_string)) fset_desired_tool_bar_string - (f, Fmake_string (make_number (size_needed), make_number (' '))); + (f, Fmake_string (make_number (size_needed), make_number (' '), Qnil)); else { AUTO_LIST4 (props, Qdisplay, Qnil, Qmenu_item, Qnil); @@ -21158,6 +21206,8 @@ maybe_produce_line_number (struct it *it) it->max_phys_descent = max (it->max_phys_descent, tem_it.max_phys_descent); } + it->line_number_produced_p = true; + bidi_unshelve_cache (itdata, false); } @@ -21175,13 +21225,7 @@ should_produce_line_number (struct it *it) #ifdef HAVE_WINDOW_SYSTEM /* Don't display line number in tooltip frames. */ - if (FRAMEP (tip_frame) && EQ (WINDOW_FRAME (it->w), tip_frame) -#ifdef USE_GTK - /* GTK builds store in tip_frame the frame that shows the tip, - so we need an additional test. */ - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (FRAME_TOOLTIP_P (XFRAME (WINDOW_FRAME (it->w)))) return false; #endif @@ -21281,6 +21325,8 @@ display_line (struct it *it, int cursor_vpos) row->displays_text_p = true; row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p; it->starts_in_middle_of_char_p = false; + it->tab_offset = 0; + it->line_number_produced_p = false; /* Arrange the overlays nicely for our purposes. Usually, we call display_line on only one line at a time, in which case this @@ -21325,6 +21371,10 @@ display_line (struct it *it, int cursor_vpos) || move_result == MOVE_POS_MATCH_OR_ZV)) it->current_x = it->first_visible_x; + /* In case move_it_in_display_line_to above "produced" the line + number. */ + it->line_number_produced_p = false; + /* Record the smallest positions seen while we moved over display elements that are not visible. This is needed by redisplay_internal for optimizing the case where the cursor @@ -21544,6 +21594,10 @@ display_line (struct it *it, int cursor_vpos) row->extra_line_spacing = max (row->extra_line_spacing, it->max_extra_line_spacing); if (it->current_x - it->pixel_width < it->first_visible_x + /* When line numbers are displayed, row->x should not be + offset, as the first glyph after the line number can + never be partially visible. */ + && !line_number_needed /* In R2L rows, we arrange in extend_face_to_end_of_line to add a right offset to the line, by a suitable change to the stretch glyph that is the leftmost @@ -21785,7 +21839,8 @@ display_line (struct it *it, int cursor_vpos) if (it->bidi_p) RECORD_MAX_MIN_POS (it); - if (x < it->first_visible_x && !row->reversed_p) + if (x < it->first_visible_x && !row->reversed_p + && !line_number_needed) /* Glyph is partially visible, i.e. row starts at negative X position. Don't do that in R2L rows, where we arrange to add a right offset to @@ -21801,6 +21856,7 @@ display_line (struct it *it, int cursor_vpos) be taken care of in produce_special_glyphs. */ if (row->reversed_p && new_x > it->last_visible_x + && !line_number_needed && !(it->line_wrap == TRUNCATE && WINDOW_LEFT_FRINGE_WIDTH (it->w) == 0)) { @@ -23213,6 +23269,23 @@ display_mode_lines (struct window *w) Lisp_Object old_frame_selected_window = XFRAME (new_frame)->selected_window; int n = 0; + if (window_wants_mode_line (w)) + { + Lisp_Object window; + Lisp_Object default_help + = buffer_local_value (Qmode_line_default_help_echo, w->contents); + + /* Set up mode line help echo. Do this before selecting w so it + can reasonably tell whether a mouse click will select w. */ + XSETWINDOW (window, w); + if (FUNCTIONP (default_help)) + wset_mode_line_help_echo (w, safe_call1 (default_help, window)); + else if (STRINGP (default_help)) + wset_mode_line_help_echo (w, default_help); + else + wset_mode_line_help_echo (w, Qnil); + } + selected_frame = new_frame; /* FIXME: If we were to allow the mode-line's computation changing the buffer or window's point, then we'd need select_window_1 here as well. */ @@ -23227,7 +23300,6 @@ display_mode_lines (struct window *w) { Lisp_Object window_mode_line_format = window_parameter (w, Qmode_line_format); - struct window *sel_w = XWINDOW (old_selected_window); /* Select mode line face based on the real selected window. */ @@ -23911,7 +23983,8 @@ store_mode_line_string (const char *string, Lisp_Object lisp_string, if (field_width > len) { field_width -= len; - lisp_string = Fmake_string (make_number (field_width), make_number (' ')); + lisp_string = Fmake_string (make_number (field_width), make_number (' '), + Qnil); if (!NILP (props)) Fadd_text_properties (make_number (0), make_number (field_width), props, lisp_string); @@ -28248,8 +28321,14 @@ x_produce_glyphs (struct it *it) int x = it->current_x + it->continuation_lines_width; int x0 = x; /* Adjust for line numbers, if needed. */ - if (!NILP (Vdisplay_line_numbers) && x0 >= it->lnum_pixel_width) - x -= it->lnum_pixel_width; + if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p) + { + x -= it->lnum_pixel_width; + /* Restore the original TAB width, if required. */ + if (x + it->tab_offset >= it->first_visible_x) + x += it->tab_offset; + } + int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; /* If the distance from the current position to the next tab @@ -28257,10 +28336,19 @@ x_produce_glyphs (struct it *it) tab stop after that. */ if (next_tab_x - x < font->space_width) next_tab_x += tab_width; - if (!NILP (Vdisplay_line_numbers) && x0 >= it->lnum_pixel_width) - next_tab_x += (it->lnum_pixel_width - - ((it->w->hscroll * font->space_width) - % tab_width)); + if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p) + { + next_tab_x += it->lnum_pixel_width; + /* If the line is hscrolled, and the TAB starts before + the first visible pixel, simulate negative row->x. */ + if (x < it->first_visible_x) + { + next_tab_x -= it->first_visible_x - x; + it->tab_offset = it->first_visible_x - x; + } + else + next_tab_x -= it->tab_offset; + } it->pixel_width = next_tab_x - x0; it->nglyphs = 1; @@ -30736,9 +30824,6 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); -#ifdef HAVE_WINDOW_SYSTEM - Display_Info *dpyinfo; -#endif Cursor cursor = No_Cursor; Lisp_Object pointer = Qnil; int dx, dy, width, height; @@ -30832,7 +30917,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, /* Set the help text and mouse pointer. If the mouse is on a part of the mode line without any text (e.g. past the right edge of - the mode line text), use the default help text and pointer. */ + the mode line text), use that windows's mode line help echo if it + has been set. */ if (STRINGP (string) || area == ON_MODE_LINE) { /* Arrange to display the help by setting the global variables @@ -30849,19 +30935,13 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, help_echo_object = string; help_echo_pos = charpos; } - else if (area == ON_MODE_LINE) + else if (area == ON_MODE_LINE + && !NILP (w->mode_line_help_echo)) { - Lisp_Object default_help - = buffer_local_value (Qmode_line_default_help_echo, - w->contents); - - if (STRINGP (default_help)) - { - help_echo_string = default_help; - XSETWINDOW (help_echo_window, w); - help_echo_object = Qnil; - help_echo_pos = -1; - } + help_echo_string = w->mode_line_help_echo; + XSETWINDOW (help_echo_window, w); + help_echo_object = Qnil; + help_echo_pos = -1; } } @@ -30873,7 +30953,6 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, || minibuf_level || NILP (Vresize_mini_windows)); - dpyinfo = FRAME_DISPLAY_INFO (f); if (STRINGP (string)) { cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -30883,25 +30962,28 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, /* Change the mouse pointer according to what is under X/Y. */ if (NILP (pointer) - && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) + && (area == ON_MODE_LINE || area == ON_HEADER_LINE)) { Lisp_Object map; + map = Fget_text_property (pos, Qlocal_map, string); if (!KEYMAPP (map)) map = Fget_text_property (pos, Qkeymap, string); - if (!KEYMAPP (map) && draggable) - cursor = dpyinfo->vertical_scroll_bar_cursor; + if (!KEYMAPP (map) && draggable && area == ON_MODE_LINE) + cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; } } - else if (draggable) - /* Default mode-line pointer. */ - cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; + else if (draggable && area == ON_MODE_LINE) + cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; + else + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; } #endif } /* Change the mouse face according to what is under X/Y. */ bool mouse_face_shown = false; + if (STRINGP (string)) { mouse_face = Fget_text_property (pos, Qmouse_face, string); @@ -31926,7 +32008,7 @@ x_draw_bottom_divider (struct window *w) int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); int y1 = WINDOW_BOTTOM_EDGE_Y (w); - struct window *p = !NILP (w->parent) ? XWINDOW (w->parent) : false; + struct window *p = !NILP (w->parent) ? XWINDOW (w->parent) : NULL; /* If W is vertically combined and has a sibling below, don't draw over any right divider. */ @@ -32958,6 +33040,7 @@ particularly when using variable `x-use-underline-position-properties' with fonts that specify an UNDERLINE_POSITION relatively close to the baseline. The default value is 1. */); underline_minimum_offset = 1; + DEFSYM (Qunderline_minimum_offset, "underline-minimum-offset"); DEFVAR_BOOL ("display-hourglass", display_hourglass_p, doc: /* Non-nil means show an hourglass pointer, when Emacs is busy. diff --git a/src/xfaces.c b/src/xfaces.c index f1fc6bb632f..56df06574a7 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -3393,7 +3393,7 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", else if (EQ (attr, QCheight)) { value = Fstring_to_number (value, make_number (10)); - if (XINT (value) <= 0) + if (!INTEGERP (value) || XINT (value) <= 0) signal_error ("Invalid face height from X resource", value); } else if (EQ (attr, QCbold) || EQ (attr, QCitalic)) @@ -4487,6 +4487,7 @@ lookup_basic_face (struct frame *f, int face_id) case MOUSE_FACE_ID: name = Qmouse; break; case MENU_FACE_ID: name = Qmenu; break; case WINDOW_DIVIDER_FACE_ID: name = Qwindow_divider; break; + case VERTICAL_BORDER_FACE_ID: name = Qvertical_border; break; case WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID: name = Qwindow_divider_first_pixel; break; case WINDOW_DIVIDER_LAST_PIXEL_FACE_ID: name = Qwindow_divider_last_pixel; break; case INTERNAL_BORDER_FACE_ID: name = Qinternal_border; break; @@ -6525,7 +6526,12 @@ other font of the appropriate family and registry is available. */); doc: /* List of ignored fonts. Each element is a regular expression that matches names of fonts to ignore. */); +#ifdef HAVE_OTF_KANNADA_BUG + /* https://debbugs.gnu.org/30193 */ + Vface_ignored_fonts = list1 (build_string ("Noto Serif Kannada")); +#else Vface_ignored_fonts = Qnil; +#endif DEFVAR_LISP ("face-remapping-alist", Vface_remapping_alist, doc: /* Alist of face remappings. diff --git a/src/xfns.c b/src/xfns.c index 20fe61bffd8..78151c81380 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -215,8 +215,9 @@ x_real_pos_and_offsets (struct frame *f, int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0; int real_x = 0, real_y = 0; bool had_errors = false; - Window win = (FRAME_PARENT_FRAME (f) - ? FRAME_X_WINDOW (FRAME_PARENT_FRAME (f)) + struct frame *parent_frame = FRAME_PARENT_FRAME (f); + Window win = (parent_frame + ? FRAME_X_WINDOW (parent_frame) : f->output_data.x->parent_desc); struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); long max_len = 400; @@ -355,8 +356,8 @@ x_real_pos_and_offsets (struct frame *f, outer_geom_cookie = xcb_get_geometry (xcb_conn, FRAME_OUTER_WINDOW (f)); - if ((dpyinfo->root_window == f->output_data.x->parent_desc) - && !FRAME_PARENT_FRAME (f)) + if (!parent_frame + && dpyinfo->root_window == f->output_data.x->parent_desc) /* Try _NET_FRAME_EXTENTS if our parent is the root window. */ prop_cookie = xcb_get_property (xcb_conn, 0, win, dpyinfo->Xatom_net_frame_extents, @@ -470,8 +471,7 @@ x_real_pos_and_offsets (struct frame *f, #endif } - if ((dpyinfo->root_window == f->output_data.x->parent_desc) - && !FRAME_PARENT_FRAME (f)) + if (!parent_frame && dpyinfo->root_window == f->output_data.x->parent_desc) { /* Try _NET_FRAME_EXTENTS if our parent is the root window. */ #ifdef USE_XCB @@ -4125,7 +4125,7 @@ x_focus_frame (struct frame *f, bool noactivate) DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, - doc: /* Internal function called by `color-defined-p', which see. + doc: /* Internal function called by `color-defined-p'. \(Note that the Nextstep version of this function ignores FRAME.) */) (Lisp_Object color, Lisp_Object frame) { @@ -4141,7 +4141,8 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, } DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, - doc: /* Internal function called by `color-values', which see. */) + doc: /* Internal function called by `color-values'. +\(Note that the Nextstep version of this function ignores FRAME.) */) (Lisp_Object color, Lisp_Object frame) { XColor foo; @@ -4156,7 +4157,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, } DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, - doc: /* Internal function called by `display-color-p', which see. */) + doc: /* Internal function called by `display-color-p'. */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4212,6 +4213,7 @@ DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) On \"multi-monitor\" setups this refers to the pixel width for all physical monitors associated with TERMINAL. To get information for @@ -4229,6 +4231,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height, The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) On \"multi-monitor\" setups this refers to the pixel height for all physical monitors associated with TERMINAL. To get information for @@ -4245,7 +4248,8 @@ DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, doc: /* Return the number of bitplanes of the X display TERMINAL. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4258,7 +4262,8 @@ DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, doc: /* Return the number of color cells of the X display TERMINAL. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4282,7 +4287,10 @@ DEFUN ("x-server-max-request-size", Fx_server_max_request_size, doc: /* Return the maximum request size of the X server of display TERMINAL. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. + +On MS Windows, this function just returns 1. +On Nextstep, this function just returns nil. */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4297,8 +4305,8 @@ DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, that operating systems cannot be developed and distributed noncommercially.) The optional argument TERMINAL specifies which display to ask about. -For GNU and Unix systems, this queries the X server software; for -MS-Windows, this queries the OS. +For GNU and Unix systems, this queries the X server software. +For MS Windows and Nextstep the result is hard-coded. TERMINAL should be a terminal object, a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. */) @@ -4318,8 +4326,9 @@ software in use. For GNU and Unix system, the first 2 numbers are the version of the X Protocol used on TERMINAL and the 3rd number is the distributor-specific -release number. For MS-Windows, the 3 numbers report the version and -the build number of the OS. +release number. For MS Windows, the 3 numbers report the OS major and +minor version and build number. For Nextstep, the first 2 numbers are +hard-coded and the 3rd represents the OS version. See also the function `x-server-vendor'. @@ -4339,7 +4348,12 @@ DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, doc: /* Return the number of screens on the X server of display TERMINAL. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. + +On MS Windows, this function just returns 1. +On Nextstep, "screen" is in X terminology, not that of Nextstep. +For the number of physical monitors, use `(length +\(display-monitor-attributes-list TERMINAL))' instead. */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4352,6 +4366,7 @@ DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) On \"multi-monitor\" setups this refers to the height in millimeters for all physical monitors associated with TERMINAL. To get information @@ -4368,6 +4383,7 @@ DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) On \"multi-monitor\" setups this refers to the width in millimeters for all physical monitors associated with TERMINAL. To get information @@ -4382,10 +4398,13 @@ for each physical monitor, use `display-monitor-attributes-list'. */) DEFUN ("x-display-backing-store", Fx_display_backing_store, Sx_display_backing_store, 0, 1, 0, doc: /* Return an indication of whether X display TERMINAL does backing store. -The value may be `always', `when-mapped', or `not-useful'. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. + +The value may be `always', `when-mapped', or `not-useful'. +On Nextstep, the value may be `buffered', `retained', or `non-retained'. +On MS Windows, this returns nothing useful. */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4417,10 +4436,12 @@ DEFUN ("x-display-visual-class", Fx_display_visual_class, doc: /* Return the visual class of the X display TERMINAL. The value is one of the symbols `static-gray', `gray-scale', `static-color', `pseudo-color', `true-color', or `direct-color'. +\(On MS Windows, the second and last result above are not possible.) The optional argument TERMINAL specifies which display to ask about. TERMINAL should a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. +\(On MS Windows, this function does not accept terminal objects.) */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4458,7 +4479,9 @@ DEFUN ("x-display-save-under", Fx_display_save_under, doc: /* Return t if the X display TERMINAL supports the save-under feature. The optional argument TERMINAL specifies which display to ask about. TERMINAL should be a terminal object, a frame or a display name (a string). -If omitted or nil, that stands for the selected frame's display. */) +If omitted or nil, that stands for the selected frame's display. + +On MS Windows, this just returns nil. */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -4612,8 +4635,9 @@ x_make_monitor_attribute_list (struct MonitorInfo *monitors, { struct frame *f = XFRAME (frame); - if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !EQ (frame, tip_frame)) + if (FRAME_X_P (f) + && FRAME_DISPLAY_INFO (f) == dpyinfo + && !FRAME_TOOLTIP_P (f)) { int i = x_get_monitor_for_frame (f, monitors, n_monitors); ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); @@ -4914,12 +4938,9 @@ Internal use only, use `display-monitor-attributes-list' instead. */) { struct frame *f = XFRAME (frame); - if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !(EQ (frame, tip_frame) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - )) + if (FRAME_X_P (f) + && FRAME_DISPLAY_INFO (f) == dpyinfo + && !FRAME_TOOLTIP_P (f)) { GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); @@ -5654,8 +5675,8 @@ DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0, doc: /* Close the connection to TERMINAL's X server. For TERMINAL, specify a terminal object, a frame or a display name (a -string). If TERMINAL is nil, that stands for the selected frame's -terminal. */) +string). If TERMINAL is nil, that stands for the selected frame's terminal. +\(On MS Windows, this function does not accept terminal objects.) */) (Lisp_Object terminal) { struct x_display_info *dpyinfo = check_x_display_info (terminal); @@ -5928,8 +5949,6 @@ FRAME. The number 0 denotes the root window. If DELETE-P is non-nil, delete the property after retrieving it. If VECTOR-RET-P is non-nil, don't return a string but a vector of values. -On MS Windows, this function accepts but ignores those optional arguments. - Value is nil if FRAME hasn't a property with name PROP or if PROP has no value of TYPE (always string in the MS Windows case). */) (Lisp_Object prop, Lisp_Object frame, Lisp_Object type, @@ -6063,22 +6082,27 @@ Otherwise, the return value is a vector with the following fields: ***********************************************************************/ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, - Lisp_Object, int, int, int *, int *); + Lisp_Object, int, int, int *, int *); -/* The frame of a currently visible tooltip. */ +/* The frame of the currently visible tooltip. */ +static Lisp_Object tip_frame; -Lisp_Object tip_frame; +/* The window-system window corresponding to the frame of the + currently visible tooltip. */ +Window tip_window; -/* If non-nil, a timer started that hides the last tooltip when it +/* A timer that hides or deletes the currently visible tooltip when it fires. */ - static Lisp_Object tip_timer; -Window tip_window; -/* If non-nil, a vector of 3 elements containing the last args - with which x-show-tip was called. See there. */ +/* STRING argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_string; + +/* Normalized FRAME argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_frame; -static Lisp_Object last_show_tip_args; +/* PARMS argument of last `x-show-tip' call. */ +static Lisp_Object tip_last_parms; static void @@ -6152,6 +6176,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) f->output_data.x->white_relief.pixel = -1; f->output_data.x->black_relief.pixel = -1; + f->tooltip = true; fset_icon_name (f, Qnil); FRAME_DISPLAY_INFO (f) = dpyinfo; f->output_data.x->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -6416,7 +6441,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) the display in *ROOT_X, and *ROOT_Y. */ static void -compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, int width, int height, int *root_x, int *root_y) +compute_tip_xy (struct frame *f, + Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, + int width, int height, int *root_x, int *root_y) { Lisp_Object left, top, right, bottom; int win_x, win_y; @@ -6513,7 +6540,19 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object } -/* Hide tooltip. Delete its frame if DELETE is true. */ +/** + * x_hide_tip: + * + * Hide currently visible tooltip and cancel its timer. + * + * If GTK+ system tooltips are used, this will try to hide the tooltip + * referenced by the x_output structure of tooltip_last_frame. For + * Emacs tooltips this will try to make tooltip_frame invisible (if + * DELETE is false) or delete tooltip_frame (if DELETE is true). + * + * Return Qt if the tooltip was either deleted or made invisible, Qnil + * otherwise. + */ static Lisp_Object x_hide_tip (bool delete) { @@ -6523,10 +6562,21 @@ x_hide_tip (bool delete) tip_timer = Qnil; } - - if (NILP (tip_frame) - || (!delete && FRAMEP (tip_frame) +#ifdef USE_GTK + /* Any GTK+ system tooltip can be found via the x_output structure of + tip_last_frame, provided that frame is still live. Any Emacs + tooltip is found via the tip_frame variable. Note that the current + value of x_gtk_use_system_tooltips might not be the same as used + for the tooltip we have to hide, see Bug#30399. */ + if ((NILP (tip_last_frame) && NILP (tip_frame)) + || (!x_gtk_use_system_tooltips + && !delete + && FRAMEP (tip_frame) + && FRAME_LIVE_P (XFRAME (tip_frame)) && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + /* Either there's no tooltip to hide or it's an already invisible + Emacs tooltip and we don't want to change its type. Return + quickly. */ return Qnil; else { @@ -6537,61 +6587,117 @@ x_hide_tip (bool delete) specbind (Qinhibit_redisplay, Qt); specbind (Qinhibit_quit, Qt); -#ifdef USE_GTK - { - /* When using system tooltip, tip_frame is the Emacs frame on - which the tip is shown. */ - struct frame *f = XFRAME (tip_frame); + /* Try to hide the GTK+ system tip first. */ + if (FRAMEP (tip_last_frame)) + { + struct frame *f = XFRAME (tip_last_frame); - if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) - { - tip_frame = Qnil; - was_open = Qt; - } - } -#endif + if (FRAME_LIVE_P (f)) + { + if (xg_hide_tooltip (f)) + was_open = Qt; + } + } + + /* Reset tip_last_frame, it will be reassigned when showing the + next GTK+ system tooltip. */ + tip_last_frame = Qnil; + /* Now look whether there's an Emacs tip around. */ if (FRAMEP (tip_frame)) { - if (delete) + struct frame *f = XFRAME (tip_frame); + + if (FRAME_LIVE_P (f)) { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; + if (delete || x_gtk_use_system_tooltips) + { + /* Delete the Emacs tooltip frame when DELETE is true + or we change the tooltip type from an Emacs one to + a GTK+ system one. */ + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (f); + + was_open = Qt; } else - x_make_frame_invisible (XFRAME (tip_frame)); + tip_frame = Qnil; + } + else + tip_frame = Qnil; + + return unbind_to (count, was_open); + } +#else /* not USE_GTK */ + if (NILP (tip_frame) + || (!delete + && FRAMEP (tip_frame) + && FRAME_LIVE_P (XFRAME (tip_frame)) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; + + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); - was_open = Qt; + if (FRAMEP (tip_frame)) + { + struct frame *f = XFRAME (tip_frame); + + if (FRAME_LIVE_P (f)) + { + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (XFRAME (tip_frame)); #ifdef USE_LUCID - /* Bloodcurdling hack alert: The Lucid menu bar widget's - redisplay procedure is not called when a tip frame over - menu items is unmapped. Redisplay the menu manually... */ - { - Widget w; - struct frame *f = SELECTED_FRAME (); - if (FRAME_X_P (f) && FRAME_LIVE_P (f)) + /* Bloodcurdling hack alert: The Lucid menu bar widget's + redisplay procedure is not called when a tip frame over + menu items is unmapped. Redisplay the menu manually... */ { - w = f->output_data.x->menubar_widget; + Widget w; + struct frame *f = SELECTED_FRAME (); - if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) - && w != NULL) + if (FRAME_X_P (f) && FRAME_LIVE_P (f)) { - block_input (); - xlwmenu_redisplay (w); - unblock_input (); + w = f->output_data.x->menubar_widget; + + if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) + && w != NULL) + { + block_input (); + xlwmenu_redisplay (w); + unblock_input (); + } } } - } #endif /* USE_LUCID */ + + was_open = Qt; + } + else + tip_frame = Qnil; } else tip_frame = Qnil; return unbind_to (count, was_open); } +#endif /* USE_GTK */ } + DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, doc: /* Show STRING in a "tooltip" window on frame FRAME. A tooltip window is a small X window displaying a string. @@ -6622,7 +6728,8 @@ with offset DY added (default is -10). A tooltip's maximum size is specified by `x-max-tooltip-size'. Text larger than the specified size is clipped. */) - (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) + (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, + Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { struct frame *f, *tip_f; struct window *w; @@ -6633,8 +6740,7 @@ Text larger than the specified size is clipped. */) int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size; - Lisp_Object tip_buf; + Lisp_Object window, size, tip_buf; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -6643,7 +6749,10 @@ Text larger than the specified size is clipped. */) if (SCHARS (string) == 0) string = make_unibyte_string (" ", 1); + if (NILP (frame)) + frame = selected_frame; f = decode_window_system_frame (frame); + if (NILP (timeout)) timeout = make_number (5); else @@ -6673,36 +6782,27 @@ Text larger than the specified size is clipped. */) { compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); xg_show_tooltip (f, root_x, root_y); - /* This is used in Fx_hide_tip. */ - XSETFRAME (tip_frame, f); + tip_last_frame = frame; } + unblock_input (); if (ok) goto start_timer; } #endif /* USE_GTK */ - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (last_show_tip_args, 0); - Lisp_Object last_frame = AREF (last_show_tip_args, 1); - Lisp_Object last_parms = AREF (last_show_tip_args, 2); - if (FRAME_VISIBLE_P (XFRAME (tip_frame)) - && EQ (frame, last_frame) - && !NILP (Fequal_including_properties (last_string, string)) - && !NILP (Fequal (last_parms, parms))) + && EQ (frame, tip_last_frame) + && !NILP (Fequal_including_properties (tip_last_string, string)) + && !NILP (Fequal (tip_last_parms, parms))) { /* Only DX and DY have changed. */ tip_f = XFRAME (tip_frame); if (!NILP (tip_timer)) { - Lisp_Object timer = tip_timer; - + call1 (Qcancel_timer, tip_timer); tip_timer = Qnil; - call1 (Qcancel_timer, timer); } block_input (); @@ -6714,15 +6814,14 @@ Text larger than the specified size is clipped. */) goto start_timer; } - else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) + else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) { bool delete = false; Lisp_Object tail, elt, parm, last; /* Check if every parameter in PARMS has the same value in - last_parms unless it should be ignored by means of - Vtooltip_reuse_hidden_frame_parameters. This may destruct - last_parms which, however, will be recreated below. */ + tip_last_parms. This may destruct tip_last_parms which, + however, will be recreated below. */ for (tail = parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); @@ -6732,7 +6831,7 @@ Text larger than the specified size is clipped. */) if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) && !EQ (parm, Qbottom)) { - last = Fassq (parm, last_parms); + last = Fassq (parm, tip_last_parms); if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) { /* We lost, delete the old tooltip. */ @@ -6740,17 +6839,18 @@ Text larger than the specified size is clipped. */) break; } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } - /* Now check if every parameter in what is left of last_parms - with a non-nil value has an association in PARMS unless it - should be ignored by means of - Vtooltip_reuse_hidden_frame_parameters. */ - for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) + /* Now check if every parameter in what is left of + tip_last_parms with a non-nil value has an association in + PARMS. */ + for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); parm = Fcar (elt); @@ -6771,9 +6871,9 @@ Text larger than the specified size is clipped. */) else x_hide_tip (true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + tip_last_frame = frame; + tip_last_string = string; + tip_last_parms = parms; if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) { @@ -6960,18 +7060,7 @@ clean_up_file_dialog (void *arg) DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, - doc: /* Read file name, prompting with PROMPT in directory DIR. -Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file -selection box, if specified. If MUSTMATCH is non-nil, the returned file -or directory must exist. - -This function is only defined on NS, MS Windows, and X Windows with the -Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. -Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. -On Windows 7 and later, the file selection dialog "remembers" the last -directory where the user selected a file, and will open that directory -instead of DIR on subsequent invocations of this function with the same -value of DIR as in previous invocations; this is standard Windows behavior. */) + doc: /* SKIP: real doc in USE_GTK definition in xfns.c. */) (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p) { @@ -7140,10 +7229,10 @@ or directory must exist. This function is only defined on NS, MS Windows, and X Windows with the Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored. Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. -On Windows 7 and later, the file selection dialog "remembers" the last +On MS Windows 7 and later, the file selection dialog "remembers" the last directory where the user selected a file, and will open that directory instead of DIR on subsequent invocations of this function with the same -value of DIR as in previous invocations; this is standard Windows behavior. */) +value of DIR as in previous invocations; this is standard MS Windows behavior. */) (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p) { struct frame *f = SELECTED_FRAME (); @@ -7718,9 +7807,9 @@ unless you set it to something else. */); Vx_pixel_size_width_font_regexp, doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. -Since Emacs gets width of a font matching with this regexp from -PIXEL_SIZE field of the name, font finding mechanism gets faster for -such a font. This is especially effective for such large fonts as +Since Emacs gets the width of a font matching this regexp from the +PIXEL_SIZE field of the name, the font-finding mechanism gets faster for +such a font. This is especially effective for large fonts such as Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; @@ -7834,7 +7923,6 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_display_list); defsubr (&Sx_synchronize); defsubr (&Sx_backspace_delete_keys_p); - defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); defsubr (&Sx_double_buffered_p); @@ -7842,9 +7930,12 @@ When using Gtk+ tooltips, the tooltip face is not used. */); staticpro (&tip_timer); tip_frame = Qnil; staticpro (&tip_frame); - - last_show_tip_args = Qnil; - staticpro (&last_show_tip_args); + tip_last_frame = Qnil; + staticpro (&tip_last_frame); + tip_last_string = Qnil; + staticpro (&tip_last_string); + tip_last_parms = Qnil; + staticpro (&tip_last_parms); defsubr (&Sx_uses_old_gtk_dialog); #if defined (USE_MOTIF) || defined (USE_GTK) diff --git a/src/xmenu.c b/src/xmenu.c index e7ef31ac564..a5865a6ec27 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -3,6 +3,10 @@ Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2018 Free Software Foundation, Inc. +Author: Jon Arnold + Roman Budzianowski + Robert Krawitz + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify @@ -20,9 +24,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ /* X pop-up deck-of-cards menu facility for GNU Emacs. * - * Written by Jon Arnold and Roman Budzianowski - * Mods and rewrite by Robert Krawitz - * */ /* Modified by Fred Pierresteguy on December 93 @@ -278,12 +279,7 @@ popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, } DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i", - doc: /* Start key navigation of the menu bar in FRAME. -This initially opens the first menu bar item and you can then navigate with the -arrow keys, select a menu entry with the return key or cancel with the -escape key. If FRAME has no menu bar this function does nothing. - -If FRAME is nil or not given, use the selected frame. */) + doc: /* SKIP: real doc in USE_GTK definition in xmenu.c. */) (Lisp_Object frame) { XEvent ev; @@ -2376,7 +2372,8 @@ popup_activated (void) /* The following is used by delayed window autoselection. */ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, - doc: /* Return t if a menu or popup dialog is active. */) + doc: /* Return t if a menu or popup dialog is active. +\(On MS Windows, this refers to the selected frame.) */) (void) { return (popup_activated ()) ? Qt : Qnil; diff --git a/src/xml.c b/src/xml.c index 8bf5a3d122b..42059d77131 100644 --- a/src/xml.c +++ b/src/xml.c @@ -18,15 +18,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> +#include "lisp.h" +#include "buffer.h" + #ifdef HAVE_LIBXML2 #include <libxml/tree.h> #include <libxml/parser.h> #include <libxml/HTMLparser.h> -#include "lisp.h" -#include "buffer.h" - #ifdef WINDOWSNT @@ -291,16 +291,43 @@ If DISCARD-COMMENTS is non-nil, all HTML comments are discarded. */) return parse_region (start, end, base_url, discard_comments, false); return Qnil; } +#endif /* HAVE_LIBXML2 */ + +DEFUN ("libxml-available-p", Flibxml_available_p, Slibxml_available_p, 0, 0, 0, + doc: /* Return t if libxml2 support is available in this instance of Emacs.*/) + (void) +{ +#ifdef HAVE_LIBXML2 +# ifdef WINDOWSNT + Lisp_Object found = Fassq (Qlibxml2, Vlibrary_cache); + if (CONSP (found)) + return XCDR (found); + else + { + Lisp_Object status; + status = init_libxml2_functions () ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qlibxml2, status), Vlibrary_cache); + return status; + } +# else + return Qt; +# endif /* WINDOWSNT */ +#else + return Qnil; +#endif /* HAVE_LIBXML2 */ +} + /*********************************************************************** Initialization ***********************************************************************/ void syms_of_xml (void) { +#ifdef HAVE_LIBXML2 defsubr (&Slibxml_parse_html_region); defsubr (&Slibxml_parse_xml_region); +#endif + defsubr (&Slibxml_available_p); } - -#endif /* HAVE_LIBXML2 */ diff --git a/src/xterm.c b/src/xterm.c index c5163aa990a..db5ea4ac55e 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -996,12 +996,7 @@ static void x_update_begin (struct frame *f) { #ifdef USE_CAIRO - if (! NILP (tip_frame) && XFRAME (tip_frame) == f - && ! FRAME_VISIBLE_P (f) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (FRAME_TOOLTIP_P (f) && !FRAME_VISIBLE_P (f)) return; if (! FRAME_CR_SURFACE (f)) @@ -3712,33 +3707,53 @@ x_draw_glyph_string (struct glyph_string *s) else { struct font *font = font_for_underline_metrics (s); + unsigned long minimum_offset; + bool underline_at_descent_line; + bool use_underline_position_properties; + Lisp_Object val + = buffer_local_value (Qunderline_minimum_offset, + s->w->contents); + if (INTEGERP (val)) + minimum_offset = XFASTINT (val); + else + minimum_offset = 1; + val = buffer_local_value (Qx_underline_at_descent_line, + s->w->contents); + underline_at_descent_line + = !(NILP (val) || EQ (val, Qunbound)); + val + = buffer_local_value (Qx_use_underline_position_properties, + s->w->contents); + use_underline_position_properties + = !(NILP (val) || EQ (val, Qunbound)); /* Get the underline thickness. Default is 1 pixel. */ if (font && font->underline_thickness > 0) thickness = font->underline_thickness; else thickness = 1; - if (x_underline_at_descent_line) + if (underline_at_descent_line) position = (s->height - thickness) - (s->ybase - s->y); else { - /* Get the underline position. This is the recommended - vertical offset in pixels from the baseline to the top of - the underline. This is a signed value according to the + /* Get the underline position. This is the + recommended vertical offset in pixels from + the baseline to the top of the underline. + This is a signed value according to the specs, and its default is ROUND ((maximum descent) / 2), with ROUND(x) = floor (x + 0.5) */ - if (x_use_underline_position_properties + if (use_underline_position_properties && font && font->underline_position >= 0) position = font->underline_position; else if (font) position = (font->descent + 1) / 2; else - position = underline_minimum_offset; + position = minimum_offset; } - position = max (position, underline_minimum_offset); + position = max (position, minimum_offset); } /* Check the sanity of thickness and position. We should avoid drawing underline out of the current line area. */ @@ -8091,7 +8106,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Redo the mouse-highlight after the tooltip has gone. */ if (event->xunmap.window == tip_window) { - tip_window = 0; + tip_window = None; x_redo_mouse_highlight (dpyinfo); } @@ -8733,7 +8748,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_X_TOOLKIT /* Tip frames are pure X window, set size for them. */ - if (! NILP (tip_frame) && XFRAME (tip_frame) == f) + if (FRAME_TOOLTIP_P (f)) { if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) @@ -9971,11 +9986,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) /* Don't change the size of a tip frame; there's no point in doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ - if (NILP (tip_frame) || XFRAME (tip_frame) != f -#ifdef USE_GTK - || NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (!FRAME_TOOLTIP_P (f)) { adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, @@ -11209,7 +11220,7 @@ x_set_window_size (struct frame *f, bool change_gravity, /* The following breaks our calculations. If it's really needed, think of something else. */ #if false - if (NILP (tip_frame) || XFRAME (tip_frame) != f) + if (!FRAME_TOOLTIP_P (f)) { int text_width, text_height; @@ -13251,11 +13262,12 @@ syms_of_xterm (void) x_use_underline_position_properties, doc: /* Non-nil means make use of UNDERLINE_POSITION font properties. A value of nil means ignore them. If you encounter fonts with bogus -UNDERLINE_POSITION font properties, for example 7x13 on XFree prior -to 4.1, set this to nil. You can also use `underline-minimum-offset' -to override the font's UNDERLINE_POSITION for small font display -sizes. */); +UNDERLINE_POSITION font properties, set this to nil. You can also use +`underline-minimum-offset' to override the font's UNDERLINE_POSITION for +small font display sizes. */); x_use_underline_position_properties = true; + DEFSYM (Qx_use_underline_position_properties, + "x-use-underline-position-properties"); DEFVAR_BOOL ("x-underline-at-descent-line", x_underline_at_descent_line, @@ -13266,6 +13278,7 @@ A value of nil means to draw the underline according to the value of the variable `x-use-underline-position-properties', which is usually at the baseline level. The default value is nil. */); x_underline_at_descent_line = false; + DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); DEFVAR_BOOL ("x-mouse-click-focus-ignore-position", x_mouse_click_focus_ignore_position, diff --git a/src/xterm.h b/src/xterm.h index f73dd0e25ab..1849a5c9535 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -503,6 +503,8 @@ extern bool x_display_ok (const char *); extern void select_visual (struct x_display_info *); +extern Window tip_window; + /* Each X frame object points to its own struct x_output object in the output_data.x field. The x_output structure contains the information that is specific to X windows. */ diff --git a/src/xwidget.c b/src/xwidget.c index 530d1af707a..95fa5f19c40 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -392,8 +392,7 @@ webkit_javascript_finished_cb (GObject *webview, /* FIXME: This might lead to disaster if LISP_CALLBACK's object was garbage collected before now. See the FIXME in Fxwidget_webkit_execute_script. */ - store_xwidget_js_callback_event (xw, XIL ((intptr_t) lisp_callback), - lisp_value); + store_xwidget_js_callback_event (xw, XPL (lisp_callback), lisp_value); } @@ -585,22 +584,20 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) xwidget on screen. Moving and clipping is done here. Also view initialization. */ struct xwidget *xww = s->xwidget; - struct xwidget_view *xv; + struct xwidget_view *xv = xwidget_view_lookup (xww, s->w); int clip_right; int clip_bottom; int clip_top; int clip_left; - /* FIXME: The result of this call is discarded. - What if the lookup fails? */ - xwidget_view_lookup (xww, s->w); - int x = s->x; int y = s->y + (s->height / 2) - (xww->height / 2); /* Do initialization here in the display loop because there is no - other time to know things like window placement etc. */ - xv = xwidget_init_view (xww, s, x, y); + other time to know things like window placement etc. Do not + create a new view if we have found one that is usable. */ + if (!xv) + xv = xwidget_init_view (xww, s, x, y); int text_area_x, text_area_y, text_area_width, text_area_height; @@ -725,7 +722,7 @@ argument procedure FUN.*/) /* FIXME: This hack might lead to disaster if FUN is garbage collected before store_xwidget_js_callback_event makes it visible to Lisp again. See the FIXME in webkit_javascript_finished_cb. */ - gpointer callback_arg = (gpointer) (intptr_t) XLI (fun); + gpointer callback_arg = XLP (fun); /* JavaScript execution happens asynchronously. If an elisp callback function is provided we pass it to the C callback |