diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/alloc.c | 2 | ||||
-rw-r--r-- | src/data.c | 1 | ||||
-rw-r--r-- | src/dispextern.h | 4 | ||||
-rw-r--r-- | src/dispnew.c | 2 | ||||
-rw-r--r-- | src/emacs-module.h.in | 2 | ||||
-rw-r--r-- | src/emacs.c | 1 | ||||
-rw-r--r-- | src/eval.c | 6 | ||||
-rw-r--r-- | src/fileio.c | 10 | ||||
-rw-r--r-- | src/frame.h | 14 | ||||
-rw-r--r-- | src/haikufns.c | 2 | ||||
-rw-r--r-- | src/indent.c | 2 | ||||
-rw-r--r-- | src/itree.c | 2 | ||||
-rw-r--r-- | src/json.c | 79 | ||||
-rw-r--r-- | src/keyboard.c | 5 | ||||
-rw-r--r-- | src/lisp.h | 1 | ||||
-rw-r--r-- | src/process.c | 11 | ||||
-rw-r--r-- | src/treesit.c | 247 | ||||
-rw-r--r-- | src/w32menu.c | 13 | ||||
-rw-r--r-- | src/w32term.c | 11 | ||||
-rw-r--r-- | src/window.c | 3 | ||||
-rw-r--r-- | src/xdisp.c | 40 | ||||
-rw-r--r-- | src/xfaces.c | 2 | ||||
-rw-r--r-- | src/xfns.c | 1 | ||||
-rw-r--r-- | src/xterm.c | 121 | ||||
-rw-r--r-- | src/xterm.h | 10 |
25 files changed, 390 insertions, 202 deletions
diff --git a/src/alloc.c b/src/alloc.c index a9eff612de8..1d11051072c 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -7487,7 +7487,7 @@ DEFUN ("memory-info", Fmemory_info, Smemory_info, 0, 0, 0, All values are in Kbytes. If there is no swap space, last two values are zero. If the system is not supported or memory information can't be obtained, return nil. -If `default-directory’ is remote, return memory information of the +If `default-directory' is remote, return memory information of the respective remote host. */) (void) { diff --git a/src/data.c b/src/data.c index f8b728a4805..e6be07179be 100644 --- a/src/data.c +++ b/src/data.c @@ -2630,6 +2630,7 @@ bool-vector. IDX starts at 0. */) } else if (RECORDP (array)) { + CHECK_IMPURE (array, XVECTOR (array)); if (idxval < 0 || idxval >= PVSIZE (array)) args_out_of_range (array, idx); ASET (array, idxval, newelt); diff --git a/src/dispextern.h b/src/dispextern.h index df6134e68f0..e6c4270bebd 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -107,7 +107,7 @@ typedef struct { int width, height; /* size of image */ char *data; /* pointer to image data */ - int bytes_per_line; /* accelarator to next line */ + int bytes_per_line; /* accelerator to next line */ int bits_per_pixel; /* bits per pixel (ZPixmap) */ } *Emacs_Pix_Container; typedef Emacs_Pix_Container Emacs_Pixmap; @@ -1712,7 +1712,7 @@ struct face /* Non-zero means characters in this face have a box of that thickness around them. Vertical (left and right) and horizontal - (top and bottom) borders size can be set separatedly using an + (top and bottom) borders size can be set separately using an associated list of two ints in the form (vertical_size . horizontal_size). In case one of the value is negative, its absolute value indicates the thickness, and the diff --git a/src/dispnew.c b/src/dispnew.c index 5a9ba8909e3..b845acdcbc4 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3188,7 +3188,7 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", Lisp_Object tail, frame; FOR_EACH_FRAME (tail, frame) - if (FRAME_VISIBLE_P (XFRAME (frame))) + if (FRAME_REDISPLAY_P (XFRAME (frame))) redraw_frame (XFRAME (frame)); return Qnil; diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in index d485de5aa18..c51d482d8a2 100644 --- a/src/emacs-module.h.in +++ b/src/emacs-module.h.in @@ -116,7 +116,7 @@ enum emacs_funcall_exit /* Function has signaled an error using `signal'. */ emacs_funcall_exit_signal = 1, - /* Function has exit using `throw'. */ + /* Function has exited using `throw'. */ emacs_funcall_exit_throw = 2 }; diff --git a/src/emacs.c b/src/emacs.c index d156b77d950..ee606181d7d 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -2918,6 +2918,7 @@ killed. */ if (!NILP (restart)) { + turn_on_atimers (false); #ifdef WINDOWSNT if (w32_reexec_emacs (initial_cmdline, initial_wd) < 0) #else diff --git a/src/eval.c b/src/eval.c index 99f3650fc9b..cff4b924778 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1367,7 +1367,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, error ("Invalid condition handler: %s", SDATA (Fprin1_to_string (tem, Qt, Qnil))); if (CONSP (tem) && EQ (XCAR (tem), QCsuccess)) - success_handler = XCDR (tem); + success_handler = tem; else clausenb++; } @@ -1430,7 +1430,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, if (!NILP (success_handler)) { if (NILP (var)) - return Fprogn (success_handler); + return Fprogn (XCDR (success_handler)); Lisp_Object handler_var = var; if (!NILP (Vinternal_interpreter_environment)) @@ -1442,7 +1442,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, specpdl_ref count = SPECPDL_INDEX (); specbind (handler_var, result); - return unbind_to (count, Fprogn (success_handler)); + return unbind_to (count, Fprogn (XCDR (success_handler))); } return result; } diff --git a/src/fileio.c b/src/fileio.c index e7c2af81421..66ce6b30887 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5376,12 +5376,16 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, { /* Transfer data and metadata to disk, retrying if interrupted. fsync can report a write failure here, e.g., due to disk full - under NFS. But ignore EINVAL, which means fsync is not - supported on this file. */ + under NFS. But ignore EINVAL (and EBADF on Windows), which + means fsync is not supported on this file. */ while (fsync (desc) != 0) if (errno != EINTR) { - if (errno != EINVAL) + if (errno != EINVAL +#ifdef WINDOWSNT + && errno != EBADF +#endif + ) ok = 0, save_errno = errno; break; } diff --git a/src/frame.h b/src/frame.h index dcd32036b86..f29cc249ea8 100644 --- a/src/frame.h +++ b/src/frame.h @@ -1010,6 +1010,20 @@ default_pixels_per_inch_y (void) /* True if frame F is currently visible. */ #define FRAME_VISIBLE_P(f) (f)->visible +/* True if frame F should be redisplayed. This is normally the same + as FRAME_VISIBLE_P (f). Under X, frames can continue to be + displayed to the user by the compositing manager even if they are + invisible, so this also checks whether or not the frame is reported + visible by the X server. */ + +#ifndef HAVE_X_WINDOWS +#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f)) +#else +#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f) \ + || (FRAME_X_P (f) \ + && FRAME_X_VISIBLE (f))) +#endif + /* True if frame F is currently visible but hidden. */ #define FRAME_OBSCURED_P(f) ((f)->visible > 1) diff --git a/src/haikufns.c b/src/haikufns.c index 5717d0354f8..ea12a144888 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -3245,7 +3245,7 @@ syms_of_haikufns (void) DEFVAR_LISP ("haiku-allowed-ui-colors", Vhaiku_allowed_ui_colors, doc: /* Vector of UI colors that Emacs can look up from the system. -If this is set up incorrectly, Emacs can crash when encoutering an +If this is set up incorrectly, Emacs can crash when encountering an invalid color. */); Vhaiku_allowed_ui_colors = Qnil; diff --git a/src/indent.c b/src/indent.c index 4671ccccf90..66edaff67de 100644 --- a/src/indent.c +++ b/src/indent.c @@ -887,6 +887,8 @@ DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ", Optional second argument MINIMUM says always do at least MINIMUM spaces even if that goes past COLUMN; by default, MINIMUM is zero. +Whether this uses tabs or spaces depends on `indent-tabs-mode'. + The return value is the column where the insertion ends. */) (Lisp_Object column, Lisp_Object minimum) { diff --git a/src/itree.c b/src/itree.c index 688d5c82476..5079e2389f8 100644 --- a/src/itree.c +++ b/src/itree.c @@ -85,7 +85,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ this narrowing is O(K*log(N)) where K is the size of the result set. If we are interested in finding the node in a range with the smallest END, we might have to examine all K nodes in that range. - In the case of the *-overlay-channge functions, K may well be equal + In the case of the *-overlay-change functions, K may well be equal to N. Ideally, a tree based data structure for overlays would have diff --git a/src/json.c b/src/json.c index cdcc11358e6..621c7d7c15f 100644 --- a/src/json.c +++ b/src/json.c @@ -555,6 +555,40 @@ json_parse_args (ptrdiff_t nargs, } } +static bool +json_available_p (void) +{ +#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); + } + return json_initialized; +#else /* !WINDOWSNT */ + return true; +#endif +} + +#ifdef WINDOWSNT +static void +ensure_json_available (void) +{ + if (!json_available_p ()) + Fsignal (Qjson_unavailable, + list1 (build_unibyte_string ("jansson library not found"))); +} +#endif + +DEFUN ("json--available-p", Fjson__available_p, Sjson__available_p, 0, 0, NULL, + doc: /* Return non-nil if libjansson is available (internal use only). */) + (void) +{ + return json_available_p () ? Qt : Qnil; +} + DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, MANY, NULL, doc: /* Return the JSON representation of OBJECT as a string. @@ -587,16 +621,7 @@ usage: (json-serialize OBJECT &rest ARGS) */) specpdl_ref 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) - Fsignal (Qjson_unavailable, - list1 (build_unibyte_string ("jansson library not found"))); + ensure_json_available (); #endif struct json_configuration conf = @@ -696,16 +721,7 @@ usage: (json-insert OBJECT &rest ARGS) */) specpdl_ref 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) - Fsignal (Qjson_unavailable, - list1 (build_unibyte_string ("jansson library not found"))); + ensure_json_available (); #endif struct json_configuration conf = @@ -953,16 +969,7 @@ usage: (json-parse-string STRING &rest ARGS) */) specpdl_ref 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) - Fsignal (Qjson_unavailable, - list1 (build_unibyte_string ("jansson library not found"))); + ensure_json_available (); #endif Lisp_Object string = args[0]; @@ -1050,16 +1057,7 @@ usage: (json-parse-buffer &rest args) */) specpdl_ref 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) - Fsignal (Qjson_unavailable, - list1 (build_unibyte_string ("jansson library not found"))); + ensure_json_available (); #endif struct json_configuration conf = @@ -1137,6 +1135,7 @@ syms_of_json (void) DEFSYM (Qplist, "plist"); DEFSYM (Qarray, "array"); + defsubr (&Sjson__available_p); defsubr (&Sjson_serialize); defsubr (&Sjson_insert); defsubr (&Sjson_parse_string); diff --git a/src/keyboard.c b/src/keyboard.c index d68b50428a9..7bf89ac7d4b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -503,11 +503,10 @@ echo_add_key (Lisp_Object c) if ((NILP (echo_string) || SCHARS (echo_string) == 0) && help_char_p (c)) { - AUTO_STRING (str, " (Type ? for further options, q for quick help)"); + AUTO_STRING (str, " (Type ? for further options, C-q for quick help)"); AUTO_LIST2 (props, Qface, Qhelp_key_binding); Fadd_text_properties (make_fixnum (7), make_fixnum (8), props, str); - Fadd_text_properties (make_fixnum (30), make_fixnum (31), props, -str); + Fadd_text_properties (make_fixnum (30), make_fixnum (33), props, str); new_string = concat2 (new_string, str); } diff --git a/src/lisp.h b/src/lisp.h index 518c2e6f99d..3fadd228d2d 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -22,7 +22,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <alloca.h> #include <setjmp.h> -#include <stdalign.h> #include <stdarg.h> #include <stddef.h> #include <string.h> diff --git a/src/process.c b/src/process.c index 6cbdfed1f59..e07a019b464 100644 --- a/src/process.c +++ b/src/process.c @@ -6795,10 +6795,13 @@ emacs_get_tty_pgrp (struct Lisp_Process *p) DEFUN ("process-running-child-p", Fprocess_running_child_p, Sprocess_running_child_p, 0, 1, 0, - doc: /* Return non-nil if PROCESS has given the terminal to a -child. If the operating system does not make it possible to find out, -return t. If we can find out, return the numeric ID of the foreground -process group. */) + doc: /* Return non-nil if PROCESS has given control of its terminal to a child. +If the operating system does not make it possible to find out, return t. +If it's possible to find out, return the numeric ID of the foreground +process group if PROCESS did give control of its terminal to a +child process, and return nil if it didn't. + +PROCESS must be a real subprocess, not a connection. */) (Lisp_Object process) { /* Initialize in case ioctl doesn't exist or gives an error, diff --git a/src/treesit.c b/src/treesit.c index 9fa88b48dcc..d168ff02b69 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -2,6 +2,8 @@ Copyright (C) 2021-2022 Free Software Foundation, Inc. +Maintainer: Yuan Fu <casouri@gmail.com> + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify @@ -404,6 +406,10 @@ init_treesit_functions (void) /*** Initialization */ +/* This is the limit on recursion levels for some tree-sitter + functions. Remember to update docstrings when changing this + value. */ +const ptrdiff_t treesit_recursion_limit = 1000; bool treesit_initialized = false; static bool @@ -927,11 +933,24 @@ static void treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree, Lisp_Object parser) { - uint32_t len; - TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len); + /* If the old_tree is NULL, meaning this is the first parse, the + changed range is the whole buffer. */ + Lisp_Object lisp_ranges; struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer); - Lisp_Object lisp_ranges = treesit_make_ranges (ranges, len, buf); - xfree (ranges); + if (old_tree) + { + uint32_t len; + TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len); + lisp_ranges = treesit_make_ranges (ranges, len, buf); + xfree (ranges); + } + else + { + struct buffer *oldbuf = current_buffer; + set_buffer_internal (buf); + lisp_ranges = Fcons (Fcons (Fpoint_min (), Fpoint_max ()), Qnil); + set_buffer_internal (oldbuf); + } specpdl_ref count = SPECPDL_INDEX (); @@ -949,6 +968,11 @@ treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree, static void treesit_ensure_parsed (Lisp_Object parser) { + /* Make sure this comes before everything else, see comment + (ref:notifier-inside-ensure-parsed) for more detail. */ + if (!XTS_PARSER (parser)->need_reparse) + return; + struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); /* Before we parse, catch up with the narrowing situation. */ @@ -957,8 +981,6 @@ treesit_ensure_parsed (Lisp_Object parser) because it might set the flag to true. */ treesit_sync_visible_region (parser); - if (!XTS_PARSER (parser)->need_reparse) - return; TSParser *treesit_parser = XTS_PARSER (parser)->parser; TSTree *tree = XTS_PARSER (parser)->tree; TSInput input = XTS_PARSER (parser)->input; @@ -978,14 +1000,17 @@ treesit_ensure_parsed (Lisp_Object parser) xsignal1 (Qtreesit_parse_error, buf); } - if (tree != NULL) - { - treesit_call_after_change_functions (tree, new_tree, parser); - ts_tree_delete (tree); - } - XTS_PARSER (parser)->tree = new_tree; XTS_PARSER (parser)->need_reparse = false; + + /* After-change functions should run at the very end, most crucially + after need_reparse is set to false, this way if the function + calls some tree-sitter function which invokes + treesit_ensure_parsed again, it returns early and do not + recursively call the after change functions again. + (ref:notifier-inside-ensure-parsed) */ + treesit_call_after_change_functions (tree, new_tree, parser); + ts_tree_delete (tree); } /* This is the read function provided to tree-sitter to read from a @@ -1762,7 +1787,7 @@ If NODE is nil, return nil. */) return build_string (string); } -static TSTreeCursor treesit_cursor_helper (TSNode, Lisp_Object); +static bool treesit_cursor_helper (TSTreeCursor *, TSNode, Lisp_Object); DEFUN ("treesit-node-parent", Ftreesit_node_parent, Streesit_node_parent, 1, 1, 0, @@ -1778,7 +1803,10 @@ Return nil if NODE has no parent. If NODE is nil, return nil. */) TSNode treesit_node = XTS_NODE (node)->node; Lisp_Object parser = XTS_NODE (node)->parser; - TSTreeCursor cursor = treesit_cursor_helper (treesit_node, parser); + TSTreeCursor cursor; + if (!treesit_cursor_helper (&cursor, treesit_node, parser)) + return return_value; + if (ts_tree_cursor_goto_parent (&cursor)) { TSNode parent = ts_tree_cursor_current_node (&cursor); @@ -2042,12 +2070,11 @@ Note that this function returns an immediate child, not the smallest struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; - ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos)); treesit_check_position (pos, buf); - treesit_initialize (); + ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos)); TSNode treesit_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -2078,14 +2105,14 @@ If NODE is nil, return nil. */) struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; - ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, XFIXNUM (beg)); - ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, XFIXNUM (end)); treesit_check_position (beg, buf); treesit_check_position (end, buf); treesit_initialize (); + ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, XFIXNUM (beg)); + ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, XFIXNUM (end)); TSNode treesit_node = XTS_NODE (node)->node; TSNode child; if (NILP (named)) @@ -2161,6 +2188,8 @@ See Info node `(elisp)Pattern Matching' for detailed explanation. */) return build_pure_c_string ("#equal"); if (EQ (pattern, QCmatch)) return build_pure_c_string ("#match"); + if (EQ (pattern, QCpred)) + return build_pure_c_string ("#pred"); Lisp_Object opening_delimeter = build_pure_c_string (VECTORP (pattern) ? "[" : "("); Lisp_Object closing_delimiter @@ -2260,10 +2289,10 @@ treesit_predicates_for_pattern (TSQuery *query, uint32_t pattern_index) return Fnreverse (result); } -/* Translate a capture NAME (symbol) to the text of the captured node. +/* Translate a capture NAME (symbol) to a node. Signals treesit-query-error if such node is not captured. */ static Lisp_Object -treesit_predicate_capture_name_to_text (Lisp_Object name, +treesit_predicate_capture_name_to_node (Lisp_Object name, struct capture_range captures) { Lisp_Object node = Qnil; @@ -2283,6 +2312,16 @@ treesit_predicate_capture_name_to_text (Lisp_Object name, name, build_pure_c_string ("A predicate can only refer" " to captured nodes in the " "same pattern")); + return node; +} + +/* Translate a capture NAME (symbol) to the text of the captured node. + Signals treesit-query-error if such node is not captured. */ +static Lisp_Object +treesit_predicate_capture_name_to_text (Lisp_Object name, + struct capture_range captures) +{ + Lisp_Object node = treesit_predicate_capture_name_to_node (name, captures); struct buffer *old_buffer = current_buffer; set_buffer_internal (XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer)); @@ -2356,13 +2395,30 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures) return false; } -/* About predicates: I decide to hard-code predicates in C instead of - implementing an extensible system where predicates are translated - to Lisp functions, and new predicates can be added by extending a - list of functions, because I really couldn't imagine any useful - predicates besides equal and match. If we later found out that - such system is indeed useful and necessary, it can be easily - added. */ +/* Handles predicate (#pred FN ARG...). Return true if FN returns + non-nil; return false otherwise. The arity of FN must match the + number of ARGs */ +static bool +treesit_predicate_pred (Lisp_Object args, struct capture_range captures) +{ + if (XFIXNUM (Flength (args)) < 2) + xsignal2 (Qtreesit_query_error, + build_pure_c_string ("Predicate `pred' requires " + "at least two arguments, " + "but was only given"), + Flength (args)); + + Lisp_Object fn = Fintern (XCAR (args), Qnil); + Lisp_Object nodes = Qnil; + Lisp_Object tail = XCDR (args); + FOR_EACH_TAIL (tail) + nodes = Fcons (treesit_predicate_capture_name_to_node (XCAR (tail), + captures), + nodes); + nodes = Fnreverse (nodes); + + return !NILP (CALLN (Fapply, fn, nodes)); +} /* If all predicates in PREDICATES passes, return true; otherwise return false. */ @@ -2378,14 +2434,17 @@ treesit_eval_predicates (struct capture_range captures, Lisp_Object predicates) Lisp_Object fn = XCAR (predicate); Lisp_Object args = XCDR (predicate); if (!NILP (Fstring_equal (fn, build_pure_c_string ("equal")))) - pass = treesit_predicate_equal (args, captures); + pass &= treesit_predicate_equal (args, captures); else if (!NILP (Fstring_equal (fn, build_pure_c_string ("match")))) - pass = treesit_predicate_match (args, captures); + pass &= treesit_predicate_match (args, captures); + else if (!NILP (Fstring_equal (fn, build_pure_c_string ("pred")))) + pass &= treesit_predicate_pred (args, captures); else xsignal3 (Qtreesit_query_error, build_pure_c_string ("Invalid predicate"), fn, build_pure_c_string ("Currently Emacs only supports" - " equal and match predicate")); + " equal, match, and pred" + " predicate")); } /* If all predicates passed, add captures to result list. */ return pass; @@ -2637,8 +2696,59 @@ treesit_assume_true (bool val) eassert (val == true); } +/* Tries to move CURSOR to point to TARGET. END_POS is the end of + TARGET. If success, return true, otherwise move CURSOR back to + starting position and return false. LIMIT is the recursion + limit. */ +static bool +treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode *target, + uint32_t end_pos, ptrdiff_t limit) +{ + if (limit <= 0) + return false; + + TSNode cursor_node = ts_tree_cursor_current_node (cursor); + if (ts_node_eq (cursor_node, *target)) + return true; + + if (!ts_tree_cursor_goto_first_child (cursor)) + return false; + + /* Skip nodes that definitely don't contain TARGET. */ + while (ts_node_end_byte (cursor_node) < end_pos) + { + if (!ts_tree_cursor_goto_next_sibling (cursor)) + break; + cursor_node = ts_tree_cursor_current_node (cursor); + } + + /* Go through each sibling that could contain TARGET. Because of + missing nodes (their width is 0), there could be multiple + siblings that could contain TARGET. */ + while (ts_node_start_byte (cursor_node) <= end_pos) + { + if (treesit_cursor_helper_1 (cursor, target, end_pos, limit - 1)) + return true; + + if (!ts_tree_cursor_goto_next_sibling (cursor)) + break; + cursor_node = ts_tree_cursor_current_node (cursor); + } + + /* Couldn't find TARGET, must be not in this subtree, move cursor + back and pray that other brothers and sisters can succeed. */ + treesit_assume_true (ts_tree_cursor_goto_parent (cursor)); + return false; +} + /* Create a TSTreeCursor pointing at NODE. PARSER is the lisp parser - that produced NODE. + that produced NODE. If success, return true, otherwise return + false. This function should almost always succeed, but if the parse + tree is strangely too deep and exceeds the recursion limit, this + function will fail and return false. + + If this function returns true, caller needs to free CURSOR; if + returns false, caller don't need to free CURSOR. The reason we need this instead of simply using ts_tree_cursor_new is that we have to create the cursor on the root node and traverse @@ -2646,56 +2756,17 @@ treesit_assume_true (bool val) Otherwise going to sibling or parent of NODE wouldn't work. (Wow perfect filling.) */ -static TSTreeCursor -treesit_cursor_helper (TSNode node, Lisp_Object parser) +static bool +treesit_cursor_helper (TSTreeCursor *cursor, TSNode node, Lisp_Object parser) { uint32_t end_pos = ts_node_end_byte (node); TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree); - TSTreeCursor cursor = ts_tree_cursor_new (root); - TSNode cursor_node = ts_tree_cursor_current_node (&cursor); - /* This is like treesit-node-at. We go down from the root node, - either to first child or next sibling, repeatedly, and finally - arrive at NODE. */ - while (!ts_node_eq (node, cursor_node)) - { - treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor)); - cursor_node = ts_tree_cursor_current_node (&cursor); - /* ts_tree_cursor_goto_first_child_for_byte is not reliable, so - we just go through each sibling. */ - while (ts_node_is_missing (cursor_node) - || ts_node_end_byte (cursor_node) < end_pos) - { - /* A "missing" node has zero width, so it's possible that - its end = NODE.end but it's not NODE, so we skip them. - But we need to make sure this missing node is not the - node we are looking for before skipping it. */ - if (ts_node_is_missing (cursor_node) - && ts_node_eq (node, cursor_node)) - return cursor; - treesit_assume_true (ts_tree_cursor_goto_next_sibling (&cursor)); - cursor_node = ts_tree_cursor_current_node (&cursor); - } - /* Right now CURSOR.end >= NODE.end. But what if CURSOR.end = - NODE.end, and there are missing nodes after CURSOR, and the - missing node after CURSOR is the NODE we are looking for?? - Well, create a probe and look ahead. (This is tested by - treesit-cursor-helper-with-missing-node.) */ - TSTreeCursor probe = ts_tree_cursor_copy (&cursor); - TSNode probe_node; - while (ts_tree_cursor_goto_next_sibling (&probe)) - { - probe_node = ts_tree_cursor_current_node (&probe); - if (!ts_node_is_missing (probe_node)) - break; - if (ts_node_eq (probe_node, node)) - { - ts_tree_cursor_delete (&cursor); - return probe; - } - } - ts_tree_cursor_delete (&probe); - } - return cursor; + *cursor = ts_tree_cursor_new (root); + bool success = treesit_cursor_helper_1 (cursor, &node, end_pos, + treesit_recursion_limit); + if (!success) + ts_tree_cursor_delete (cursor); + return success; } /* Move CURSOR to the next/previous sibling. FORWARD controls the @@ -2957,7 +3028,7 @@ Return the first matched node, or nil if none matches. */) /* We use a default limit of 1000. See bug#59426 for the discussion. */ - ptrdiff_t the_limit = 1000; + ptrdiff_t the_limit = treesit_recursion_limit; if (!NILP (limit)) { CHECK_FIXNUM (limit); @@ -2968,7 +3039,10 @@ Return the first matched node, or nil if none matches. */) Lisp_Object parser = XTS_NODE (node)->parser; Lisp_Object return_value = Qnil; - TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (node)->node, parser); + TSTreeCursor cursor; + if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser)) + return return_value; + if (treesit_search_dfs (&cursor, predicate, parser, NILP (backward), NILP (all), the_limit, false)) { @@ -3022,7 +3096,10 @@ always traverse leaf nodes first, then upwards. */) Lisp_Object parser = XTS_NODE (start)->parser; Lisp_Object return_value = Qnil; - TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (start)->node, parser); + TSTreeCursor cursor; + if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser)) + return return_value; + if (treesit_search_forward (&cursor, predicate, parser, NILP (backward), NILP (all))) { @@ -3130,7 +3207,7 @@ a regexp. */) /* We use a default limit of 1000. See bug#59426 for the discussion. */ - ptrdiff_t the_limit = 1000; + ptrdiff_t the_limit = treesit_recursion_limit; if (!NILP (limit)) { CHECK_FIXNUM (limit); @@ -3141,7 +3218,10 @@ a regexp. */) Lisp_Object parser = XTS_NODE (root)->parser; Lisp_Object parent = Fcons (Qnil, Qnil); - TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (root)->node, parser); + TSTreeCursor cursor; + if (!treesit_cursor_helper (&cursor, XTS_NODE (root)->node, parser)) + return Qnil; + treesit_build_sparse_tree (&cursor, parent, predicate, process_fn, the_limit, parser); ts_tree_cursor_delete (&cursor); @@ -3187,6 +3267,7 @@ syms_of_treesit (void) DEFSYM (QCanchor, ":anchor"); DEFSYM (QCequal, ":equal"); DEFSYM (QCmatch, ":match"); + DEFSYM (QCpred, ":pred"); DEFSYM (Qnot_found, "not-found"); DEFSYM (Qsymbol_error, "symbol-error"); diff --git a/src/w32menu.c b/src/w32menu.c index b10239d5cc6..5f06f4c4170 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1073,7 +1073,10 @@ is_simple_dialog (Lisp_Object contents) if (NILP (Fstring_equal (name, other))) return false; - /* Check there are no more options. */ + /* Check there are no more options. + + (FIXME: Since we use MB_YESNOCANCEL, we could also consider + dialogs with 3 options: Yes/No/Cancel as "simple". */ options = XCDR (options); return !(CONSP (options)); } @@ -1085,7 +1088,13 @@ simple_dialog_show (struct frame *f, Lisp_Object contents, Lisp_Object header) UINT type; Lisp_Object lispy_answer = Qnil, temp = XCAR (contents); - type = MB_YESNO; + /* We use MB_YESNOCANCEL to allow the user the equivalent of C-g + when the Yes/No question is asked vya y-or-n-p or + yes-or-no-p. */ + if (w32_yes_no_dialog_show_cancel) + type = MB_YESNOCANCEL; + else + type = MB_YESNO; /* Since we only handle Yes/No dialogs, and we already checked is_simple_dialog, we don't need to worry about checking contents diff --git a/src/w32term.c b/src/w32term.c index dff21489e5b..e40e4588fde 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -7696,6 +7696,7 @@ static void w32_initialize (void) { HANDLE shell; + BOOL caret; HRESULT (WINAPI * set_user_model) (const wchar_t * id); baud_rate = 19200; @@ -7732,8 +7733,9 @@ w32_initialize (void) /* Initialize w32_use_visible_system_caret based on whether a screen reader is in use. */ - if (!SystemParametersInfo (SPI_GETSCREENREADER, 0, - &w32_use_visible_system_caret, 0)) + if (SystemParametersInfo (SPI_GETSCREENREADER, 0, &caret, 0)) + w32_use_visible_system_caret = caret == TRUE; + else w32_use_visible_system_caret = 0; any_help_event_p = 0; @@ -7923,6 +7925,11 @@ unconditionally set to nil on older systems. */); w32_use_native_image_api = 0; #endif + DEFVAR_BOOL ("w32-yes-no-dialog-show-cancel", + w32_yes_no_dialog_show_cancel, + doc: /* If non-nil, show Cancel button in MS-Windows GUI Yes/No dialogs. */); + w32_yes_no_dialog_show_cancel = 1; + /* FIXME: The following variable will be (hopefully) removed before Emacs 25.1 gets released. */ diff --git a/src/window.c b/src/window.c index 90fa6ac2dfe..cd43919a7d8 100644 --- a/src/window.c +++ b/src/window.c @@ -1649,7 +1649,8 @@ check_window_containing (struct window *w, void *user_data) set *PART to the id of that element. If there is no window under X, Y return nil and leave *PART - unmodified. TOOL_BAR_P means detect tool-bar windows. + unmodified. TOOL_BAR_P means detect tool-bar windows, and + TAB_BAR_P means detect tab-bar windows. This function was previously implemented with a loop cycling over windows with Fnext_window, and starting with the frame's selected diff --git a/src/xdisp.c b/src/xdisp.c index e8df230ef89..db6dd3fab63 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12938,7 +12938,7 @@ clear_garbaged_frames (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) + if (FRAME_REDISPLAY_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p /* It makes no sense to redraw a non-selected TTY @@ -12987,7 +12987,7 @@ echo_area_display (bool update_frame_p) f = XFRAME (WINDOW_FRAME (w)); /* Don't display if frame is invisible or not yet initialized. */ - if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p) + if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p) return; #ifdef HAVE_WINDOW_SYSTEM @@ -13543,7 +13543,7 @@ prepare_menu_bars (void) TTY frames to be completely redrawn, when there are more than one of them, even though nothing should be changed on display. */ - || (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f)))) + || (FRAME_REDISPLAY_P (f) && FRAME_WINDOW_P (f)))) gui_consider_frame_title (frame); } } @@ -14271,12 +14271,14 @@ redisplay_tab_bar (struct frame *f) frame_default_tab_bar_height = new_height; } - /* If new_height or new_nrows indicate that we need to enlarge the - tab-bar window, we can return right away. */ + /* If new_height or new_nrows indicate that we need to enlarge or + shrink the tab-bar window, we can return right away. */ if (new_nrows > f->n_tab_bar_rows || (EQ (Vauto_resize_tab_bars, Qgrow_only) && !f->minimize_tab_bar_window_p - && new_height > WINDOW_PIXEL_HEIGHT (w))) + && new_height > WINDOW_PIXEL_HEIGHT (w)) + || (! EQ (Vauto_resize_tab_bars, Qgrow_only) + && new_height < WINDOW_PIXEL_HEIGHT (w))) { if (FRAME_TERMINAL (f)->change_tab_bar_height_hook) FRAME_TERMINAL (f)->change_tab_bar_height_hook (f, new_height); @@ -16430,7 +16432,7 @@ redisplay_internal (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f)) + if (FRAME_REDISPLAY_P (f)) { ++number_of_visible_frames; /* Adjust matrices for visible frames only. */ @@ -16572,7 +16574,7 @@ redisplay_internal (void) && !w->update_mode_line && !current_buffer->clip_changed && !current_buffer->prevent_redisplay_optimizations_p - && FRAME_VISIBLE_P (XFRAME (w->frame)) + && FRAME_REDISPLAY_P (XFRAME (w->frame)) && !FRAME_OBSCURED_P (XFRAME (w->frame)) && !XFRAME (w->frame)->cursor_type_changed && !XFRAME (w->frame)->face_change @@ -16838,14 +16840,20 @@ redisplay_internal (void) /* Only GC scrollbars when we redisplay the whole frame. */ = f->redisplay || !REDISPLAY_SOME_P (); bool f_redisplay_flag = f->redisplay; + + /* The X error handler may have deleted that frame + before we went back to retry_frame. This must come + before any accesses to f->terminal. */ + if (!FRAME_LIVE_P (f)) + continue; + /* Mark all the scroll bars to be removed; we'll redeem the ones we want when we redisplay their windows. */ if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook) FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { - /* Don't allow freeing images and faces for this frame as long as the frame's update wasn't completed. This prevents crashes when some Lisp @@ -16870,7 +16878,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook) FRAME_TERMINAL (f)->judge_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { /* If fonts changed on visible frame, display again. */ if (f->fonts_changed) @@ -16976,7 +16984,7 @@ redisplay_internal (void) } } } - else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { sf->inhibit_clear_image_cache = true; displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); @@ -17027,7 +17035,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { if (hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (selected_window)) @@ -17126,7 +17134,7 @@ redisplay_internal (void) FOR_EACH_FRAME (tail, frame) { - if (XFRAME (frame)->visible) + if (FRAME_REDISPLAY_P (XFRAME (frame))) new_count++; } @@ -33250,7 +33258,7 @@ display_and_set_cursor (struct window *w, bool on, windows and frames; in the latter case, the frame or window may be in the midst of changing its size, and x and y may be off the window. */ - if (! FRAME_VISIBLE_P (f) + if (! FRAME_REDISPLAY_P (f) || vpos >= w->current_matrix->nrows || hpos >= w->current_matrix->matrix_w) return; @@ -33411,7 +33419,7 @@ gui_update_cursor (struct frame *f, bool on_p) void gui_clear_cursor (struct window *w) { - if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p) + if (FRAME_REDISPLAY_P (XFRAME (w->frame)) && w->phys_cursor_on_p) update_window_cursor (w, false); } diff --git a/src/xfaces.c b/src/xfaces.c index 0189e612128..823c1d93d07 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -7279,7 +7279,7 @@ syms_of_xfaces (void) DEFVAR_BOOL ("face-filters-always-match", face_filters_always_match, doc: /* Non-nil means that face filters are always deemed to match. This variable is intended for use only by code that evaluates -the "specifity" of a face specification and should be let-bound +the "specificity" of a face specification and should be let-bound only for this purpose. */); DEFVAR_LISP ("face--new-frame-defaults", Vface_new_frame_defaults, diff --git a/src/xfns.c b/src/xfns.c index 668f711bdb5..1cc5aec1eb4 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4741,6 +4741,7 @@ This function is an internal primitive--use `make-frame' instead. */) #endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */ f->output_data.x->white_relief.pixel = -1; f->output_data.x->black_relief.pixel = -1; + f->output_data.x->visibility_state = VisibilityFullyObscured; fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, diff --git a/src/xterm.c b/src/xterm.c index a1acfa80744..1eef8e7a724 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4597,7 +4597,7 @@ x_dnd_send_position (struct frame *f, Window target, Window toplevel, maintained by the original author of the protocol specifies it for all versions. Since at least one program supports these flags, but uses protocol v4 (and not v5), set them for all - protocool versions. */ + protocol versions. */ if (button >= 4 && button <= 7) { msg.xclient.data.l[1] |= (1 << 10); @@ -7645,6 +7645,46 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row) #endif } +/* Generate a premultiplied pixel value for COLOR with ALPHA applied + on the given display. COLOR will be modified. The display must + use a visual that supports an alpha channel. + + This is possibly dead code on builds which do not support + XRender. */ + +#ifndef USE_CAIRO + +static unsigned long +x_premultiply_pixel (struct x_display_info *dpyinfo, + XColor *color, double alpha) +{ + unsigned long pixel; + + eassert (dpyinfo->alpha_bits); + + /* Multiply the RGB channels. */ + color->red *= alpha; + color->green *= alpha; + color->blue *= alpha; + + /* First, allocate a fully opaque pixel. */ + pixel = x_make_truecolor_pixel (dpyinfo, color->red, + color->green, + color->blue); + + /* Next, erase the alpha component. */ + pixel &= ~dpyinfo->alpha_mask; + + /* And add an alpha channel. */ + pixel |= (((unsigned long) (alpha * 65535) + >> (16 - dpyinfo->alpha_bits)) + << dpyinfo->alpha_offset); + + return pixel; +} + +#endif + static void x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p) @@ -7734,18 +7774,15 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, if (FRAME_DISPLAY_INFO (f)->alpha_bits && f->alpha_background < 1.0) { + /* Extend the background color with an alpha channel + according to f->alpha_background. */ bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, + f->alpha_background); } /* Draw the bitmap. I believe these small pixmaps can be cached @@ -8894,7 +8931,11 @@ x_color_cells (Display *dpy, int *ncells) /* On frame F, translate pixel colors to RGB values for the NCOLORS - colors in COLORS. Use cached information, if available. */ + colors in COLORS. Use cached information, if available. + + Pixel values are in unsigned normalized format, meaning that + extending missing bits is done straightforwardly without any + complex colorspace conversions. */ void x_query_colors (struct frame *f, XColor *colors, int ncolors) @@ -8942,6 +8983,7 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) colors[i].green = (g * gmult) >> 16; colors[i].blue = (b * bmult) >> 16; } + return; } @@ -8984,16 +9026,10 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor) { bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, f->alpha_background); } #endif } @@ -21707,9 +21743,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case VisibilityNotify: f = x_top_window_to_frame (dpyinfo, event->xvisibility.window); - if (f && (event->xvisibility.state == VisibilityUnobscured - || event->xvisibility.state == VisibilityPartiallyObscured)) - SET_FRAME_VISIBLE (f, 1); + + if (f) + FRAME_X_OUTPUT (f)->visibility_state = event->xvisibility.state; goto OTHER; @@ -26264,8 +26300,10 @@ x_error_handler (Display *display, XErrorEvent *event) static void NO_INLINE x_error_quitter (Display *display, XErrorEvent *event) { - char buf[256], buf1[400 + INT_STRLEN_BOUND (int) - + INT_STRLEN_BOUND (unsigned long)]; + char buf[256], buf1[800 + INT_STRLEN_BOUND (int) + + INT_STRLEN_BOUND (unsigned long) + + INT_STRLEN_BOUND (XID) + + INT_STRLEN_BOUND (int)]; /* Ignore BadName errors. They can happen because of fonts or colors that are not defined. */ @@ -26278,8 +26316,12 @@ x_error_quitter (Display *display, XErrorEvent *event) XGetErrorText (display, event->error_code, buf, sizeof (buf)); sprintf (buf1, "X protocol error: %s on protocol request %d\n" - "Serial no: %lu\n", buf, event->request_code, - event->serial); + "Serial no: %lu\n" + "Failing resource ID (if any): 0x%lx\n" + "Minor code: %d\n" + "This is a bug! Please report this to bug-gnu-emacs@gnu.org!\n", + buf, event->request_code, event->serial, event->resourceid, + event->minor_code); x_connection_closed (display, buf1, false); } @@ -28435,7 +28477,10 @@ x_make_frame_invisible (struct frame *f) error ("Can't notify window manager of window withdrawal"); } - XSync (FRAME_X_DISPLAY (f), False); + /* Don't perform the synchronization if the network connection is + slow, and the user says it is unwanted. */ + if (NILP (Vx_lax_frame_positioning)) + XSync (FRAME_X_DISPLAY (f), False); /* We can't distinguish this from iconification just by the event that we get from the server. @@ -28446,8 +28491,7 @@ x_make_frame_invisible (struct frame *f) SET_FRAME_ICONIFIED (f, false); if (CONSP (frame_size_history)) - frame_size_history_plain - (f, build_string ("x_make_frame_invisible")); + frame_size_history_plain (f, build_string ("x_make_frame_invisible")); unblock_input (); } @@ -29894,13 +29938,17 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { char *vendor = ServerVendor (dpy); - /* Temporarily hide the partially initialized terminal. */ + /* Temporarily hide the partially initialized terminal. + Use safe_call so that if a signal happens, a partially + initialized display (and display connection) is not + kept around. */ terminal_list = terminal->next_terminal; unblock_input (); - kset_system_key_alist - (terminal->kboard, - call1 (Qvendor_specific_keysyms, - vendor ? build_string (vendor) : empty_unibyte_string)); + kset_system_key_alist (terminal->kboard, + safe_call1 (Qvendor_specific_keysyms, + (vendor + ? build_string (vendor) + : empty_unibyte_string))); block_input (); terminal->next_terminal = terminal_list; terminal_list = terminal; @@ -31970,6 +32018,7 @@ too slow, which is usually true when the X server is located over a network connection with high latency. Doing so will make frame creation and placement faster at the cost of reducing the accuracy of frame placement via frame parameters, `set-frame-position', and -`set-frame-size'. */); +`set-frame-size', along with the actual state of a frame after +`x_make_frame_invisible'. */); Vx_lax_frame_positioning = Qnil; } diff --git a/src/xterm.h b/src/xterm.h index 832ffc172b9..f06e1ec5bc6 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1290,6 +1290,11 @@ struct x_output strictly an optimization to avoid extraneous synchronizing in some cases. */ int root_x, root_y; + + /* The frame visibility state. This starts out + VisibilityFullyObscured, but is set to something else in + handle_one_xevent. */ + int visibility_state; }; enum @@ -1408,6 +1413,11 @@ extern void x_mark_frame_dirty (struct frame *f); /* And its corresponding visual info. */ #define FRAME_X_VISUAL_INFO(f) (&FRAME_DISPLAY_INFO (f)->visual_info) +/* Whether or not the frame is visible. Do not test this alone. + Instead, use FRAME_REDISPLAY_P. */ +#define FRAME_X_VISIBLE(f) (FRAME_X_OUTPUT (f)->visibility_state \ + != VisibilityFullyObscured) + #ifdef HAVE_XRENDER #define FRAME_X_PICTURE_FORMAT(f) FRAME_DISPLAY_INFO (f)->pict_format #define FRAME_X_PICTURE(f) ((f)->output_data.x->picture) |