summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuuki Harano <masm+github@masm11.me>2021-04-18 15:30:29 +0900
committerYuuki Harano <masm+github@masm11.me>2021-04-18 15:30:29 +0900
commitde46c7796e635faf8647a7c6a5ae34fda9adae3b (patch)
tree1a2c5f85416a642300ca217b3d85ff1be5d9f35e /src
parentfb5f3e694b0f6e2bccfc2124555c986fdc409cd0 (diff)
parent5c07cd0f156217db268ccb9fa64566fb429c4257 (diff)
downloademacs-de46c7796e635faf8647a7c6a5ae34fda9adae3b.tar.gz
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs into feature/pgtk
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c2
-rw-r--r--src/character.c56
-rw-r--r--src/character.h4
-rw-r--r--src/editfns.c9
-rw-r--r--src/emacs.c207
-rw-r--r--src/eval.c34
-rw-r--r--src/frame.c1
-rw-r--r--src/image.c58
-rw-r--r--src/minibuf.c38
-rw-r--r--src/w32term.c20
-rw-r--r--src/window.c35
-rw-r--r--src/window.h1
-rw-r--r--src/xdisp.c58
-rw-r--r--src/xselect.c21
14 files changed, 426 insertions, 118 deletions
diff --git a/src/alloc.c b/src/alloc.c
index ab1e96e0bc6..efcf0a52f34 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6251,7 +6251,7 @@ For further details, see Info node `(elisp)Garbage Collection'. */)
}
DEFUN ("garbage-collect-maybe", Fgarbage_collect_maybe,
-Sgarbage_collect_maybe, 1, 1, "",
+Sgarbage_collect_maybe, 1, 1, 0,
doc: /* Call `garbage-collect' if enough allocation happened.
FACTOR determines what "enough" means here:
If FACTOR is a positive number N, it means to run GC if more than
diff --git a/src/character.c b/src/character.c
index a599a0355f4..41abb83a48b 100644
--- a/src/character.c
+++ b/src/character.c
@@ -321,28 +321,32 @@ strwidth (const char *str, ptrdiff_t len)
return c_string_width ((const unsigned char *) str, len, -1, NULL, NULL);
}
-/* Return width of Lisp string STRING when displayed in the current
- buffer. The width is measured by how many columns it occupies on
- the screen while paying attention to compositions. If PRECISION >
- 0, return the width of longest substring that doesn't exceed
- PRECISION, and set number of characters and bytes of the substring
- in *NCHARS and *NBYTES respectively. */
+/* Return width of a (substring of a) Lisp string STRING when
+ displayed in the current buffer. The width is measured by how many
+ columns it occupies on the screen while paying attention to
+ compositions. If PRECISION > 0, return the width of longest
+ substring that doesn't exceed PRECISION, and set number of
+ characters and bytes of the substring in *NCHARS and *NBYTES
+ respectively. FROM and TO are zero-based character indices
+ that define the substring of STRING to consider. */
ptrdiff_t
-lisp_string_width (Lisp_Object string, ptrdiff_t precision,
- ptrdiff_t *nchars, ptrdiff_t *nbytes)
+lisp_string_width (Lisp_Object string, ptrdiff_t from, ptrdiff_t to,
+ ptrdiff_t precision, ptrdiff_t *nchars, ptrdiff_t *nbytes)
{
- ptrdiff_t len = SCHARS (string);
/* This set multibyte to 0 even if STRING is multibyte when it
contains only ascii and eight-bit-graphic, but that's
intentional. */
- bool multibyte = len < SBYTES (string);
+ bool multibyte = SCHARS (string) < SBYTES (string);
unsigned char *str = SDATA (string);
- ptrdiff_t i = 0, i_byte = 0;
+ ptrdiff_t i = from, i_byte = from ? string_char_to_byte (string, from) : 0;
+ ptrdiff_t from_byte = i_byte;
ptrdiff_t width = 0;
struct Lisp_Char_Table *dp = buffer_display_table ();
- while (i < len)
+ eassert (precision <= 0 || (nchars && nbytes));
+
+ while (i < to)
{
ptrdiff_t chars, bytes, thiswidth;
Lisp_Object val;
@@ -375,8 +379,8 @@ lisp_string_width (Lisp_Object string, ptrdiff_t precision,
if (0 < precision && precision - width < thiswidth)
{
- *nchars = i;
- *nbytes = i_byte;
+ *nchars = i - from;
+ *nbytes = i_byte - from_byte;
return width;
}
if (INT_ADD_WRAPV (thiswidth, width, &width))
@@ -387,27 +391,37 @@ lisp_string_width (Lisp_Object string, ptrdiff_t precision,
if (precision > 0)
{
- *nchars = i;
- *nbytes = i_byte;
+ *nchars = i - from;
+ *nbytes = i_byte - from_byte;
}
return width;
}
-DEFUN ("string-width", Fstring_width, Sstring_width, 1, 1, 0,
+DEFUN ("string-width", Fstring_width, Sstring_width, 1, 3, 0,
doc: /* Return width of STRING when displayed in the current buffer.
Width is measured by how many columns it occupies on the screen.
+Optional arguments FROM and TO specify the substring of STRING to
+consider, and are interpreted as in `substring'.
+
When calculating width of a multibyte character in STRING,
only the base leading-code is considered; the validity of
the following bytes is not checked. Tabs in STRING are always
-taken to occupy `tab-width' columns.
-usage: (string-width STRING) */)
- (Lisp_Object str)
+taken to occupy `tab-width' columns. The effect of faces and fonts
+used for non-Latin and other unusual characters (such as emoji) is
+ignored as well, as are display properties and invisible text.
+For these reasons, the results are not generally reliable;
+for accurate dimensions of text as it will be displayed,
+use `window-text-pixel-size' instead.
+usage: (string-width STRING &optional FROM TO) */)
+ (Lisp_Object str, Lisp_Object from, Lisp_Object to)
{
Lisp_Object val;
+ ptrdiff_t ifrom, ito;
CHECK_STRING (str);
- XSETFASTINT (val, lisp_string_width (str, -1, NULL, NULL));
+ validate_subarray (str, from, to, SCHARS (str), &ifrom, &ito);
+ XSETFASTINT (val, lisp_string_width (str, ifrom, ito, -1, NULL, NULL));
return val;
}
diff --git a/src/character.h b/src/character.h
index cbf43097ae2..d19e1e2604c 100644
--- a/src/character.h
+++ b/src/character.h
@@ -572,8 +572,8 @@ extern ptrdiff_t str_to_unibyte (const unsigned char *, unsigned char *,
extern ptrdiff_t strwidth (const char *, ptrdiff_t);
extern ptrdiff_t c_string_width (const unsigned char *, ptrdiff_t, int,
ptrdiff_t *, ptrdiff_t *);
-extern ptrdiff_t lisp_string_width (Lisp_Object, ptrdiff_t,
- ptrdiff_t *, ptrdiff_t *);
+extern ptrdiff_t lisp_string_width (Lisp_Object, ptrdiff_t, ptrdiff_t,
+ ptrdiff_t, ptrdiff_t *, ptrdiff_t *);
extern Lisp_Object Vchar_unify_table;
extern Lisp_Object string_escape_byte8 (Lisp_Object);
diff --git a/src/editfns.c b/src/editfns.c
index 87e743afc31..bc73c1e2c5b 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3386,12 +3386,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
else
{
ptrdiff_t nch, nby;
- width = lisp_string_width (arg, prec, &nch, &nby);
+ nchars_string = SCHARS (arg);
+ width = lisp_string_width (arg, 0, nchars_string, prec,
+ &nch, &nby);
if (prec < 0)
- {
- nchars_string = SCHARS (arg);
- nbytes = SBYTES (arg);
- }
+ nbytes = SBYTES (arg);
else
{
nchars_string = nch;
diff --git a/src/emacs.c b/src/emacs.c
index 5995410037d..9a83a087dee 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -61,6 +61,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
# include <sys/socket.h>
#endif
+#if defined HAVE_LINUX_SECCOMP_H && defined HAVE_LINUX_FILTER_H \
+ && HAVE_DECL_SECCOMP_SET_MODE_FILTER \
+ && HAVE_DECL_SECCOMP_FILTER_FLAG_TSYNC
+# define SECCOMP_USABLE 1
+#else
+# define SECCOMP_USABLE 0
+#endif
+
+#if SECCOMP_USABLE
+# include <linux/seccomp.h>
+# include <linux/filter.h>
+# include <sys/prctl.h>
+# include <sys/syscall.h>
+#endif
+
#ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
@@ -241,6 +256,11 @@ Initialization options:\n\
--dump-file FILE read dumped state from FILE\n\
",
#endif
+#if SECCOMP_USABLE
+ "\
+--sandbox=FILE read Seccomp BPF filter from FILE\n\
+"
+#endif
"\
--no-build-details do not add build details such as time stamps\n\
--no-desktop do not load a saved desktop\n\
@@ -938,6 +958,181 @@ load_pdump (int argc, char **argv)
}
#endif /* HAVE_PDUMPER */
+#if SECCOMP_USABLE
+
+/* Wrapper function for the `seccomp' system call on GNU/Linux. This
+ system call usually doesn't have a wrapper function. See the
+ manual page of `seccomp' for the signature. */
+
+static int
+emacs_seccomp (unsigned int operation, unsigned int flags, void *args)
+{
+#ifdef SYS_seccomp
+ return syscall (SYS_seccomp, operation, flags, args);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/* Read SIZE bytes into BUFFER. Return the number of bytes read, or
+ -1 if reading failed altogether. */
+
+static ptrdiff_t
+read_full (int fd, void *buffer, ptrdiff_t size)
+{
+ eassert (0 <= fd);
+ eassert (buffer != NULL);
+ eassert (0 <= size);
+ enum
+ {
+ /* See MAX_RW_COUNT in sysdep.c. */
+#ifdef MAX_RW_COUNT
+ max_size = MAX_RW_COUNT
+#else
+ max_size = INT_MAX >> 18 << 18
+#endif
+ };
+ if (PTRDIFF_MAX < size || max_size < size)
+ {
+ errno = EFBIG;
+ return -1;
+ }
+ char *ptr = buffer;
+ ptrdiff_t read = 0;
+ while (size != 0)
+ {
+ ptrdiff_t n = emacs_read (fd, ptr, size);
+ if (n < 0)
+ return -1;
+ if (n == 0)
+ break; /* Avoid infinite loop on encountering EOF. */
+ eassert (n <= size);
+ size -= n;
+ ptr += n;
+ read += n;
+ }
+ return read;
+}
+
+/* Attempt to load Secure Computing filters from FILE. Return false
+ if that doesn't work for some reason. */
+
+static bool
+load_seccomp (const char *file)
+{
+ bool success = false;
+ void *buffer = NULL;
+ int fd
+ = emacs_open_noquit (file, O_RDONLY | O_CLOEXEC | O_BINARY, 0);
+ if (fd < 0)
+ {
+ emacs_perror ("open");
+ goto out;
+ }
+ struct stat stat;
+ if (fstat (fd, &stat) != 0)
+ {
+ emacs_perror ("fstat");
+ goto out;
+ }
+ if (! S_ISREG (stat.st_mode))
+ {
+ fprintf (stderr, "seccomp file %s is not regular\n", file);
+ goto out;
+ }
+ struct sock_fprog program;
+ if (stat.st_size <= 0 || SIZE_MAX <= stat.st_size
+ || PTRDIFF_MAX <= stat.st_size
+ || stat.st_size % sizeof *program.filter != 0)
+ {
+ fprintf (stderr, "seccomp filter %s has invalid size %ld\n",
+ file, (long) stat.st_size);
+ goto out;
+ }
+ size_t size = stat.st_size;
+ size_t count = size / sizeof *program.filter;
+ eassert (0 < count && count < SIZE_MAX);
+ if (USHRT_MAX < count)
+ {
+ fprintf (stderr, "seccomp filter %s is too big\n", file);
+ goto out;
+ }
+ /* Try reading one more byte to detect file size changes. */
+ buffer = malloc (size + 1);
+ if (buffer == NULL)
+ {
+ emacs_perror ("malloc");
+ goto out;
+ }
+ ptrdiff_t read = read_full (fd, buffer, size + 1);
+ if (read < 0)
+ {
+ emacs_perror ("read");
+ goto out;
+ }
+ eassert (read <= SIZE_MAX);
+ if (read != size)
+ {
+ fprintf (stderr,
+ "seccomp filter %s changed size while reading\n",
+ file);
+ goto out;
+ }
+ if (emacs_close (fd) != 0)
+ emacs_perror ("close"); /* not a fatal error */
+ fd = -1;
+ program.len = count;
+ program.filter = buffer;
+
+ /* See man page of `seccomp' why this is necessary. Note that we
+ intentionally don't check the return value: a parent process
+ might have made this call before, in which case it would fail;
+ or, if enabling privilege-restricting mode fails, the `seccomp'
+ syscall will fail anyway. */
+ prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ /* Install the filter. Make sure that potential other threads can't
+ escape it. */
+ if (emacs_seccomp (SECCOMP_SET_MODE_FILTER,
+ SECCOMP_FILTER_FLAG_TSYNC, &program)
+ != 0)
+ {
+ emacs_perror ("seccomp");
+ goto out;
+ }
+ success = true;
+
+ out:
+ if (0 <= fd)
+ emacs_close (fd);
+ free (buffer);
+ return success;
+}
+
+/* Load Secure Computing filter from file specified with the --seccomp
+ option. Exit if that fails. */
+
+static void
+maybe_load_seccomp (int argc, char **argv)
+{
+ int skip_args = 0;
+ char *file = NULL;
+ while (skip_args < argc - 1)
+ {
+ if (argmatch (argv, argc, "-seccomp", "--seccomp", 9, &file,
+ &skip_args)
+ || argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args))
+ break;
+ ++skip_args;
+ }
+ if (file == NULL)
+ return;
+ if (! load_seccomp (file))
+ fatal ("cannot enable seccomp filter from %s", file);
+}
+
+#endif /* SECCOMP_USABLE */
+
int
main (int argc, char **argv)
{
@@ -945,6 +1140,13 @@ main (int argc, char **argv)
for pointers. */
void *stack_bottom_variable;
+ /* First, check whether we should apply a seccomp filter. This
+ should come at the very beginning to allow the filter to protect
+ the initialization phase. */
+#if SECCOMP_USABLE
+ maybe_load_seccomp (argc, argv);
+#endif
+
bool no_loadup = false;
char *junk = 0;
char *dname_arg = 0;
@@ -2148,12 +2350,15 @@ static const struct standard_args standard_args[] =
{ "-color", "--color", 5, 0},
{ "-no-splash", "--no-splash", 3, 0 },
{ "-no-desktop", "--no-desktop", 3, 0 },
- /* The following two must be just above the file-name args, to get
+ /* The following three must be just above the file-name args, to get
them out of our way, but without mixing them with file names. */
{ "-temacs", "--temacs", 1, 1 },
#ifdef HAVE_PDUMPER
{ "-dump-file", "--dump-file", 1, 1 },
#endif
+#if SECCOMP_USABLE
+ { "-seccomp", "--seccomp", 1, 1 },
+#endif
#ifdef HAVE_NS
{ "-NSAutoLaunch", 0, 5, 1 },
{ "-NXAutoLaunch", 0, 5, 1 },
diff --git a/src/eval.c b/src/eval.c
index ddaa8edd817..fd93f5b9e1f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1301,7 +1301,7 @@ DEFUN ("condition-case", Fcondition_case, Scondition_case, 2, UNEVALLED, 0,
doc: /* Regain control when an error is signaled.
Executes BODYFORM and returns its value if no error happens.
Each element of HANDLERS looks like (CONDITION-NAME BODY...)
-where the BODY is made of Lisp expressions.
+or (:success BODY...), where the BODY is made of Lisp expressions.
A handler is applicable to an error if CONDITION-NAME is one of the
error's condition names. Handlers may also apply when non-error
@@ -1323,6 +1323,10 @@ with VAR bound to (ERROR-SYMBOL . SIGNAL-DATA) from the error.
Then the value of the last BODY form is returned from the `condition-case'
expression.
+The special handler (:success BODY...) is invoked if BODYFORM terminated
+without signalling an error. BODY is then evaluated with VAR bound to
+the value returned by BODYFORM.
+
See also the function `signal' for more info.
usage: (condition-case VAR BODYFORM &rest HANDLERS) */)
(Lisp_Object args)
@@ -1346,16 +1350,21 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
CHECK_SYMBOL (var);
+ Lisp_Object success_handler = Qnil;
+
for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object tem = XCAR (tail);
- clausenb++;
if (! (NILP (tem)
|| (CONSP (tem)
&& (SYMBOLP (XCAR (tem))
|| CONSP (XCAR (tem))))))
error ("Invalid condition handler: %s",
SDATA (Fprin1_to_string (tem, Qt)));
+ if (EQ (XCAR (tem), QCsuccess))
+ success_handler = XCDR (tem);
+ else
+ clausenb++;
}
/* The first clause is the one that should be checked first, so it
@@ -1369,7 +1378,8 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
Lisp_Object volatile *clauses = alloca (clausenb * sizeof *clauses);
clauses += clausenb;
for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail))
- *--clauses = XCAR (tail);
+ if (!EQ (XCAR (XCAR (tail)), QCsuccess))
+ *--clauses = XCAR (tail);
for (ptrdiff_t i = 0; i < clausenb; i++)
{
Lisp_Object clause = clauses[i];
@@ -1409,6 +1419,23 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
Lisp_Object result = eval_sub (bodyform);
handlerlist = oldhandlerlist;
+ if (!NILP (success_handler))
+ {
+ if (NILP (var))
+ return Fprogn (success_handler);
+
+ Lisp_Object handler_var = var;
+ if (!NILP (Vinternal_interpreter_environment))
+ {
+ result = Fcons (Fcons (var, result),
+ Vinternal_interpreter_environment);
+ handler_var = Qinternal_interpreter_environment;
+ }
+
+ ptrdiff_t count = SPECPDL_INDEX ();
+ specbind (handler_var, result);
+ return unbind_to (count, Fprogn (success_handler));
+ }
return result;
}
@@ -4381,6 +4408,7 @@ alist of active lexical bindings. */);
defsubr (&Sthrow);
defsubr (&Sunwind_protect);
defsubr (&Scondition_case);
+ DEFSYM (QCsuccess, ":success");
defsubr (&Ssignal);
defsubr (&Scommandp);
defsubr (&Sautoload);
diff --git a/src/frame.c b/src/frame.c
index 17e1b3f7261..a20c53699ac 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -3750,6 +3750,7 @@ window state change flag is reset. */)
DEFUN ("frame-scale-factor", Fframe_scale_factor, Sframe_scale_factor,
0, 1, 0,
doc: /* Return FRAMEs scale factor.
+If FRAME is omitted or nil, the selected frame is used.
The scale factor is the amount by which a logical pixel size must be
multiplied to find the real number of pixels. */)
(Lisp_Object frame)
diff --git a/src/image.c b/src/image.c
index 107670d72c1..96084068dcd 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2109,46 +2109,68 @@ scale_image_size (int size, size_t divisor, size_t multiplier)
return INT_MAX;
}
+/* Return a size, in pixels, from the value specified by SYMBOL, which
+ may be an integer or a pair of the form (VALUE . 'em) where VALUE
+ is a float that is multiplied by the font size to get the final
+ dimension.
+
+ If the value doesn't exist in the image spec, or is invalid, return
+ -1.
+*/
+static int
+image_get_dimension (struct image *img, Lisp_Object symbol)
+{
+ Lisp_Object value = image_spec_value (img->spec, symbol, NULL);
+
+ if (FIXNATP (value))
+ return min (XFIXNAT (value), INT_MAX);
+ if (CONSP (value) && NUMBERP (CAR (value)) && EQ (Qem, CDR (value)))
+ return min (img->face_font_size * XFLOATINT (CAR (value)), INT_MAX);
+
+ return -1;
+}
+
/* Compute the desired size of an image with native size WIDTH x HEIGHT.
Use SPEC to deduce the size. Store the desired size into
*D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
static void
compute_image_size (size_t width, size_t height,
- Lisp_Object spec,
+ struct image *img,
int *d_width, int *d_height)
{
Lisp_Object value;
+ int int_value;
int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
double scale = 1;
- value = image_spec_value (spec, QCscale, NULL);
+ value = image_spec_value (img->spec, QCscale, NULL);
if (NUMBERP (value))
scale = XFLOATINT (value);
- value = image_spec_value (spec, QCmax_width, NULL);
- if (FIXNATP (value))
- max_width = min (XFIXNAT (value), INT_MAX);
+ int_value = image_get_dimension (img, QCmax_width);
+ if (int_value >= 0)
+ max_width = int_value;
- value = image_spec_value (spec, QCmax_height, NULL);
- if (FIXNATP (value))
- max_height = min (XFIXNAT (value), INT_MAX);
+ int_value = image_get_dimension (img, QCmax_height);
+ if (int_value >= 0)
+ max_height = int_value;
/* If width and/or height is set in the display spec assume we want
to scale to those values. If either h or w is unspecified, the
unspecified should be calculated from the specified to preserve
aspect ratio. */
- value = image_spec_value (spec, QCwidth, NULL);
- if (FIXNATP (value))
+ int_value = image_get_dimension (img, QCwidth);
+ if (int_value >= 0)
{
- desired_width = min (XFIXNAT (value) * scale, INT_MAX);
+ desired_width = int_value * scale;
/* :width overrides :max-width. */
max_width = -1;
}
- value = image_spec_value (spec, QCheight, NULL);
- if (FIXNATP (value))
+ int_value = image_get_dimension (img, QCheight);
+ if (int_value >= 0)
{
- desired_height = min (XFIXNAT (value) * scale, INT_MAX);
+ desired_height = int_value * scale;
/* :height overrides :max-height. */
max_height = -1;
}
@@ -2339,7 +2361,7 @@ image_set_transform (struct frame *f, struct image *img)
}
else
#endif
- compute_image_size (img->width, img->height, img->spec, &width, &height);
+ compute_image_size (img->width, img->height, img, &width, &height);
/* Determine rotation. */
double rotation = 0.0;
@@ -9345,7 +9367,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
#ifndef DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE
compute_image_size (MagickGetImageWidth (image_wand),
MagickGetImageHeight (image_wand),
- img->spec, &desired_width, &desired_height);
+ img, &desired_width, &desired_height);
#else
desired_width = desired_height = -1;
#endif
@@ -10208,7 +10230,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
viewbox_height = dimension_data.height;
}
- compute_image_size (viewbox_width, viewbox_height, img->spec,
+ compute_image_size (viewbox_width, viewbox_height, img,
&width, &height);
width *= FRAME_SCALE_FACTOR (f);
@@ -10917,6 +10939,8 @@ non-numeric, there is no explicit limit on the size of images. */);
DEFSYM (QCmax_width, ":max-width");
DEFSYM (QCmax_height, ":max-height");
+ DEFSYM (Qem, "em");
+
#ifdef HAVE_NATIVE_TRANSFORMS
DEFSYM (Qscale, "scale");
DEFSYM (Qrotate, "rotate");
diff --git a/src/minibuf.c b/src/minibuf.c
index c9831fd50f4..a3c1b99bf32 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -112,13 +112,15 @@ choose_minibuf_frame (void)
{
if (FRAMEP (selected_frame)
&& FRAME_LIVE_P (XFRAME (selected_frame))
+ && WINDOW_LIVE_P (XFRAME (selected_frame)->minibuffer_window)
&& !EQ (minibuf_window, XFRAME (selected_frame)->minibuffer_window))
{
struct frame *sf = XFRAME (selected_frame);
- /* I don't think that any frames may validly have a null minibuffer
- window anymore. */
- if (NILP (sf->minibuffer_window))
- emacs_abort ();
+ /* I don't think that any frames may validly have a null
+ minibuffer window anymore. (2021-04-15): Tooltip frames have
+ a null MB. Comment out the following. */
+ /* if (NILP (sf->minibuffer_window)) */
+ /* emacs_abort (); */
minibuf_window = sf->minibuffer_window;
}
@@ -195,7 +197,9 @@ move_minibuffers_onto_frame (struct frame *of, bool for_deletion)
&& (for_deletion || minibuf_follows_frame () || FRAME_INITIAL_P (of))))
return;
if (FRAME_LIVE_P (f)
- && !EQ (f->minibuffer_window, of->minibuffer_window))
+ && !EQ (f->minibuffer_window, of->minibuffer_window)
+ && WINDOW_LIVE_P (f->minibuffer_window) /* F not a tootip frame */
+ && WINDOW_LIVE_P (of->minibuffer_window))
{
zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window);
if (for_deletion && XFRAME (MB_frame) != of)
@@ -636,6 +640,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
if (minibuf_level > 1
+ && WINDOW_LIVE_P (XFRAME (MB_frame)->minibuffer_window)
&& !EQ (XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame,
MB_frame)
&& minibuf_moves_frame_when_opened ()
@@ -908,11 +913,13 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
unbind_to (count, Qnil);
/* Switch the frame back to the calling frame. */
- if ((!EQ (selected_frame, calling_frame)
- || !EQ (XWINDOW (XFRAME (calling_frame)->minibuffer_window)->frame,
- calling_frame))
- && FRAMEP (calling_frame)
- && FRAME_LIVE_P (XFRAME (calling_frame)))
+ if (FRAMEP (calling_frame)
+ && FRAME_LIVE_P (XFRAME (calling_frame))
+ && (!EQ (selected_frame, calling_frame)
+ || (WINDOW_LIVE_P (XFRAME (calling_frame)->minibuffer_window)
+ && !EQ (XWINDOW (XFRAME (calling_frame)->minibuffer_window)
+ ->frame,
+ calling_frame))))
call2 (intern ("select-frame-set-input-focus"), calling_frame, Qnil);
/* Add the value to the appropriate history list, if any. This is
@@ -1056,10 +1063,13 @@ read_minibuf_unwind (void)
{
f = XFRAME (exp_MB_frame);
window = f->minibuffer_window;
- w = XWINDOW (window);
- if (EQ (w->frame, exp_MB_frame)
- && EQ (w->contents, nth_minibuffer (minibuf_level)))
- goto found;
+ if (WINDOW_LIVE_P (window))
+ {
+ w = XWINDOW (window);
+ if (EQ (w->frame, exp_MB_frame)
+ && EQ (w->contents, nth_minibuffer (minibuf_level)))
+ goto found;
+ }
}
return; /* expired minibuffer not found. Maybe we should output an
error, here. */
diff --git a/src/w32term.c b/src/w32term.c
index 0ee805a8526..361cf33c024 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -2031,8 +2031,11 @@ w32_draw_image_relief (struct glyph_string *s)
if (s->hl == DRAW_IMAGE_SUNKEN
|| s->hl == DRAW_IMAGE_RAISED)
{
- thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief
- : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
+ thick = (tab_bar_button_relief < 0
+ ? DEFAULT_TAB_BAR_BUTTON_RELIEF
+ : (tool_bar_button_relief < 0
+ ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
+ : min (tool_bar_button_relief, 1000000)));
raised_p = s->hl == DRAW_IMAGE_RAISED;
}
else
@@ -2045,6 +2048,19 @@ w32_draw_image_relief (struct glyph_string *s)
y1 = y + s->slice.height - 1;
extra_x = extra_y = 0;
+ if (s->face->id == TAB_BAR_FACE_ID)
+ {
+ if (CONSP (Vtab_bar_button_margin)
+ && FIXNUMP (XCAR (Vtab_bar_button_margin))
+ && FIXNUMP (XCDR (Vtab_bar_button_margin)))
+ {
+ extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin));
+ extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin));
+ }
+ else if (FIXNUMP (Vtab_bar_button_margin))
+ extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin);
+ }
+
if (s->face->id == TOOL_BAR_FACE_ID)
{
if (CONSP (Vtool_bar_button_margin)
diff --git a/src/window.c b/src/window.c
index 4d5c7e763ec..7c238a33fcb 100644
--- a/src/window.c
+++ b/src/window.c
@@ -215,20 +215,6 @@ wset_combination (struct window *w, bool horflag, Lisp_Object val)
w->horizontal = horflag;
}
-static void
-wset_update_mode_line (struct window *w)
-{
- /* If this window is the selected window on its frame, set the
- global variable update_mode_lines, so that gui_consider_frame_title
- will consider this frame's title for redisplay. */
- Lisp_Object fselected_window = XFRAME (WINDOW_FRAME (w))->selected_window;
-
- if (WINDOWP (fselected_window) && XWINDOW (fselected_window) == w)
- update_mode_lines = 42;
- else
- w->update_mode_line = true;
-}
-
/* True if leaf window W doesn't reflect the actual state
of displayed buffer due to its text or overlays change. */
@@ -2556,8 +2542,13 @@ window_list (void)
if (!CONSP (Vwindow_list))
{
Lisp_Object tail, frame;
+ ptrdiff_t count = SPECPDL_INDEX ();
Vwindow_list = Qnil;
+ /* Don't allow quitting in Fnconc. Otherwise we might end up
+ with a too short Vwindow_list and Fkill_buffer not being able
+ to replace a buffer in all windows showing it (Bug#47244). */
+ specbind (Qinhibit_quit, Qt);
FOR_EACH_FRAME (tail, frame)
{
Lisp_Object arglist = Qnil;
@@ -2569,6 +2560,8 @@ window_list (void)
arglist = Fnreverse (arglist);
Vwindow_list = nconc2 (Vwindow_list, arglist);
}
+
+ unbind_to (count, Qnil);
}
return Vwindow_list;
@@ -2705,6 +2698,8 @@ static Lisp_Object
next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames,
bool next_p)
{
+ ptrdiff_t count = SPECPDL_INDEX ();
+
decode_next_window_args (&window, &minibuf, &all_frames);
/* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
@@ -2713,6 +2708,9 @@ next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames,
&& !EQ (all_frames, XWINDOW (window)->frame))
return Fframe_first_window (all_frames);
+ /* Don't allow quitting in Fmemq. */
+ specbind (Qinhibit_quit, Qt);
+
if (next_p)
{
Lisp_Object list;
@@ -2762,6 +2760,8 @@ next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames,
window = candidate;
}
+ unbind_to (count, Qnil);
+
return window;
}
@@ -2852,10 +2852,14 @@ static Lisp_Object
window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
{
Lisp_Object tail, list, rest;
+ ptrdiff_t count = SPECPDL_INDEX ();
decode_next_window_args (&window, &minibuf, &all_frames);
list = Qnil;
+ /* Don't allow quitting in Fmemq and Fnconc. */
+ specbind (Qinhibit_quit, Qt);
+
for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
list = Fcons (XCAR (tail), list);
@@ -2870,6 +2874,9 @@ window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
XSETCDR (tail, Qnil);
list = nconc2 (rest, list);
}
+
+ unbind_to (count, Qnil);
+
return list;
}
diff --git a/src/window.h b/src/window.h
index 4f209f32d34..3a75c99813d 100644
--- a/src/window.h
+++ b/src/window.h
@@ -1141,6 +1141,7 @@ extern void wset_redisplay (struct window *w);
extern void fset_redisplay (struct frame *f);
extern void bset_redisplay (struct buffer *b);
extern void bset_update_mode_line (struct buffer *b);
+extern void wset_update_mode_line (struct window *w);
/* Call this to tell redisplay to look for other windows than selected-window
that need to be redisplayed. Calling one of the *set_redisplay functions
above already does it, so it's only needed in unusual cases. */
diff --git a/src/xdisp.c b/src/xdisp.c
index 82c9dc0fec4..fecf1f6ee41 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -869,6 +869,19 @@ bset_update_mode_line (struct buffer *b)
b->text->redisplay = true;
}
+void
+wset_update_mode_line (struct window *w)
+{
+ w->update_mode_line = true;
+ /* When a window's mode line needs to be updated, the window's frame's
+ title may also need to be updated, but we don't need to worry about it
+ here. Instead, `gui_consider_frame_title' is automatically called
+ whenever w->update_mode_line is set for that frame's selected window.
+ But for this to work reliably, we have to make sure the window
+ is considered, so we have to mark it for redisplay. */
+ wset_redisplay (w);
+}
+
DEFUN ("set-buffer-redisplay", Fset_buffer_redisplay,
Sset_buffer_redisplay, 4, 4, 0,
doc: /* Mark the current buffer for redisplay.
@@ -13607,8 +13620,9 @@ redisplay_tab_bar (struct frame *f)
/* Get information about the tab-bar item which is displayed in GLYPH
on frame F. Return in *PROP_IDX the index where tab-bar item
- properties start in F->tab_bar_items. Value is false if
- GLYPH doesn't display a tab-bar item. */
+ properties start in F->tab_bar_items. Return in CLOSE_P an
+ indication whether the click was on the close-tab icon of the tab.
+ Value is false if GLYPH doesn't display a tab-bar item. */
static bool
tab_bar_item_info (struct frame *f, struct glyph *glyph,
@@ -13654,7 +13668,6 @@ static int
get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
int *hpos, int *vpos, int *prop_idx, bool *close_p)
{
- Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
struct window *w = XWINDOW (f->tab_bar_window);
int area;
@@ -13668,18 +13681,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
if (!tab_bar_item_info (f, *glyph, prop_idx, close_p))
return -1;
- /* Is mouse on the highlighted item? */
- if (EQ (f->tab_bar_window, hlinfo->mouse_face_window)
- && *vpos >= hlinfo->mouse_face_beg_row
- && *vpos <= hlinfo->mouse_face_end_row
- && (*vpos > hlinfo->mouse_face_beg_row
- || *hpos >= hlinfo->mouse_face_beg_col)
- && (*vpos < hlinfo->mouse_face_end_row
- || *hpos < hlinfo->mouse_face_end_col
- || hlinfo->mouse_face_past_end))
- return 0;
-
- return 1;
+ return *prop_idx == f->last_tab_bar_item ? 0 : 1;
}
@@ -13701,25 +13703,14 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
Lisp_Object enabled_p;
int ts;
- /* If not on the highlighted tab-bar item, and mouse-highlight is
- non-nil, return. This is so we generate the tab-bar button
- click only when the mouse button is released on the same item as
- where it was pressed. However, when mouse-highlight is disabled,
- generate the click when the button is released regardless of the
- highlight, since tab-bar items are not highlighted in that
- case. */
frame_to_window_pixel_xy (w, &x, &y);
ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
if (ts == -1
- || (ts != 0 && !NILP (Vmouse_highlight)))
+ /* If the button is released on a tab other than the one where
+ it was pressed, don't generate the tab-bar button click event. */
+ || (ts != 0 && !down_p))
return;
- /* When mouse-highlight is off, generate the click for the item
- where the button was pressed, disregarding where it was
- released. */
- if (NILP (Vmouse_highlight) && !down_p)
- prop_idx = f->last_tab_bar_item;
-
/* If item is disabled, do nothing. */
enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
if (NILP (enabled_p))
@@ -13727,10 +13718,10 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
if (down_p)
{
- /* Show item in pressed state. */
+ /* Show the clicked button in pressed state. */
if (!NILP (Vmouse_highlight))
show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
- f->last_tab_bar_item = prop_idx;
+ f->last_tab_bar_item = prop_idx; /* record the pressed tab */
}
else
{
@@ -31998,6 +31989,11 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row,
static void
show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
{
+ /* Don't bother doing anything if the mouse-face window is not set
+ up. */
+ if (!WINDOWP (hlinfo->mouse_face_window))
+ return;
+
struct window *w = XWINDOW (hlinfo->mouse_face_window);
struct frame *f = XFRAME (WINDOW_FRAME (w));
diff --git a/src/xselect.c b/src/xselect.c
index 030f6240712..cd6d86bdf4c 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -1482,14 +1482,21 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo,
= XGetSelectionOwner (display, selection_atom) != 0;
unblock_input ();
if (there_is_a_selection_owner)
- signal_error ("Selection owner couldn't convert",
- actual_type
- ? list2 (target_type,
- x_atom_to_symbol (dpyinfo, actual_type))
- : target_type);
+ {
+ AUTO_STRING (format, "Selection owner couldn't convert: %s");
+ CALLN (Fmessage, format,
+ actual_type
+ ? list2 (target_type,
+ x_atom_to_symbol (dpyinfo, actual_type))
+ : target_type);
+ return Qnil;
+ }
else
- signal_error ("No selection",
- x_atom_to_symbol (dpyinfo, selection_atom));
+ {
+ AUTO_STRING (format, "No selection: %s");
+ CALLN (Fmessage, format, x_atom_to_symbol (dpyinfo, selection_atom));
+ return Qnil;
+ }
}
if (actual_type == dpyinfo->Xatom_INCR)