diff options
author | Yuuki Harano <masm+github@masm11.me> | 2021-04-18 15:30:29 +0900 |
---|---|---|
committer | Yuuki Harano <masm+github@masm11.me> | 2021-04-18 15:30:29 +0900 |
commit | de46c7796e635faf8647a7c6a5ae34fda9adae3b (patch) | |
tree | 1a2c5f85416a642300ca217b3d85ff1be5d9f35e /src | |
parent | fb5f3e694b0f6e2bccfc2124555c986fdc409cd0 (diff) | |
parent | 5c07cd0f156217db268ccb9fa64566fb429c4257 (diff) | |
download | emacs-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.c | 2 | ||||
-rw-r--r-- | src/character.c | 56 | ||||
-rw-r--r-- | src/character.h | 4 | ||||
-rw-r--r-- | src/editfns.c | 9 | ||||
-rw-r--r-- | src/emacs.c | 207 | ||||
-rw-r--r-- | src/eval.c | 34 | ||||
-rw-r--r-- | src/frame.c | 1 | ||||
-rw-r--r-- | src/image.c | 58 | ||||
-rw-r--r-- | src/minibuf.c | 38 | ||||
-rw-r--r-- | src/w32term.c | 20 | ||||
-rw-r--r-- | src/window.c | 35 | ||||
-rw-r--r-- | src/window.h | 1 | ||||
-rw-r--r-- | src/xdisp.c | 58 | ||||
-rw-r--r-- | src/xselect.c | 21 |
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) |