diff options
author | Andrea Corallo <akrl@sdf.org> | 2021-01-16 13:26:10 +0100 |
---|---|---|
committer | Andrea Corallo <akrl@sdf.org> | 2021-01-16 13:26:10 +0100 |
commit | 0a7ac0b5504e75275699a3d8d2d5d94bcfda8708 (patch) | |
tree | bb6158c8a9edeb1e716718abfc98dca16aef9e9e /src | |
parent | f1efac1f9efbfa15b6434ebef507c00c1277633f (diff) | |
parent | 0732fc31932c75c682c8b65b4dcb4376ca63e8fd (diff) | |
download | emacs-0a7ac0b5504e75275699a3d8d2d5d94bcfda8708.tar.gz emacs-0a7ac0b5504e75275699a3d8d2d5d94bcfda8708.tar.bz2 emacs-0a7ac0b5504e75275699a3d8d2d5d94bcfda8708.zip |
Merge remote-tracking branch 'savannah/master' into native-comp
Diffstat (limited to 'src')
-rw-r--r-- | src/buffer.c | 2 | ||||
-rw-r--r-- | src/callproc.c | 33 | ||||
-rw-r--r-- | src/data.c | 3 | ||||
-rw-r--r-- | src/dispnew.c | 16 | ||||
-rw-r--r-- | src/emacs.c | 4 | ||||
-rw-r--r-- | src/eval.c | 26 | ||||
-rw-r--r-- | src/fns.c | 85 | ||||
-rw-r--r-- | src/keymap.c | 35 | ||||
-rw-r--r-- | src/lisp.h | 8 | ||||
-rw-r--r-- | src/lread.c | 29 | ||||
-rw-r--r-- | src/minibuf.c | 211 | ||||
-rw-r--r-- | src/pdumper.c | 2 | ||||
-rw-r--r-- | src/process.c | 13 | ||||
-rw-r--r-- | src/sysdep.c | 217 | ||||
-rw-r--r-- | src/w32term.c | 3 | ||||
-rw-r--r-- | src/window.c | 5 | ||||
-rw-r--r-- | src/window.h | 4 | ||||
-rw-r--r-- | src/xdisp.c | 13 | ||||
-rw-r--r-- | src/xfaces.c | 8 |
19 files changed, 619 insertions, 98 deletions
diff --git a/src/buffer.c b/src/buffer.c index 71ad5edd527..80c799e719b 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4785,7 +4785,7 @@ mmap_init (void) if (mmap_fd <= 0) { /* No anonymous mmap -- we need the file descriptor. */ - mmap_fd = emacs_open ("/dev/zero", O_RDONLY, 0); + mmap_fd = emacs_open_noquit ("/dev/zero", O_RDONLY, 0); if (mmap_fd == -1) fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno)); } diff --git a/src/callproc.c b/src/callproc.c index 8d2a5619eb8..cb72b070b7b 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -314,6 +314,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, #ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */ char *tempfile = NULL; #else + sigset_t oldset; pid_t pid = -1; #endif int child_errno; @@ -601,9 +602,12 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, #ifndef MSDOS + block_input (); + block_child_signal (&oldset); + child_errno = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env, - SSDATA (current_dir), NULL); + SSDATA (current_dir), NULL, &oldset); eassert ((child_errno == 0) == (0 < pid)); if (pid > 0) @@ -624,6 +628,9 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, } } + unblock_child_signal (&oldset); + unblock_input (); + if (pid < 0) report_file_errno (CHILD_SETUP_ERROR_DESC, Qnil, child_errno); @@ -1227,17 +1234,21 @@ child_setup (int in, int out, int err, char **new_argv, char **env, process image file ARGV[0]. Use ENVP for the environment block for the new process. Use CWD as working directory for the new process. If PTY is not NULL, it must be a pseudoterminal device. If PTY is - NULL, don't perform any terminal setup. */ + NULL, don't perform any terminal setup. OLDSET must be a pointer + to a signal set initialized by `block_child_signal'. Before + calling this function, call `block_input' and `block_child_signal'; + afterwards, call `unblock_input' and `unblock_child_signal'. Be + sure to call `unblock_child_signal' only after registering NEWPID + in a list where `handle_child_signal' can find it! */ int emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, - char **argv, char **envp, const char *cwd, const char *pty) + char **argv, char **envp, const char *cwd, + const char *pty, const sigset_t *oldset) { - sigset_t oldset; int pid; - block_input (); - block_child_signal (&oldset); + eassert (input_blocked_p ()); #ifndef WINDOWSNT /* vfork, and prevent local vars from being clobbered by the vfork. */ @@ -1249,6 +1260,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, int volatile stdout_volatile = std_out; int volatile stderr_volatile = std_err; char **volatile envp_volatile = envp; + const sigset_t *volatile oldset_volatile = oldset; #ifdef DARWIN_OS /* Darwin doesn't let us run setsid after a vfork, so use fork when @@ -1270,6 +1282,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, std_out = stdout_volatile; std_err = stderr_volatile; envp = envp_volatile; + oldset = oldset_volatile; if (pid == 0) #endif /* not WINDOWSNT */ @@ -1323,7 +1336,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, would work? */ if (std_in >= 0) emacs_close (std_in); - std_out = std_in = emacs_open (pty, O_RDWR, 0); + std_out = std_in = emacs_open_noquit (pty, O_RDWR, 0); if (std_in < 0) { @@ -1364,7 +1377,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, #endif /* Stop blocking SIGCHLD in the child. */ - unblock_child_signal (&oldset); + unblock_child_signal (oldset); if (pty_flag) child_setup_tty (std_out); @@ -1382,10 +1395,6 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, int vfork_error = pid < 0 ? errno : 0; - /* Stop blocking in the parent. */ - unblock_child_signal (&oldset); - unblock_input (); - if (pid < 0) { eassert (0 < vfork_error); diff --git a/src/data.c b/src/data.c index 3cf5bbbdd56..0dc21c8c2a1 100644 --- a/src/data.c +++ b/src/data.c @@ -3834,6 +3834,7 @@ syms_of_data (void) DEFSYM (Qbuffer_read_only, "buffer-read-only"); DEFSYM (Qtext_read_only, "text-read-only"); DEFSYM (Qmark_inactive, "mark-inactive"); + DEFSYM (Qinhibited_interaction, "inhibited-interaction"); DEFSYM (Qlistp, "listp"); DEFSYM (Qconsp, "consp"); @@ -3918,6 +3919,8 @@ syms_of_data (void) PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only"); PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail), "Text is read-only"); + PUT_ERROR (Qinhibited_interaction, error_tail, + "User interaction while inhibited"); DEFSYM (Qrange_error, "range-error"); DEFSYM (Qdomain_error, "domain-error"); diff --git a/src/dispnew.c b/src/dispnew.c index 36a6dd8a091..e603c671363 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6049,7 +6049,14 @@ additional wait period, in milliseconds; this is for backwards compatibility. READING is true if reading input. If DISPLAY_OPTION is >0 display process output while waiting. If DISPLAY_OPTION is >1 perform an initial redisplay before waiting. -*/ + + Returns a boolean Qt if we waited the full time and returns Qnil if the + wait was interrupted by incoming process output or keyboard events. + + FIXME: When `wait_reading_process_output` returns early because of + process output, instead of returning nil we should loop and wait some + more (i.e. until either there's pending input events or the timeout + expired). */ Lisp_Object sit_for (Lisp_Object timeout, bool reading, int display_option) @@ -6110,8 +6117,9 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) gobble_input (); #endif - wait_reading_process_output (sec, nsec, reading ? -1 : 1, do_display, - Qnil, NULL, 0); + int nbytes + = wait_reading_process_output (sec, nsec, reading ? -1 : 1, do_display, + Qnil, NULL, 0); if (reading && curbuf_eq_winbuf) /* Timers and process filters/sentinels may have changed the selected @@ -6120,7 +6128,7 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) buffer to start with). */ set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents)); - return detect_input_pending () ? Qnil : Qt; + return (nbytes > 0 || detect_input_pending ()) ? Qnil : Qt; } diff --git a/src/emacs.c b/src/emacs.c index 738ef12c98c..c6581bba37e 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1300,7 +1300,7 @@ main (int argc, char **argv) { emacs_close (STDIN_FILENO); emacs_close (STDOUT_FILENO); - int result = emacs_open (term, O_RDWR, 0); + int result = emacs_open_noquit (term, O_RDWR, 0); if (result != STDIN_FILENO || (fcntl (STDIN_FILENO, F_DUPFD_CLOEXEC, STDOUT_FILENO) != STDOUT_FILENO)) @@ -2884,7 +2884,7 @@ from the parent process and its tty file descriptors. */) int nfd; /* Get rid of stdin, stdout and stderr. */ - nfd = emacs_open ("/dev/null", O_RDWR, 0); + nfd = emacs_open_noquit ("/dev/null", O_RDWR, 0); err |= nfd < 0; err |= dup2 (nfd, STDIN_FILENO) < 0; err |= dup2 (nfd, STDOUT_FILENO) < 0; diff --git a/src/eval.c b/src/eval.c index f77f07e1711..cef9407dbfa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1176,9 +1176,18 @@ Lisp_Object internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) { + /* MINIBUFFER_QUIT_LEVEL is to handle quitting from nested minibuffers by + throwing t to tag `exit'. + Value -1 means there is no (throw 'exit t) in progress; + 0 means the `throw' wasn't done from an active minibuffer; + N > 0 means the `throw' was done from the minibuffer at level N. */ + static EMACS_INT minibuffer_quit_level = -1; /* This structure is made part of the chain `catchlist'. */ struct handler *c = push_handler (tag, CATCHER); + if (EQ (tag, Qexit)) + minibuffer_quit_level = -1; + /* Call FUNC. */ if (! sys_setjmp (c->jmp)) { @@ -1192,6 +1201,23 @@ internal_catch (Lisp_Object tag, Lisp_Object val = handlerlist->val; clobbered_eassert (handlerlist == c); handlerlist = handlerlist->next; + if (EQ (tag, Qexit) && EQ (val, Qt)) + /* If we've thrown t to tag `exit' from within a minibuffer, we + exit all minibuffers more deeply nested than the current + one. */ + { + EMACS_INT mini_depth = this_minibuffer_depth (Qnil); + if (mini_depth && mini_depth != minibuffer_quit_level) + { + if (minibuffer_quit_level == -1) + minibuffer_quit_level = mini_depth; + if (minibuffer_quit_level + && (minibuf_level > minibuffer_quit_level)) + Fthrow (Qexit, Qt); + } + else + minibuffer_quit_level = -1; + } return val; } } diff --git a/src/fns.c b/src/fns.c index 5fcc54f0d1f..7ab2e8f1a03 100644 --- a/src/fns.c +++ b/src/fns.c @@ -5548,6 +5548,90 @@ It should not be used for anything security-related. See return make_digest_string (digest, SHA1_DIGEST_SIZE); } +DEFUN ("buffer-line-statistics", Fbuffer_line_statistics, + Sbuffer_line_statistics, 0, 1, 0, + doc: /* Return data about lines in BUFFER. +The data is returned as a list, and the first element is the number of +lines in the buffer, the second is the length of the longest line, and +the third is the mean line length. The lengths returned are in bytes, not +characters. */ ) + (Lisp_Object buffer_or_name) +{ + Lisp_Object buffer; + ptrdiff_t lines = 0, longest = 0; + double mean = 0; + struct buffer *b; + + if (NILP (buffer_or_name)) + buffer = Fcurrent_buffer (); + else + buffer = Fget_buffer (buffer_or_name); + if (NILP (buffer)) + nsberror (buffer_or_name); + + b = XBUFFER (buffer); + + unsigned char *start = BUF_BEG_ADDR (b); + ptrdiff_t area = BUF_GPT_BYTE (b) - BUF_BEG_BYTE (b), pre_gap = 0; + + /* Process the first part of the buffer. */ + while (area > 0) + { + unsigned char *n = memchr (start, '\n', area); + + if (n) + { + ptrdiff_t this_line = n - start; + if (this_line > longest) + longest = this_line; + lines++; + /* Blame Knuth. */ + mean = mean + (this_line - mean) / lines; + area = area - this_line - 1; + start += this_line + 1; + } + else + { + /* Didn't have a newline here, so save the rest for the + post-gap calculation. */ + pre_gap = area; + area = 0; + } + } + + /* If the gap is before the end of the buffer, process the last half + of the buffer. */ + if (BUF_GPT_BYTE (b) < BUF_Z_BYTE (b)) + { + start = BUF_GAP_END_ADDR (b); + area = BUF_Z_ADDR (b) - BUF_GAP_END_ADDR (b); + + while (area > 0) + { + unsigned char *n = memchr (start, '\n', area); + ptrdiff_t this_line = n? n - start + pre_gap: area + pre_gap; + + if (this_line > longest) + longest = this_line; + lines++; + /* Blame Knuth again. */ + mean = mean + (this_line - mean) / lines; + area = area - this_line - 1; + start += this_line + 1; + pre_gap = 0; + } + } + else if (pre_gap > 0) + { + if (pre_gap > longest) + longest = pre_gap; + lines++; + mean = mean + (pre_gap - mean) / lines; + } + + return list3 (make_int (lines), make_int (longest), make_float (mean)); +} + static bool string_ascii_p (Lisp_Object string) { @@ -5871,4 +5955,5 @@ this variable. */); defsubr (&Ssecure_hash); defsubr (&Sbuffer_hash); defsubr (&Slocale_info); + defsubr (&Sbuffer_line_statistics); } diff --git a/src/keymap.c b/src/keymap.c index 1197f6fd4a5..de9b2b58c5e 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -1646,39 +1646,6 @@ specified buffer position instead of point are used. /* GC is possible in this function if it autoloads a keymap. */ -DEFUN ("local-key-binding", Flocal_key_binding, Slocal_key_binding, 1, 2, 0, - doc: /* Return the binding for command KEYS in current local keymap only. -KEYS is a string or vector, a sequence of keystrokes. -The binding is probably a symbol with a function definition. - -If optional argument ACCEPT-DEFAULT is non-nil, recognize default -bindings; see the description of `lookup-key' for more details about this. */) - (Lisp_Object keys, Lisp_Object accept_default) -{ - register Lisp_Object map = BVAR (current_buffer, keymap); - if (NILP (map)) - return Qnil; - return Flookup_key (map, keys, accept_default); -} - -/* GC is possible in this function if it autoloads a keymap. */ - -DEFUN ("global-key-binding", Fglobal_key_binding, Sglobal_key_binding, 1, 2, 0, - doc: /* Return the binding for command KEYS in current global keymap only. -KEYS is a string or vector, a sequence of keystrokes. -The binding is probably a symbol with a function definition. -This function's return values are the same as those of `lookup-key' -\(which see). - -If optional argument ACCEPT-DEFAULT is non-nil, recognize default -bindings; see the description of `lookup-key' for more details about this. */) - (Lisp_Object keys, Lisp_Object accept_default) -{ - return Flookup_key (current_global_map, keys, accept_default); -} - -/* GC is possible in this function if it autoloads a keymap. */ - DEFUN ("minor-mode-key-binding", Fminor_mode_key_binding, Sminor_mode_key_binding, 1, 2, 0, doc: /* Find the visible minor mode bindings of KEY. Return an alist of pairs (MODENAME . BINDING), where MODENAME is @@ -3253,8 +3220,6 @@ be preferred. */); defsubr (&Scopy_keymap); defsubr (&Scommand_remapping); defsubr (&Skey_binding); - defsubr (&Slocal_key_binding); - defsubr (&Sglobal_key_binding); defsubr (&Sminor_mode_key_binding); defsubr (&Sdefine_key); defsubr (&Slookup_key); diff --git a/src/lisp.h b/src/lisp.h index b6182c37eed..296f9af7337 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4368,9 +4368,12 @@ extern Lisp_Object Vminibuffer_list; extern Lisp_Object last_minibuf_string; extern void move_minibuffer_onto_frame (void); extern bool is_minibuffer (EMACS_INT, Lisp_Object); +extern EMACS_INT this_minibuffer_depth (Lisp_Object); +extern EMACS_INT minibuf_level; extern Lisp_Object get_minibuffer (EMACS_INT); extern void init_minibuf_once (void); extern void syms_of_minibuf (void); +extern void barf_if_interaction_inhibited (void); /* Defined in callint.c. */ @@ -4518,8 +4521,8 @@ extern void setup_process_coding_systems (Lisp_Object); # define CHILD_SETUP_ERROR_DESC "Doing vfork" #endif -extern int emacs_spawn (pid_t *, int, int, int, char **, char **, const char *, - const char *); +extern int emacs_spawn (pid_t *, int, int, int, char **, char **, + const char *, const char *, const sigset_t *); extern char **make_environment_block (Lisp_Object); extern void init_callproc_1 (void); extern void init_callproc (void); @@ -4598,6 +4601,7 @@ extern AVOID emacs_abort (void) NO_INLINE; extern int emacs_fstatat (int, char const *, void *, int); extern int emacs_openat (int, char const *, int, int); extern int emacs_open (const char *, int, int); +extern int emacs_open_noquit (const char *, int, int); extern int emacs_pipe (int[2]); extern int emacs_close (int); extern ptrdiff_t emacs_read (int, void *, ptrdiff_t); diff --git a/src/lread.c b/src/lread.c index e308fa88699..4cf4f8cde9b 100644 --- a/src/lread.c +++ b/src/lread.c @@ -767,11 +767,16 @@ is used for reading a character. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { Lisp_Object val; + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); val = read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds); @@ -782,6 +787,12 @@ floating-point value. */) DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0, doc: /* Read an event object from the input stream. + +If you want to read non-character events, consider calling `read-key' +instead. `read-key' will decode events via `input-decode-map' that +`read-event' will not. On a terminal this includes function keys such +as <F7> and <RIGHT>, or mouse events generated by `xterm-mouse-mode'. + If the optional argument PROMPT is non-nil, display that as a prompt. If PROMPT is nil or the string \"\", the key sequence/events that led to the current command is used as the prompt. @@ -793,9 +804,14 @@ is used for reading a character. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method), seconds); @@ -822,11 +838,16 @@ is used for reading a character. If the optional argument SECONDS is non-nil, it should be a number specifying the maximum number of seconds to wait for input. If no input arrives in that time, return nil. SECONDS may be a -floating-point value. */) - (Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) +floating-point value. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) +(Lisp_Object prompt, Lisp_Object inherit_input_method, Lisp_Object seconds) { Lisp_Object val; + barf_if_interaction_inhibited (); + if (! NILP (prompt)) message_with_string ("%s", prompt, 0); diff --git a/src/minibuf.c b/src/minibuf.c index 5ee440f6622..5df10453739 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -63,10 +63,31 @@ static Lisp_Object minibuf_prompt; static ptrdiff_t minibuf_prompt_width; +static Lisp_Object nth_minibuffer (EMACS_INT depth); + +/* Return TRUE when a frame switch causes a minibuffer on the old + frame to move onto the new one. */ static bool minibuf_follows_frame (void) { + return EQ (Fdefault_toplevel_value (Qminibuffer_follows_selected_frame), + Qt); +} + +/* Return TRUE when a minibuffer always remains on the frame where it + was first invoked. */ +static bool +minibuf_stays_put (void) +{ + return NILP (Fdefault_toplevel_value (Qminibuffer_follows_selected_frame)); +} + +/* Return TRUE when opening a (recursive) minibuffer causes + minibuffers on other frames to move to the selected frame. */ +static bool +minibuf_moves_frame_when_opened (void) +{ return !NILP (Fdefault_toplevel_value (Qminibuffer_follows_selected_frame)); } @@ -90,7 +111,7 @@ choose_minibuf_frame (void) minibuf_window = sf->minibuffer_window; /* If we've still got another minibuffer open, use its mini-window instead. */ - if (minibuf_level && !minibuf_follows_frame ()) + if (minibuf_level > 1 && minibuf_stays_put ()) { Lisp_Object buffer = get_minibuffer (minibuf_level); Lisp_Object tail, frame; @@ -105,26 +126,40 @@ choose_minibuf_frame (void) } } - if (minibuf_follows_frame ()) + if (minibuf_moves_frame_when_opened () + && FRAMEP (selected_frame) + && FRAME_LIVE_P (XFRAME (selected_frame))) /* Make sure no other frame has a minibuffer as its selected window, because the text would not be displayed in it, and that would be confusing. Only allow the selected frame to do this, and that only if the minibuffer is active. */ - { - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (XFRAME (frame)))) - && !(EQ (frame, selected_frame) - && minibuf_level > 0)) - Fset_frame_selected_window (frame, Fframe_first_window (frame), - Qnil); - } + { + Lisp_Object tail, frame; + struct frame *of; + + FOR_EACH_FRAME (tail, frame) + if (!EQ (frame, selected_frame) + && minibuf_level > 1 + /* The frame's minibuffer can be on a different frame. */ + && ! EQ (XWINDOW ((of = XFRAME (frame))->minibuffer_window)->frame, + selected_frame)) + { + if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of)))) + Fset_frame_selected_window (frame, Fframe_first_window (frame), + Qnil); + + if (!EQ (XWINDOW (of->minibuffer_window)->contents, + nth_minibuffer (0))) + set_window_buffer (of->minibuffer_window, + nth_minibuffer (0), 0, 0); + } + } } -/* If `minibuffer_follows_selected_frame' and we have a minibuffer, move it - from its current frame to the selected frame. This function is - intended to be called from `do_switch_frame' in frame.c. */ +/* If `minibuffer_follows_selected_frame' is t and we have a + minibuffer, move it from its current frame to the selected frame. + This function is intended to be called from `do_switch_frame' in + frame.c. */ void move_minibuffer_onto_frame (void) { if (!minibuf_level) @@ -135,14 +170,18 @@ void move_minibuffer_onto_frame (void) && FRAME_LIVE_P (XFRAME (selected_frame)) && !EQ (minibuf_window, XFRAME (selected_frame)->minibuffer_window)) { + EMACS_INT i; struct frame *sf = XFRAME (selected_frame); Lisp_Object old_frame = XWINDOW (minibuf_window)->frame; struct frame *of = XFRAME (old_frame); - Lisp_Object buffer = XWINDOW (minibuf_window)->contents; - set_window_buffer (sf->minibuffer_window, buffer, 0, 0); + /* Stack up all the (recursively) open minibuffers on the selected + mini_window. */ + for (i = 1; i <= minibuf_level; i++) + set_window_buffer (sf->minibuffer_window, nth_minibuffer (i), 0, 0); minibuf_window = sf->minibuffer_window; - set_window_buffer (of->minibuffer_window, get_minibuffer (0), 0, 0); + if (of != sf) + set_window_buffer (of->minibuffer_window, get_minibuffer (0), 0, 0); } } @@ -336,6 +375,63 @@ return t only if BUFFER is an active minibuffer. */) ? Qt : Qnil; } +DEFUN ("innermost-minibuffer-p", Finnermost_minibuffer_p, + Sinnermost_minibuffer_p, 0, 1, 0, + doc: /* Return t if BUFFER is the most nested active minibuffer. +No argument or nil as argument means use the current buffer as BUFFER. */) + (Lisp_Object buffer) +{ + if (NILP (buffer)) + buffer = Fcurrent_buffer (); + return EQ (buffer, (Fcar (Fnthcdr (make_fixnum (minibuf_level), + Vminibuffer_list)))) + ? Qt + : Qnil; +} + +/* Return the nesting depth of the active minibuffer BUFFER, or 0 if + BUFFER isn't such a thing. If BUFFER is nil, this means use the current + buffer. */ +EMACS_INT +this_minibuffer_depth (Lisp_Object buffer) +{ + EMACS_INT i; + Lisp_Object bufs; + + if (NILP (buffer)) + buffer = Fcurrent_buffer (); + for (i = 1, bufs = Fcdr (Vminibuffer_list); + i <= minibuf_level; + i++, bufs = Fcdr (bufs)) + if (EQ (Fcar (bufs), buffer)) + return i; + return 0; +} + +DEFUN ("abort-minibuffers", Fabort_minibuffers, Sabort_minibuffers, 0, 0, "", + doc: /* Abort the current minibuffer. +If we are not currently in the innermost minibuffer, prompt the user to +confirm the aborting of the current minibuffer and all contained ones. */) + (void) +{ + EMACS_INT minibuf_depth = this_minibuffer_depth (Qnil); + Lisp_Object array[2]; + AUTO_STRING (fmt, "Abort %s minibuffer levels? "); + + if (!minibuf_depth) + error ("Not in a minibuffer"); + if (minibuf_depth < minibuf_level) + { + array[0] = fmt; + array[1] = make_fixnum (minibuf_level - minibuf_depth + 1); + if (!NILP (Fyes_or_no_p (Fformat (2, array)))) + Fthrow (Qexit, Qt); + } + else + Fthrow (Qexit, Qt); + return Qnil; +} + DEFUN ("minibuffer-prompt-end", Fminibuffer_prompt_end, Sminibuffer_prompt_end, 0, 0, 0, doc: /* Return the buffer position of the end of the minibuffer prompt. @@ -411,6 +507,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, Lisp_Object val; ptrdiff_t count = SPECPDL_INDEX (); Lisp_Object mini_frame, ambient_dir, minibuffer, input_method; + Lisp_Object calling_frame = selected_frame; Lisp_Object enable_multibyte; EMACS_INT pos = 0; /* String to add to the history. */ @@ -648,6 +745,17 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, } } + if (minibuf_moves_frame_when_opened ()) + { + EMACS_INT i; + + /* Stack up all the (recursively) open minibuffers on the selected + mini_window. */ + for (i = 1; i < minibuf_level; i++) + set_window_buffer (XFRAME (mini_frame)->minibuffer_window, + nth_minibuffer (i), 0, 0); + } + /* Display this minibuffer in the proper window. */ /* Use set_window_buffer instead of Fset_window_buffer (see discussion of bug#11984, bug#12025, bug#12026). */ @@ -729,6 +837,20 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, recursive_edit_1 (); + /* We've exited the recursive edit without an error, so switch the + current window away from the expired minibuffer window. */ + { + Lisp_Object prev = Fprevious_window (minibuf_window, Qnil, Qnil); + /* PREV can be on a different frame when we have a minibuffer only + frame, the other frame's minibuffer window is MINIBUF_WINDOW, + and its "focus window" is also MINIBUF_WINDOW. */ + while (!EQ (prev, minibuf_window) + && !EQ (selected_frame, WINDOW_FRAME (XWINDOW (prev)))) + prev = Fprevious_window (prev, Qnil, Qnil); + if (!EQ (prev, minibuf_window)) + Fset_frame_selected_window (selected_frame, prev, Qnil); + } + /* If cursor is on the minibuffer line, show the user we have exited by putting it in column 0. */ if (XWINDOW (minibuf_window)->cursor.vpos >= 0 @@ -767,6 +889,12 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, in set-window-configuration. */ unbind_to (count, Qnil); + /* Switch the frame back to the calling frame. */ + if (!EQ (selected_frame, calling_frame) + && FRAMEP (calling_frame) + && FRAME_LIVE_P (XFRAME (calling_frame))) + call2 (intern ("select-frame-set-input-focus"), calling_frame, Qnil); + /* Add the value to the appropriate history list, if any. This is done after the previous buffer has been made current again, in case the history variable is buffer-local. */ @@ -790,6 +918,14 @@ is_minibuffer (EMACS_INT depth, Lisp_Object buf) && EQ (Fcar (tail), buf); } +/* Return the DEPTHth minibuffer, or nil if such does not yet exist. */ +static Lisp_Object +nth_minibuffer (EMACS_INT depth) +{ + Lisp_Object tail = Fnthcdr (make_fixnum (depth), Vminibuffer_list); + return XCAR (tail); +} + /* Return a buffer to be used as the minibuffer at depth `depth'. depth = 0 is the lowest allowed argument, and that is the value used for nonrecursive minibuffer invocations. */ @@ -939,6 +1075,13 @@ read_minibuf_unwind (void) } +void +barf_if_interaction_inhibited (void) +{ + if (inhibit_interaction) + xsignal0 (Qinhibited_interaction); +} + DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Sread_from_minibuffer, 1, 7, 0, doc: /* Read a string from the minibuffer, prompting with string PROMPT. @@ -983,6 +1126,9 @@ If the variable `minibuffer-allow-text-properties' is non-nil, then the string which is returned includes whatever text properties were present in the minibuffer. Otherwise the value has no text properties. +If `inhibit-interaction' is non-nil, this function will signal an + `inhibited-interaction' error. + The remainder of this documentation string describes the INITIAL-CONTENTS argument in more detail. It is only relevant when studying existing code, or when HIST is a cons. If non-nil, @@ -998,6 +1144,8 @@ and some related functions, which use zero-indexing for POSITION. */) { Lisp_Object histvar, histpos, val; + barf_if_interaction_inhibited (); + CHECK_STRING (prompt); if (NILP (keymap)) keymap = Vminibuffer_local_map; @@ -1071,11 +1219,17 @@ point positioned at the end, so that SPACE will accept the input. \(Actually, INITIAL can also be a cons of a string and an integer. Such values are treated as in `read-from-minibuffer', but are normally not useful in this function.) + Third arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits -the current input method and the setting of`enable-multibyte-characters'. */) +the current input method and the setting of`enable-multibyte-characters'. + +If `inhibit-interaction' is non-nil, this function will signal an +`inhibited-interaction' error. */) (Lisp_Object prompt, Lisp_Object initial, Lisp_Object inherit_input_method) { CHECK_STRING (prompt); + barf_if_interaction_inhibited (); + return read_minibuf (Vminibuffer_local_ns_map, initial, prompt, 0, Qminibuffer_history, make_fixnum (0), Qnil, 0, !NILP (inherit_input_method)); @@ -2032,13 +2186,15 @@ For example, `eval-expression' uses this. */); The function is called with the arguments passed to `read-buffer'. */); Vread_buffer_function = Qnil; - DEFVAR_BOOL ("minibuffer-follows-selected-frame", minibuffer_follows_selected_frame, - doc: /* Non-nil means the active minibuffer always displays on the selected frame. + DEFVAR_LISP ("minibuffer-follows-selected-frame", minibuffer_follows_selected_frame, + doc: /* t means the active minibuffer always displays on the selected frame. Nil means that a minibuffer will appear only in the frame which created it. +Any other value means the minibuffer will move onto another frame, but +only when the user starts using a minibuffer there. Any buffer local or dynamic binding of this variable is ignored. Only the default top level value is used. */); - minibuffer_follows_selected_frame = 1; + minibuffer_follows_selected_frame = Qt; DEFVAR_BOOL ("read-buffer-completion-ignore-case", read_buffer_completion_ignore_case, @@ -2183,6 +2339,15 @@ This variable also overrides the default character that `read-passwd' uses to hide passwords. */); Vread_hide_char = Qnil; + DEFVAR_BOOL ("inhibit-interaction", + inhibit_interaction, + doc: /* Non-nil means any user interaction will signal an error. +This variable can be bound when user interaction can't be performed, +for instance when running a headless Emacs server. Functions like +`read-from-minibuffer' (and the like) will signal `inhibited-interaction' +instead. */); + inhibit_interaction = 0; + defsubr (&Sactive_minibuffer_window); defsubr (&Sset_minibuffer_window); defsubr (&Sread_from_minibuffer); @@ -2196,6 +2361,8 @@ uses to hide passwords. */); defsubr (&Sminibuffer_prompt); defsubr (&Sminibufferp); + defsubr (&Sinnermost_minibuffer_p); + defsubr (&Sabort_minibuffers); defsubr (&Sminibuffer_prompt_end); defsubr (&Sminibuffer_contents); defsubr (&Sminibuffer_contents_no_properties); diff --git a/src/pdumper.c b/src/pdumper.c index 7eefcc83fda..f0711078a5a 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -5460,7 +5460,7 @@ pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd) eassert (!dump_loaded_p ()); int err; - int dump_fd = emacs_open (dump_filename, O_RDONLY, 0); + int dump_fd = emacs_open_noquit (dump_filename, O_RDONLY, 0); if (dump_fd < 0) { err = (errno == ENOENT || errno == ENOTDIR diff --git a/src/process.c b/src/process.c index 06d750d3368..dac7d0440fa 100644 --- a/src/process.c +++ b/src/process.c @@ -692,8 +692,7 @@ status_convert (int w) if (WIFSTOPPED (w)) return Fcons (Qstop, Fcons (make_fixnum (WSTOPSIG (w)), Qnil)); else if (WIFEXITED (w)) - return Fcons (Qexit, Fcons (make_fixnum (WEXITSTATUS (w)), - WCOREDUMP (w) ? Qt : Qnil)); + return Fcons (Qexit, Fcons (make_fixnum (WEXITSTATUS (w)), Qnil)); else if (WIFSIGNALED (w)) return Fcons (Qsignal, Fcons (make_fixnum (WTERMSIG (w)), WCOREDUMP (w) ? Qt : Qnil)); @@ -2059,6 +2058,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) bool pty_flag = 0; char pty_name[PTY_NAME_SIZE]; Lisp_Object lisp_pty_name = Qnil; + sigset_t oldset; inchannel = outchannel = -1; @@ -2139,13 +2139,16 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) setup_process_coding_systems (process); char **env = make_environment_block (current_dir); + block_input (); + block_child_signal (&oldset); + pty_flag = p->pty_flag; eassert (pty_flag == ! NILP (lisp_pty_name)); vfork_errno = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env, SSDATA (current_dir), - pty_flag ? SSDATA (lisp_pty_name) : NULL); + pty_flag ? SSDATA (lisp_pty_name) : NULL, &oldset); eassert ((vfork_errno == 0) == (0 < pid)); @@ -2153,6 +2156,10 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) if (pid >= 0) p->alive = 1; + /* Stop blocking in the parent. */ + unblock_child_signal (&oldset); + unblock_input (); + /* Environment block no longer needed. */ unbind_to (count, Qnil); diff --git a/src/sysdep.c b/src/sysdep.c index 6ede06b1aa3..941b4e2fa24 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -53,6 +53,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ # include <sys/sysctl.h> #endif +#if defined __OpenBSD__ +# include <sys/proc.h> +#endif + #ifdef DARWIN_OS # include <libproc.h> #endif @@ -2316,6 +2320,28 @@ emacs_open (char const *file, int oflags, int mode) return emacs_openat (AT_FDCWD, file, oflags, mode); } +/* Same as above, but doesn't allow the user to quit. */ + +static int +emacs_openat_noquit (int dirfd, const char *file, int oflags, + int mode) +{ + int fd; + if (! (oflags & O_TEXT)) + oflags |= O_BINARY; + oflags |= O_CLOEXEC; + do + fd = openat (dirfd, file, oflags, mode); + while (fd < 0 && errno == EINTR); + return fd; +} + +int +emacs_open_noquit (char const *file, int oflags, int mode) +{ + return emacs_openat_noquit (AT_FDCWD, file, oflags, mode); +} + /* Open FILE as a stream for Emacs use, with mode MODE. Act like emacs_open with respect to threads, signals, and quits. */ @@ -2972,6 +2998,14 @@ make_lisp_timeval (struct timeval t) return make_lisp_time (timeval_to_timespec (t)); } +#elif defined __OpenBSD__ + +static Lisp_Object +make_lisp_timeval (long sec, long usec) +{ + return make_lisp_time(make_timespec(sec, usec * 1000)); +} + #endif #ifdef GNU_LINUX @@ -3661,6 +3695,189 @@ system_process_attributes (Lisp_Object pid) return attrs; } +#elif defined __OpenBSD__ + +Lisp_Object +system_process_attributes (Lisp_Object pid) +{ + int proc_id, nentries, fscale, i; + int pagesize = getpagesize (); + int mib[6]; + size_t len; + double pct; + char *ttyname, args[ARG_MAX]; + struct kinfo_proc proc; + struct passwd *pw; + struct group *gr; + struct timespec t; + struct uvmexp uvmexp; + + Lisp_Object attrs = Qnil; + Lisp_Object decoded_comm; + + CHECK_NUMBER (pid); + CONS_TO_INTEGER (pid, int, proc_id); + + len = sizeof proc; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = proc_id; + mib[4] = len; + mib[5] = 1; + if (sysctl (mib, 6, &proc, &len, NULL, 0) != 0) + return attrs; + + attrs = Fcons (Fcons (Qeuid, INT_TO_INTEGER (proc.p_uid)), attrs); + + block_input (); + pw = getpwuid (proc.p_uid); + unblock_input (); + if (pw) + attrs = Fcons (Fcons (Quser, build_string(pw->pw_name)), attrs); + + attrs = Fcons (Fcons (Qegid, INT_TO_INTEGER(proc.p_svgid)), attrs); + + block_input (); + gr = getgrgid (proc.p_svgid); + unblock_input (); + if (gr) + attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + + AUTO_STRING (comm, proc.p_comm); + decoded_comm = code_convert_string_norecord (comm, Vlocale_coding_system, 0); + attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs); + + { + char state[2] = {'\0', '\0'}; + switch (proc.p_stat) { + case SIDL: + state[0] = 'I'; + break; + case SRUN: + state[0] = 'R'; + break; + case SSLEEP: + state[0] = 'S'; + break; + case SSTOP: + state[0] = 'T'; + break; + case SZOMB: + state[0] = 'Z'; + break; + case SDEAD: + state[0] = 'D'; + break; + } + attrs = Fcons (Fcons (Qstate, build_string (state)), attrs); + } + + attrs = Fcons (Fcons (Qppid, INT_TO_INTEGER (proc.p_ppid)), attrs); + attrs = Fcons (Fcons (Qpgrp, INT_TO_INTEGER (proc.p_gid)), attrs); + attrs = Fcons (Fcons (Qsess, INT_TO_INTEGER (proc.p_sid)), attrs); + + block_input (); + ttyname = proc.p_tdev == NODEV ? NULL : devname (proc.p_tdev, S_IFCHR); + unblock_input (); + if (ttyname) + attrs = Fcons (Fcons (Qttname, build_string (ttyname)), attrs); + + attrs = Fcons (Fcons (Qtpgid, INT_TO_INTEGER (proc.p_tpgid)), attrs); + attrs = Fcons (Fcons (Qminflt, INT_TO_INTEGER (proc.p_uru_minflt)), + attrs); + attrs = Fcons (Fcons (Qmajflt, INT_TO_INTEGER (proc.p_uru_majflt)), + attrs); + + /* FIXME: missing cminflt, cmajflt. */ + + attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc.p_uutime_sec, + proc.p_uutime_usec)), + attrs); + attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.p_ustime_sec, + proc.p_ustime_usec)), + attrs); + t = timespec_add (make_timespec (proc.p_uutime_sec, + proc.p_uutime_usec * 1000), + make_timespec (proc.p_ustime_sec, + proc.p_ustime_usec * 1000)); + attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs); + + attrs = Fcons (Fcons (Qcutime, make_lisp_timeval (proc.p_uctime_sec, + proc.p_uctime_usec)), + attrs); + + /* FIXME: missing cstime and thus ctime. */ + + attrs = Fcons (Fcons (Qpri, make_fixnum (proc.p_priority)), attrs); + attrs = Fcons (Fcons (Qnice, make_fixnum (proc.p_nice)), attrs); + + /* FIXME: missing thcount (thread count) */ + + attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc.p_ustart_sec, + proc.p_ustart_usec)), + attrs); + + len = (proc.p_vm_tsize + proc.p_vm_dsize + proc.p_vm_ssize) * pagesize >> 10; + attrs = Fcons (Fcons (Qvsize, make_fixnum (len)), attrs); + + attrs = Fcons (Fcons (Qrss, make_fixnum (proc.p_vm_rssize * pagesize >> 10)), + attrs); + + t = make_timespec (proc.p_ustart_sec, + proc.p_ustart_usec * 1000); + t = timespec_sub (current_timespec (), t); + attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); + + len = sizeof (fscale); + mib[0] = CTL_KERN; + mib[1] = KERN_FSCALE; + if (sysctl (mib, 2, &fscale, &len, NULL, 0) != -1) + { + pct = (double)proc.p_pctcpu / fscale * 100.0; + attrs = Fcons (Fcons (Qpcpu, make_float (pct)), attrs); + } + + len = sizeof (uvmexp); + mib[0] = CTL_VM; + mib[1] = VM_UVMEXP; + if (sysctl (mib, 2, &uvmexp, &len, NULL, 0) != -1) + { + pct = (100.0 * (double)proc.p_vm_rssize / uvmexp.npages); + attrs = Fcons (Fcons (Qpmem, make_float (pct)), attrs); + } + + len = sizeof args; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = proc_id; + mib[3] = KERN_PROC_ARGV; + if (sysctl (mib, 4, &args, &len, NULL, 0) == 0 && len != 0) + { + char **argv = (char**)args; + + /* concatenate argv reusing the existing storage storage. + sysctl(8) guarantees that "the buffer pointed to by oldp is + filled with an array of char pointers followed by the strings + themselves." */ + for (i = 0; argv[i] != NULL; ++i) + { + if (argv[i+1] != NULL) + { + len = strlen (argv[i]); + argv[i][len] = ' '; + } + } + + AUTO_STRING (comm, *argv); + decoded_comm = code_convert_string_norecord (comm, + Vlocale_coding_system, 0); + attrs = Fcons (Fcons (Qargs, decoded_comm), attrs); + } + + return attrs; +} + #elif defined DARWIN_OS Lisp_Object diff --git a/src/w32term.c b/src/w32term.c index e5a8a823b48..109aa58d732 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -7507,7 +7507,8 @@ w32_initialize (void) } #ifdef CYGWIN - if ((w32_message_fd = emacs_open ("/dev/windows", O_RDWR, 0)) == -1) + if ((w32_message_fd = emacs_open_noquit ("/dev/windows", O_RDWR, 0)) + == -1) fatal ("opening /dev/windows: %s", strerror (errno)); #endif /* CYGWIN */ diff --git a/src/window.c b/src/window.c index 5e78aa400b5..e025e0b0821 100644 --- a/src/window.c +++ b/src/window.c @@ -2663,12 +2663,15 @@ static void decode_next_window_args (Lisp_Object *window, Lisp_Object *minibuf, Lisp_Object *all_frames) { struct window *w = decode_live_window (*window); + Lisp_Object miniwin = XFRAME (w->frame)->minibuffer_window; XSETWINDOW (*window, w); /* MINIBUF nil may or may not include minibuffers. Decide if it does. */ if (NILP (*minibuf)) - *minibuf = minibuf_level ? minibuf_window : Qlambda; + *minibuf = this_minibuffer_depth (XWINDOW (miniwin)->contents) + ? miniwin + : Qlambda; else if (!EQ (*minibuf, Qt)) *minibuf = Qlambda; diff --git a/src/window.h b/src/window.h index 332cb3091fd..79eb44e7a38 100644 --- a/src/window.h +++ b/src/window.h @@ -1124,10 +1124,6 @@ extern Lisp_Object echo_area_window; extern EMACS_INT command_loop_level; -/* Depth in minibuffer invocations. */ - -extern EMACS_INT minibuf_level; - /* Non-zero if we should redraw the mode lines on the next redisplay. Usually set to a unique small integer so we can track the main causes of full redisplays in `redisplay--mode-lines-cause'. */ diff --git a/src/xdisp.c b/src/xdisp.c index 6a4304d194b..ea67329cff1 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -9285,8 +9285,8 @@ move_it_in_display_line_to (struct it *it, if (may_wrap && char_can_wrap_before (it)) { /* We have reached a glyph that follows one or more - whitespace characters or a character that allows - wrapping after it. If this character allows + whitespace characters or characters that allow + wrapping after them. If this character allows wrapping before it, save this position as a wrapping point. */ if (atpos_it.sp >= 0) @@ -9303,7 +9303,6 @@ move_it_in_display_line_to (struct it *it, } /* Otherwise, we can wrap here. */ SAVE_IT (wrap_it, *it, wrap_data); - next_may_wrap = false; } /* Update may_wrap for the next iteration. */ may_wrap = next_may_wrap; @@ -10650,9 +10649,10 @@ include the height of both, if present, in the return value. */) bpos = BEGV_BYTE; while (bpos < ZV_BYTE) { - c = fetch_char_advance (&start, &bpos); + c = FETCH_BYTE (bpos); if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) break; + inc_both (&start, &bpos); } while (bpos > BEGV_BYTE) { @@ -10681,7 +10681,10 @@ include the height of both, if present, in the return value. */) dec_both (&end, &bpos); c = FETCH_BYTE (bpos); if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) - break; + { + inc_both (&end, &bpos); + break; + } } while (bpos < ZV_BYTE) { diff --git a/src/xfaces.c b/src/xfaces.c index b3b19a9cb2e..258b365eda3 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -3293,7 +3293,8 @@ FRAME 0 means change the face on all frames, and change the default } else if (EQ (k, QCstyle)) { - if (!EQ (v, Qpressed_button) && !EQ (v, Qreleased_button)) + if (!EQ (v, Qpressed_button) && !EQ (v, Qreleased_button) + && !EQ(v, Qflat_button)) break; } else @@ -6031,6 +6032,10 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] face->box = FACE_RAISED_BOX; else if (EQ (value, Qpressed_button)) face->box = FACE_SUNKEN_BOX; + else if (EQ (value, Qflat_button)) { + face->box = FACE_SIMPLE_BOX; + face->box_color = face->background; + } } } } @@ -6919,6 +6924,7 @@ syms_of_xfaces (void) DEFSYM (Qwave, "wave"); DEFSYM (Qreleased_button, "released-button"); DEFSYM (Qpressed_button, "pressed-button"); + DEFSYM (Qflat_button, "flat-button"); DEFSYM (Qnormal, "normal"); DEFSYM (Qextra_light, "extra-light"); DEFSYM (Qlight, "light"); |