summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gdbinit33
-rw-r--r--src/Makefile.in34
-rw-r--r--src/alloc.c150
-rw-r--r--src/bidi.c10
-rw-r--r--src/buffer.c4
-rw-r--r--src/bytecode.c15
-rw-r--r--src/callint.c300
-rw-r--r--src/character.c26
-rw-r--r--src/character.h2
-rw-r--r--src/cmds.c5
-rw-r--r--src/coding.c31
-rw-r--r--src/coding.h27
-rw-r--r--src/data.c22
-rw-r--r--src/decompress.c29
-rw-r--r--src/dispextern.h19
-rw-r--r--src/dispnew.c11
-rw-r--r--src/doc.c42
-rw-r--r--src/doprnt.c2
-rw-r--r--src/dosfns.c6
-rw-r--r--src/editfns.c141
-rw-r--r--src/emacs-module.c42
-rw-r--r--src/emacs.c20
-rw-r--r--src/eval.c73
-rw-r--r--src/fileio.c113
-rw-r--r--src/fns.c3
-rw-r--r--src/frame.c66
-rw-r--r--src/frame.h7
-rw-r--r--src/fringe.c5
-rw-r--r--src/gmalloc.c16
-rw-r--r--src/gtkutil.c39
-rw-r--r--src/json.c920
-rw-r--r--src/keyboard.c386
-rw-r--r--src/keyboard.h1
-rw-r--r--src/kqueue.c2
-rw-r--r--src/lastfile.c3
-rw-r--r--src/lisp.h231
-rw-r--r--src/lread.c149
-rw-r--r--src/macfont.m2
-rw-r--r--src/menu.c96
-rw-r--r--src/menu.h1
-rw-r--r--src/minibuf.c14
-rw-r--r--src/msdos.c2
-rw-r--r--src/nsfns.m286
-rw-r--r--src/nsimage.m116
-rw-r--r--src/nsmenu.m12
-rw-r--r--src/nsselect.m8
-rw-r--r--src/nsterm.h12
-rw-r--r--src/nsterm.m477
-rw-r--r--src/print.c62
-rw-r--r--src/process.c136
-rw-r--r--src/process.h2
-rw-r--r--src/ptr-bounds.h79
-rw-r--r--src/regex.c37
-rw-r--r--src/regex.h9
-rw-r--r--src/sound.c5
-rw-r--r--src/syntax.c26
-rw-r--r--src/sysdep.c29
-rw-r--r--src/syssignal.h1
-rw-r--r--src/systhread.c20
-rw-r--r--src/systhread.h1
-rw-r--r--src/term.c14
-rw-r--r--src/thread.c8
-rw-r--r--src/thread.h1
-rw-r--r--src/tparam.h3
-rw-r--r--src/w16select.c39
-rw-r--r--src/w32cygwinx.c140
-rw-r--r--src/w32fns.c513
-rw-r--r--src/w32menu.c2
-rw-r--r--src/w32notify.c9
-rw-r--r--src/w32reg.c8
-rw-r--r--src/w32select.c42
-rw-r--r--src/w32term.c69
-rw-r--r--src/w32term.h2
-rw-r--r--src/window.h9
-rw-r--r--src/xdisp.c233
-rw-r--r--src/xfaces.c8
-rw-r--r--src/xfns.c355
-rw-r--r--src/xmenu.c17
-rw-r--r--src/xml.c37
-rw-r--r--src/xterm.c63
-rw-r--r--src/xterm.h2
-rw-r--r--src/xwidget.c17
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