From f6ef15cf84c1288e972ef0e6165b97e34d6033b6 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 22 Jun 2017 11:21:20 -0700 Subject: Use unlocked stdio more systematically This can improve performance significantly on stdio-bottlenecked code. E.g., make-docfile is 3x faster on my Fedora 25 x86-64 desktop. * admin/merge-gnulib (GNULIB_MODULES): Add unlocked-io. * lib-src/ebrowse.c, lib-src/emacsclient.c, lib-src/etags.c: * lib-src/hexl.c, lib-src/make-docfile.c, lib-src/movemail.c: * lib-src/profile.c, lib-src/update-game-score.c: Include unlocked-io.h instead of stdio.h, since these programs are single-threaded. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/unlocked-io.h, m4/unlocked-io.m4: New files, copied from Gnulib. * src/charset.c, src/cm.c, src/emacs.c, src/image.c, src/keyboard.c: * src/lread.c, src/term.c: Include sysstdio.h, possibly instead of stdio.h, to define the unlocked functions if the system does not provide them. * src/charset.c, src/lread.c (getc_unlocked): Remove, since sysstdio.h now defines it if needed. * src/cm.c (cmputc, cmcheckmagic): * src/dispnew.c (update_frame, update_frame_with_menu) (update_frame_1, Fsend_string_to_terminal, Fding, bitch_at_user): * src/emacs.c (main, Fdump_emacs): * src/fileio.c (Fdo_auto_save, Fset_binary_mode): * src/image.c (slurp_file, png_read_from_file, png_load_body) (our_stdio_fill_input_buffer): * src/keyboard.c (record_char, kbd_buffer_get_event, handle_interrupt): * src/lread.c (readbyte_from_file): * src/minibuf.c (read_minibuf_noninteractive): * src/print.c (printchar_to_stream, strout) (Fredirect_debugging_output): * src/sysdep.c (reset_sys_modes, procfs_ttyname) (procfs_get_total_memory): * src/term.c (tty_ring_bell, tty_send_additional_strings) (tty_set_terminal_modes, tty_reset_terminal_modes) (tty_update_end, tty_clear_end_of_line, tty_write_glyphs) (tty_write_glyphs_with_face, tty_insert_glyphs) (tty_menu_activate): * src/xfaces.c (Fx_load_color_file): Use unlocked stdio when it should be safe. * src/sysstdio.h (clearerr_unlocked, feof_unlocked, ferror_unlocked) (fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked) (fread_unlocked, fwrite_unlocked, getc_unlocked, getchar_unlocked) (putc_unlocked, putchar_unloced): Provide substitutes if not declared. --- src/charset.c | 6 +----- src/cm.c | 14 +++++++------- src/dispnew.c | 22 +++++++++++----------- src/emacs.c | 8 ++++---- src/fileio.c | 16 +++++++--------- src/image.c | 11 ++++++----- src/keyboard.c | 19 ++++++++++--------- src/lread.c | 11 +++-------- src/minibuf.c | 8 ++++---- src/print.c | 10 +++++----- src/sysdep.c | 15 ++++++--------- src/sysstdio.h | 41 +++++++++++++++++++++++++++++++++++++++++ src/term.c | 47 ++++++++++++++++++++++++----------------------- src/xfaces.c | 2 +- 14 files changed, 130 insertions(+), 100 deletions(-) (limited to 'src') diff --git a/src/charset.c b/src/charset.c index 9d15375dd79..d0840f7d2a9 100644 --- a/src/charset.c +++ b/src/charset.c @@ -29,7 +29,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include #include @@ -40,6 +39,7 @@ along with GNU Emacs. If not, see . */ #include "charset.h" #include "coding.h" #include "buffer.h" +#include "sysstdio.h" /*** GENERAL NOTES on CODED CHARACTER SETS (CHARSETS) *** @@ -198,10 +198,6 @@ static struct #define GET_TEMP_CHARSET_WORK_DECODER(CODE) \ (temp_charset_work->table.decoder[(CODE)]) - -#ifndef HAVE_GETC_UNLOCKED -#define getc_unlocked getc -#endif /* Set to 1 to warn that a charset map is loaded and thus a buffer diff --git a/src/cm.c b/src/cm.c index efa50b0f58d..9a90f37445c 100644 --- a/src/cm.c +++ b/src/cm.c @@ -19,10 +19,10 @@ along with GNU Emacs. If not, see . */ #include -#include #include "lisp.h" #include "cm.h" +#include "sysstdio.h" #include "termchar.h" #include "tparam.h" @@ -45,8 +45,8 @@ int cmputc (int c) { if (current_tty->termscript) - putc (c & 0177, current_tty->termscript); - putc (c & 0177, current_tty->output); + putc_unlocked (c & 0177, current_tty->termscript); + putc_unlocked (c & 0177, current_tty->output); return c; } @@ -117,11 +117,11 @@ cmcheckmagic (struct tty_display_info *tty) if (!MagicWrap (tty) || curY (tty) >= FrameRows (tty) - 1) emacs_abort (); if (tty->termscript) - putc ('\r', tty->termscript); - putc ('\r', tty->output); + putc_unlocked ('\r', tty->termscript); + putc_unlocked ('\r', tty->output); if (tty->termscript) - putc ('\n', tty->termscript); - putc ('\n', tty->output); + putc_unlocked ('\n', tty->termscript); + putc_unlocked ('\n', tty->output); curX (tty) = 0; curY (tty)++; } diff --git a/src/dispnew.c b/src/dispnew.c index 27c69bde831..925e44d9804 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3126,9 +3126,9 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) { if (FRAME_TTY (f)->termscript) - fflush (FRAME_TTY (f)->termscript); + fflush_unlocked (FRAME_TTY (f)->termscript); if (FRAME_TERMCAP_P (f)) - fflush (FRAME_TTY (f)->output); + fflush_unlocked (FRAME_TTY (f)->output); } /* Check window matrices for lost pointers. */ @@ -3181,8 +3181,8 @@ update_frame_with_menu (struct frame *f, int row, int col) update_end (f); if (FRAME_TTY (f)->termscript) - fflush (FRAME_TTY (f)->termscript); - fflush (FRAME_TTY (f)->output); + fflush_unlocked (FRAME_TTY (f)->termscript); + fflush_unlocked (FRAME_TTY (f)->output); /* Check window matrices for lost pointers. */ #if GLYPH_DEBUG #if 0 @@ -4531,7 +4531,7 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, ptrdiff_t outq = __fpending (display_output); if (outq > 900 || (outq > 20 && ((i - 1) % preempt_count == 0))) - fflush (display_output); + fflush_unlocked (display_output); } } @@ -5615,13 +5615,13 @@ when TERMINAL is nil. */) if (tty->termscript) { - fwrite (SDATA (string), 1, SBYTES (string), tty->termscript); - fflush (tty->termscript); + fwrite_unlocked (SDATA (string), 1, SBYTES (string), tty->termscript); + fflush_unlocked (tty->termscript); } out = tty->output; } - fwrite (SDATA (string), 1, SBYTES (string), out); - fflush (out); + fwrite_unlocked (SDATA (string), 1, SBYTES (string), out); + fflush_unlocked (out); unblock_input (); return Qnil; } @@ -5636,7 +5636,7 @@ terminate any keyboard macro currently executing. */) if (!NILP (arg)) { if (noninteractive) - putchar (07); + putchar_unlocked (07); else ring_bell (XFRAME (selected_frame)); } @@ -5650,7 +5650,7 @@ void bitch_at_user (void) { if (noninteractive) - putchar (07); + putchar_unlocked (07); else if (!INTERACTIVE) /* Stop executing a keyboard macro. */ { const char *msg diff --git a/src/emacs.c b/src/emacs.c index da8df1bf1c7..0fec7167588 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -23,7 +23,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include @@ -33,6 +32,7 @@ along with GNU Emacs. If not, see . */ #define MAIN_PROGRAM #include "lisp.h" +#include "sysstdio.h" #ifdef WINDOWSNT #include @@ -885,7 +885,7 @@ main (int argc, char **argv) } #endif /* HAVE_SETRLIMIT and RLIMIT_STACK and not CYGWIN */ - clearerr (stdin); + clearerr_unlocked (stdin); emacs_backtrace (-1); @@ -983,7 +983,7 @@ main (int argc, char **argv) int i; printf ("Usage: %s [OPTION-OR-FILENAME]...\n", argv[0]); for (i = 0; i < ARRAYELTS (usage_message); i++) - fputs (usage_message[i], stdout); + fputs_unlocked (usage_message[i], stdout); exit (0); } @@ -2197,7 +2197,7 @@ You must run Emacs in batch mode in order to dump it. */) } #endif - fflush (stdout); + fflush_unlocked (stdout); /* Tell malloc where start of impure now is. */ /* Also arrange for warnings when nearly out of space. */ #if !defined SYSTEM_MALLOC && !defined HYBRID_MALLOC diff --git a/src/fileio.c b/src/fileio.c index cb070029a9b..a57d50b24e0 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5643,14 +5643,12 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) { block_input (); if (!NILP (BVAR (b, filename))) - { - fwrite (SDATA (BVAR (b, filename)), 1, - SBYTES (BVAR (b, filename)), stream); - } - putc ('\n', stream); - fwrite (SDATA (BVAR (b, auto_save_file_name)), 1, - SBYTES (BVAR (b, auto_save_file_name)), stream); - putc ('\n', stream); + fwrite_unlocked (SDATA (BVAR (b, filename)), 1, + SBYTES (BVAR (b, filename)), stream); + putc_unlocked ('\n', stream); + fwrite_unlocked (SDATA (BVAR (b, auto_save_file_name)), 1, + SBYTES (BVAR (b, auto_save_file_name)), stream); + putc_unlocked ('\n', stream); unblock_input (); } @@ -5841,7 +5839,7 @@ effect except for flushing STREAM's data. */) binmode = NILP (mode) ? O_TEXT : O_BINARY; if (fp != stdin) - fflush (fp); + fflush_unlocked (fp); return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil; } diff --git a/src/image.c b/src/image.c index aedec7954ee..07c4769e9e3 100644 --- a/src/image.c +++ b/src/image.c @@ -20,7 +20,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include /* Include this before including to work around bugs with @@ -41,6 +40,7 @@ along with GNU Emacs. If not, see . */ #include "buffer.h" #include "dispextern.h" #include "blockinput.h" +#include "sysstdio.h" #include "systime.h" #include #include "coding.h" @@ -2361,7 +2361,7 @@ slurp_file (int fd, ptrdiff_t *size) This can happen if the file grows as we read it. */ ptrdiff_t buflen = st.st_size; buf = xmalloc (buflen + 1); - if (fread (buf, 1, buflen + 1, fp) == buflen) + if (fread_unlocked (buf, 1, buflen + 1, fp) == buflen) *size = buflen; else { @@ -5890,7 +5890,7 @@ png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length) { FILE *fp = png_get_io_ptr (png_ptr); - if (fread (data, 1, length, fp) < length) + if (fread_unlocked (data, 1, length, fp) < length) png_error (png_ptr, "Read error"); } @@ -5959,7 +5959,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) } /* Check PNG signature. */ - if (fread (sig, 1, sizeof sig, fp) != sizeof sig + if (fread_unlocked (sig, 1, sizeof sig, fp) != sizeof sig || png_sig_cmp (sig, 0, sizeof sig)) { fclose (fp); @@ -6598,7 +6598,8 @@ our_stdio_fill_input_buffer (j_decompress_ptr cinfo) { ptrdiff_t bytes; - bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file); + bytes = fread_unlocked (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, + src->file); if (bytes > 0) src->mgr.bytes_in_buffer = bytes; else diff --git a/src/keyboard.c b/src/keyboard.c index 55486c6d9ab..3442b18409a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -39,6 +39,7 @@ along with GNU Emacs. If not, see . */ #include "intervals.h" #include "keymap.h" #include "blockinput.h" +#include "sysstdio.h" #include "systime.h" #include "atimer.h" #include "process.h" @@ -3290,7 +3291,7 @@ record_char (Lisp_Object c) if (INTEGERP (c)) { if (XUINT (c) < 0x100) - putc (XUINT (c), dribble); + putc_unlocked (XUINT (c), dribble); else fprintf (dribble, " 0x%"pI"x", XUINT (c)); } @@ -3303,15 +3304,15 @@ record_char (Lisp_Object c) if (SYMBOLP (dribblee)) { - putc ('<', dribble); - fwrite (SDATA (SYMBOL_NAME (dribblee)), sizeof (char), - SBYTES (SYMBOL_NAME (dribblee)), - dribble); - putc ('>', dribble); + putc_unlocked ('<', dribble); + fwrite_unlocked (SDATA (SYMBOL_NAME (dribblee)), sizeof (char), + SBYTES (SYMBOL_NAME (dribblee)), + dribble); + putc_unlocked ('>', dribble); } } - fflush (dribble); + fflush_unlocked (dribble); unblock_input (); } } @@ -3769,7 +3770,7 @@ kbd_buffer_get_event (KBOARD **kbp, detaching from the terminal. */ || (IS_DAEMON && DAEMON_RUNNING)) { - int c = getchar (); + int c = getchar_unlocked (); XSETINT (obj, c); *kbp = current_kboard; return obj; @@ -10377,7 +10378,7 @@ handle_interrupt (bool in_signal_handler) sigemptyset (&blocked); sigaddset (&blocked, SIGINT); pthread_sigmask (SIG_BLOCK, &blocked, 0); - fflush (stdout); + fflush_unlocked (stdout); } reset_all_sys_modes (); diff --git a/src/lread.c b/src/lread.c index 8716b86e9bf..182f96223a5 100644 --- a/src/lread.c +++ b/src/lread.c @@ -72,10 +72,6 @@ along with GNU Emacs. If not, see . */ #define file_tell ftell #endif -#ifndef HAVE_GETC_UNLOCKED -#define getc_unlocked getc -#endif - /* The objects or placeholders read with the #n=object form. A hash table maps a number to either a placeholder (while the @@ -474,16 +470,15 @@ readbyte_from_file (int c, Lisp_Object readcharfun) } block_input (); - c = getc_unlocked (instream); /* Interrupted reads have been observed while reading over the network. */ - while (c == EOF && ferror (instream) && errno == EINTR) + while ((c = getc_unlocked (instream)) == EOF && errno == EINTR + && ferror_unlocked (instream)) { unblock_input (); maybe_quit (); block_input (); - clearerr (instream); - c = getc_unlocked (instream); + clearerr_unlocked (instream); } unblock_input (); diff --git a/src/minibuf.c b/src/minibuf.c index 1bbe276776e..835992fa79d 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -20,7 +20,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include @@ -31,6 +30,7 @@ along with GNU Emacs. If not, see . */ #include "frame.h" #include "window.h" #include "keymap.h" +#include "sysstdio.h" #include "systty.h" /* List of buffers for use as minibuffers. @@ -209,15 +209,15 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial, suppress_echo_on_tty (STDIN_FILENO); } - fwrite (SDATA (prompt), 1, SBYTES (prompt), stdout); - fflush (stdout); + fwrite_unlocked (SDATA (prompt), 1, SBYTES (prompt), stdout); + fflush_unlocked (stdout); val = Qnil; size = 100; len = 0; line = xmalloc (size); - while ((c = getchar ()) != '\n' && c != '\r') + while ((c = getchar_unlocked ()) != '\n' && c != '\r') { if (c == EOF) { diff --git a/src/print.c b/src/print.c index aaec5b04956..6bf8af9ef93 100644 --- a/src/print.c +++ b/src/print.c @@ -228,7 +228,7 @@ printchar_to_stream (unsigned int ch, FILE *stream) { if (ASCII_CHAR_P (ch)) { - putc (ch, stream); + putc_unlocked (ch, stream); #ifdef WINDOWSNT /* Send the output to a debugger (nothing happens if there isn't one). */ @@ -246,7 +246,7 @@ printchar_to_stream (unsigned int ch, FILE *stream) if (encode_p) encoded_ch = code_convert_string_norecord (encoded_ch, coding_system, true); - fwrite (SSDATA (encoded_ch), 1, SBYTES (encoded_ch), stream); + fwrite_unlocked (SSDATA (encoded_ch), 1, SBYTES (encoded_ch), stream); #ifdef WINDOWSNT if (print_output_debug_flag && stream == stderr) OutputDebugString (SSDATA (encoded_ch)); @@ -298,7 +298,7 @@ printchar (unsigned int ch, Lisp_Object fun) if (DISP_TABLE_P (Vstandard_display_table)) printchar_to_stream (ch, stdout); else - fwrite (str, 1, len, stdout); + fwrite_unlocked (str, 1, len, stdout); noninteractive_need_newline = 1; } else @@ -350,7 +350,7 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t size_byte, } } else - fwrite (ptr, 1, size_byte, stdout); + fwrite_unlocked (ptr, 1, size_byte, stdout); noninteractive_need_newline = 1; } @@ -801,7 +801,7 @@ append to existing target file. */) report_file_error ("Cannot open debugging output stream", file); } - fflush (stderr); + fflush_unlocked (stderr); if (dup2 (fd, STDERR_FILENO) < 0) report_file_error ("dup2", file); if (fd != stderr_dup) diff --git a/src/sysdep.c b/src/sysdep.c index 70f4a9dd7ea..b52236769e0 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1408,7 +1408,7 @@ reset_sys_modes (struct tty_display_info *tty_out) { if (noninteractive) { - fflush (stdout); + fflush_unlocked (stdout); return; } if (!tty_out->term_initted) @@ -1428,17 +1428,14 @@ reset_sys_modes (struct tty_display_info *tty_out) } else { /* have to do it the hard way */ - int i; tty_turn_off_insert (tty_out); - for (i = cursorX (tty_out); i < FrameCols (tty_out) - 1; i++) - { - fputc (' ', tty_out->output); - } + for (int i = cursorX (tty_out); i < FrameCols (tty_out) - 1; i++) + fputc_unlocked (' ', tty_out->output); } cmgoto (tty_out, FrameRows (tty_out) - 1, 0); - fflush (tty_out->output); + fflush_unlocked (tty_out->output); if (tty_out->terminal->reset_terminal_modes_hook) tty_out->terminal->reset_terminal_modes_hook (tty_out->terminal); @@ -3079,7 +3076,7 @@ procfs_ttyname (int rdev) char minor[25]; /* 2 32-bit numbers + dash */ char *endp; - for (; !feof (fdev) && !ferror (fdev); name[0] = 0) + for (; !feof_unlocked (fdev) && !ferror_unlocked (fdev); name[0] = 0) { if (fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) >= 3 && major == MAJOR (rdev)) @@ -3129,7 +3126,7 @@ procfs_get_total_memory (void) break; case 0: - while ((c = getc (fmem)) != EOF && c != '\n') + while ((c = getc_unlocked (fmem)) != EOF && c != '\n') continue; done = c == EOF; break; diff --git a/src/sysstdio.h b/src/sysstdio.h index 45ee33f5580..7fbcefcdad9 100644 --- a/src/sysstdio.h +++ b/src/sysstdio.h @@ -33,4 +33,45 @@ extern FILE *emacs_fopen (char const *, char const *); # define FOPEN_TEXT "" #endif +/* These are compatible with unlocked-io.h, if both files are included. */ +#if !HAVE_DECL_CLEARERR_UNLOCKED +# define clearerr_unlocked(x) clearerr (x) +#endif +#if !HAVE_DECL_FEOF_UNLOCKED +# define feof_unlocked(x) feof (x) +#endif +#if !HAVE_DECL_FERROR_UNLOCKED +# define ferror_unlocked(x) ferror (x) +#endif +#if !HAVE_DECL_FFLUSH_UNLOCKED +# define fflush_unlocked(x) fflush (x) +#endif +#if !HAVE_DECL_FGETS_UNLOCKED +# define fgets_unlocked(x,y,z) fgets (x,y,z) +#endif +#if !HAVE_DECL_FPUTC_UNLOCKED +# define fputc_unlocked(x,y) fputc (x,y) +#endif +#if !HAVE_DECL_FPUTS_UNLOCKED +# define fputs_unlocked(x,y) fputs (x,y) +#endif +#if !HAVE_DECL_FREAD_UNLOCKED +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +#endif +#if !HAVE_DECL_FWRITE_UNLOCKED +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +#endif +#if !HAVE_DECL_GETC_UNLOCKED +# define getc_unlocked(x) getc (x) +#endif +#if !HAVE_DECL_GETCHAR_UNLOCKED +# define getchar_unlocked() getchar () +#endif +#if !HAVE_DECL_PUTC_UNLOCKED +# define putc_unlocked(x,y) putc (x,y) +#endif +#if !HAVE_DECL_PUTCHAR_UNLOCKED +# define putchar_unlocked(x) putchar (x) +#endif + #endif /* EMACS_SYSSTDIO_H */ diff --git a/src/term.c b/src/term.c index 8770aff8a92..3d7f4ada0b9 100644 --- a/src/term.c +++ b/src/term.c @@ -22,7 +22,6 @@ along with GNU Emacs. If not, see . */ #include #include #include -#include #include #include #include @@ -45,6 +44,7 @@ along with GNU Emacs. If not, see . */ #include "keymap.h" #include "blockinput.h" #include "syssignal.h" +#include "sysstdio.h" #ifdef MSDOS #include "msdos.h" static int been_here = -1; @@ -146,7 +146,7 @@ tty_ring_bell (struct frame *f) OUTPUT (tty, (tty->TS_visible_bell && visible_bell ? tty->TS_visible_bell : tty->TS_bell)); - fflush (tty->output); + fflush_unlocked (tty->output); } } @@ -167,9 +167,10 @@ tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym) Lisp_Object string = XCAR (extra_codes); if (STRINGP (string)) { - fwrite (SDATA (string), 1, SBYTES (string), tty->output); + fwrite_unlocked (SDATA (string), 1, SBYTES (string), tty->output); if (tty->termscript) - fwrite (SDATA (string), 1, SBYTES (string), tty->termscript); + fwrite_unlocked (SDATA (string), 1, SBYTES (string), + tty->termscript); } } } @@ -197,7 +198,7 @@ tty_set_terminal_modes (struct terminal *terminal) OUTPUT_IF (tty, tty->TS_keypad_mode); losecursor (tty); tty_send_additional_strings (terminal, Qtty_mode_set_strings); - fflush (tty->output); + fflush_unlocked (tty->output); } } @@ -220,7 +221,7 @@ tty_reset_terminal_modes (struct terminal *terminal) /* Output raw CR so kernel can track the cursor hpos. */ current_tty = tty; cmputc ('\r'); - fflush (tty->output); + fflush_unlocked (tty->output); } } @@ -235,7 +236,7 @@ tty_update_end (struct frame *f) tty_show_cursor (tty); tty_turn_off_insert (tty); tty_background_highlight (tty); - fflush (tty->output); + fflush_unlocked (tty->output); } /* The implementation of set_terminal_window for termcap frames. */ @@ -497,8 +498,8 @@ tty_clear_end_of_line (struct frame *f, int first_unused_hpos) for (i = curX (tty); i < first_unused_hpos; i++) { if (tty->termscript) - fputc (' ', tty->termscript); - fputc (' ', tty->output); + fputc_unlocked (' ', tty->termscript); + fputc_unlocked (' ', tty->output); } cmplus (tty, first_unused_hpos - curX (tty)); } @@ -771,11 +772,11 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) if (coding->produced > 0) { block_input (); - fwrite (conversion_buffer, 1, coding->produced, tty->output); - if (ferror (tty->output)) - clearerr (tty->output); + fwrite_unlocked (conversion_buffer, 1, coding->produced, tty->output); + clearerr_unlocked (tty->output); if (tty->termscript) - fwrite (conversion_buffer, 1, coding->produced, tty->termscript); + fwrite_unlocked (conversion_buffer, 1, coding->produced, + tty->termscript); unblock_input (); } string += n; @@ -832,11 +833,11 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str if (coding->produced > 0) { block_input (); - fwrite (conversion_buffer, 1, coding->produced, tty->output); - if (ferror (tty->output)) - clearerr (tty->output); + fwrite_unlocked (conversion_buffer, 1, coding->produced, tty->output); + clearerr_unlocked (tty->output); if (tty->termscript) - fwrite (conversion_buffer, 1, coding->produced, tty->termscript); + fwrite_unlocked (conversion_buffer, 1, coding->produced, + tty->termscript); unblock_input (); } @@ -918,11 +919,11 @@ tty_insert_glyphs (struct frame *f, struct glyph *start, int len) if (coding->produced > 0) { block_input (); - fwrite (conversion_buffer, 1, coding->produced, tty->output); - if (ferror (tty->output)) - clearerr (tty->output); + fwrite_unlocked (conversion_buffer, 1, coding->produced, tty->output); + clearerr_unlocked (tty->output); if (tty->termscript) - fwrite (conversion_buffer, 1, coding->produced, tty->termscript); + fwrite_unlocked (conversion_buffer, 1, coding->produced, + tty->termscript); unblock_input (); } @@ -3327,7 +3328,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, which calls tty_show_cursor. Re-hide it, so it doesn't show through the menus. */ tty_hide_cursor (tty); - fflush (tty->output); + fflush_unlocked (tty->output); } sf->mouse_moved = 0; @@ -3335,7 +3336,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, while (statecount--) free_saved_screen (state[statecount].screen_behind); tty_show_cursor (tty); /* Turn cursor back on. */ - fflush (tty->output); + fflush_unlocked (tty->output); /* Clean up any mouse events that are waiting inside Emacs event queue. These events are likely to be generated before the menu was even diff --git a/src/xfaces.c b/src/xfaces.c index 4714b7b3cb8..86bb9b0b496 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -6232,7 +6232,7 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) int red, green, blue; int num; - while (fgets (buf, sizeof (buf), fp) != NULL) { + while (fgets_unlocked (buf, sizeof (buf), fp) != NULL) { if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3) { #ifdef HAVE_NTGUI -- cgit v1.2.1 From 1886246f6f40b8c376467f71605141035959cae0 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Sun, 25 Jun 2017 11:33:25 +0200 Subject: Provide additional support for child frames Provide mouse dragging and resizing of frames. Allow resizing frames proportionally. Provide additional functionality for child frames. Minor bug fixes. * lisp/frame.el (frame-border-width, frame-pixel-width) (frame-pixel-height): Alias to `frame-internal-border-width', `frame-native-width' and `frame-native-height'. (frame-inner-width, frame-inner-height, frame-outer-width) (frame-outer-height): New functions. * lisp/minibuffer.el (completion-auto-help): Fix typo. * lisp/mouse.el (mouse-drag-line, mouse-drag-mode-line) (mouse-drag-header-line): Allow moving a frame by dragging the mode line of its bottommost window (on a minibuffer-less frame) or the header line of its topmost window. (mouse-drag-vertical-line): Mention argument in doc-string. (mouse-resize-frame, mouse-drag-frame, mouse-drag-left-edge) (mouse-drag-top-left-corner, mouse-drag-top-edge) (mouse-drag-top-right-corner, mouse-drag-right-edge) (mouse-drag-bottom-right-corner, mouse-drag-bottom-edge) (mouse-drag-bottom-left-corner): New functions for resizing a frame by dragging its internal border together with corresponding key bindings. * lisp/tooltip.el (tooltip-frame-parameters): Add 'no-special-glyphs' to default parameters and update version tag. * lisp/window.el (frame-auto-hide-function): Add choice to make frame invisible and update version tag. (window--delete): Handle 'auto-hide-function' frame parameter. (window--maybe-raise-frame): Respect 'no-focus-on-map' and 'no-accept-focus' frame parameters. (display-buffer--action-function-custom-type): Add `display-buffer-in-child-frame'. (display-buffer): Mention `display-buffer-in-child-frame' in doc-string. (display-buffer-in-child-frame): New action function for `display-buffer'. (window--sanitize-margin): Return zero when MARGIN cannot be sanitized. (fit-frame-to-buffer): Major rewrite to handle child frames and 'fit-frame-to-buffer-sizes' and 'fit-frame-to-buffer-margins' frame parameters. (window-largest-empty-rectangle--maximums-1) (window-largest-empty-rectangle--maximums) (window-largest-empty-rectangle--disjoint-maximums) (window-largest-empty-rectangle): New functions. * src/dispextern.h (WINDOW_WANTS_MODELINE_P) (WINDOW_WANTS_HEADER_LINE_P): Remove. Functionality is now provided by corresponding functions window_wants_modeline and window_wants_header_line in window.c. Adjust users. * src/dispnew.c (adjust_glyph_matrix) (buffer_posn_from_coords): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. * src/frame.c (keep_ratio): New function. (adjust_frame_size): Call keep_ratio for each of F's child frames. (make_frame): Initialize no_special_glyphs slot. (frame_internal_border_part): New function. (Fframe_pixel_width, Fframe_pixel_height, Fborder_width): Rename to Fframe_native_width, Fframe_native_height mand Fframe_internal_border_width. (frame_parm_table): Add Qno_special_glyphs entry. (frame_float_type): New enumeration type. (frame_float): New function to handle frame size and position ratios. (x_set_frame_parameters): Handle size and position ratios. (x_set_no_special_glyphs): New function (x_figure_window_size): Handle size and position ratios. (syms_of_frame): Add Qdisplay_monitor_attributes_list, Qno_special_glyphs, Qframe_edges, Qkeep_ratio, Qwidth_only, Qheight_only, Qleft_only and Qtop_only. * src/frame.h (internal_border_part): New enumeration type. (struct frame): New slot no_special_glyphs. (FRAME_NO_SPECIAL_GLYPHS): New macro. * src/gtkutil.c (xg_frame_restack): Return immediately for GTK versions before 2.18.0. * src/keyboard.c (internal_border_parts): New array constant. (make_lispy_position): For frames with border dragging enabled return internal border part. (syms_of_keyboard): New symbols Qdrag_internal_border, Qleft_edge, Qtop_left_corner, Qtop_edge, Qtop_right_corner, Qright_edge, Qbottom_right_corner, Qbottom_edge and Qbottom_left_corner. * src/minibuf.c (read_minibuf_unwind): When exiting the minibuffer deal with frames that have the 'minibuffer-exit' parameter set. (syms_of_minibuf): New symbol Qminibuffer_exit. * src/nsfns.m (frame_parm_handler): Add entry for x_set_no_special_glyphs. (Fx_create_frame): Handle 'no-special-glyphs' parameter. Intitialize new cursor types for dragging frame borders. * src/nsterm.h (struct ns_output): Add new cursor types for dragging frame borders. * src/w32fns.c (w32_frame_parm_handlers): Add entry for x_set_no_special_glyphs. (Fx_create_frame): Handle 'no-special-glyphs' parameter. Intitialize new cursor types for dragging frame borders. * src/w32term.h (struct w32_output): Add new cursor types for dragging frame borders. * src/window.c (coordinates_in_window) (Fwindow_line_height, window_internal_height): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (Fwindow_lines_pixel_dimensions): New function. (window_parameter): New function. (Fwindow_parameter): Call window_parameter. (window_wants_mode_line, window_wants_header_line): New functions replacing the macros WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P from dispextern.h. (syms_of_window): New symbols Qmode_line_format and Qheader_line_format. * src/window.h: Reorganize and re-comment macros. Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (MINI_NON_ONLY_WINDOW_P, MINI_ONLY_WINDOW_P): Minor rewrite. (WINDOW_BUFFER): New macro. (WINDOW_BOX_LEFT_EDGE_COL, WINDOW_BOX_RIGHT_EDGE_COL): Remove. * src/xdisp.c (window_text_bottom_y, window_box_height) (window_box, start_display) (compute_window_start_on_continuation_line) (try_cursor_movement, redisplay_window) (try_window_reusing_current_matrix, try_window_id) (display_line, expose_window): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (pos_visible_p, display_mode_lines): Respect W's 'mode-line-format' and 'header-line-format' window parameters. (init_iterator): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. For tip frames respect no_special_glyphs value. (note_mouse_highlight): Set frame border cursors when on internal border. (x_draw_right_divider, x_draw_bottom_divider): Try to improve drawing of window dividers. * src/xfns.c (mouse_cursor): Add entries for border parts. (mouse_cursor_types): Add entries for cursor types to drag frame borders. (INSTALL_CURSOR): Add entries for new cursor types to drag frame borders. (Fx_create_frame): Handle 'no-special-glyphs' parameter. (x_frame_parm_handlers): Add entry for x_set_no_special_glyphs. (Vx_window_left_edge_shape, Vx_window_top_left_corner_shape) (Vx_window_top_edge_shape, Vx_window_top_right_corner_shape) (Vx_window_right_edge_shape) (Vx_window_bottom_right_corner_shape) (Vx_window_bottom_edge_shape) (Vx_window_bottom_left_corner_shape): New variables. (x_frame_restack): Call xg_frame_restack only for GTK versions starting with 2.18.0. * src/xterm.c (x_free_frame_resources): Remove new cursors for dragging frame borders. * src/xterm.h (struct x_output): Add new cursor types for dragging frame borders. * doc/lispref/display.texi (Size of Displayed Text): Document `window-lines-pixel-dimensions'. * doc/lispref/elisp.texi (Top): Add entry for "Mouse Dragging Parameters". * doc/lispref/frames.texi (Frame Size): Replace frame-pixel-width/-height by frame-native-width/-height. Add frame-inner-width/-height and frame-outer-width/-height docs. (Position Parameters): Describe specifying position as ratios. Clarify remark about positions relative to bottom/ridge display edge. (Size Parameters): Describe specifying sizes as ratios. Describe 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes' parameters. (Layout Parameters): Describe 'no-special-glyphs' parameter. (Frame Interaction Parameters): Describe 'auto-hide-function', 'minibuffer-exit' and 'keep-ratio' parameters. (Mouse Dragging Parameters): New section describing 'drag-internal-border', 'drag-with-header-line', 'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible' parameters. (Management Parameters): Mention that `override-redirect' has no effect on MS Windows. (Font and Color Parameters): Mention child frames for `alpha' parameter. (Child Frames): Rewrite section with description and cross references to new frame parameters added. * doc/lispref/modes.texi (Mode Line Basics): Mention 'mode-line-format' and 'header-line-format' window parameters. * doc/lispref/windows.texi (Resizing Windows): Mention effect of `fit-frame-to-buffer-margins' for child frames. (Display Action Functions): New action function `display-buffer-in-child-frame'. (Quitting Windows): Mention `make-frame-invisible' as optional value of `frame-auto-hide-function' and `auto-hide-function' frame paameter. (Coordinates and Windows): Describe new function `window-largest-empty-rectangle'. (Window Parameters): Describe new parameters 'mode-line-format' and 'header-line-format'. Index all window parameters described in this section. --- src/dispextern.h | 36 +-- src/dispnew.c | 10 +- src/frame.c | 789 ++++++++++++++++++++++++++++++++++++++++++++----------- src/frame.h | 28 +- src/gtkutil.c | 2 + src/keyboard.c | 52 +++- src/minibuf.c | 26 ++ src/nsfns.m | 12 + src/nsterm.h | 8 + src/w32fns.c | 41 ++- src/w32term.c | 63 ++++- src/w32term.h | 8 + src/window.c | 213 ++++++++++++++- src/window.h | 200 +++++++------- src/xdisp.c | 185 ++++++++++--- src/xfns.c | 101 ++++++- src/xterm.c | 16 ++ src/xterm.h | 8 + 18 files changed, 1412 insertions(+), 386 deletions(-) (limited to 'src') diff --git a/src/dispextern.h b/src/dispextern.h index d1e4715c329..8644ce26d13 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1106,7 +1106,7 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int); #define MATRIX_BOTTOM_TEXT_ROW(MATRIX, W) \ ((MATRIX)->rows \ + (MATRIX)->nrows \ - - (WINDOW_WANTS_MODELINE_P ((W)) ? 1 : 0)) + - (window_wants_mode_line ((W)) ? 1 : 0)) /* Non-zero if the face of the last glyph in ROW's text area has to be drawn to the end of the text area. */ @@ -1469,40 +1469,6 @@ struct glyph_string #define DESIRED_HEADER_LINE_HEIGHT(W) \ MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix) -/* PXW: The height checks below serve to show at least one text line - instead of a mode- and/or header line when a window gets very small. - But (1) the check fails when the mode- or header-line is taller than - the associated frame's line height and (2) we don't care much about - text visibility anyway when shrinking a frame containing a toolbar. - - So maybe these checks should be removed and any clipping left to the - window manager. */ - -/* Value is true if window W wants a mode line and is large enough - to accommodate it. */ -#define WINDOW_WANTS_MODELINE_P(W) \ - (BUFFERP ((W)->contents) \ - ? (!MINI_WINDOW_P (W) \ - && !(W)->pseudo_window_p \ - && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W))) \ - && !NILP (BVAR (XBUFFER ((W)->contents), mode_line_format)) \ - && WINDOW_PIXEL_HEIGHT (W) > WINDOW_FRAME_LINE_HEIGHT (W)) \ - : false) - -/* Value is true if window W wants a header line and is large enough - to accommodate it. */ -#define WINDOW_WANTS_HEADER_LINE_P(W) \ - (BUFFERP ((W)->contents) \ - ? (!MINI_WINDOW_P (W) \ - && !(W)->pseudo_window_p \ - && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W))) \ - && !NILP (BVAR (XBUFFER ((W)->contents), header_line_format)) \ - && (WINDOW_PIXEL_HEIGHT (W) \ - > (WINDOW_WANTS_MODELINE_P (W) \ - ? (2 * WINDOW_FRAME_LINE_HEIGHT (W)) \ - : WINDOW_FRAME_LINE_HEIGHT (W)))) \ - : false) - /* Return proper value to be used as baseline offset of font that has ASCENT and DESCENT to draw characters by the font at the vertical center of the line of frame F. diff --git a/src/dispnew.c b/src/dispnew.c index 925e44d9804..93ef6a55a2e 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -377,7 +377,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y { window_box (w, ANY_AREA, 0, 0, &window_width, &window_height); - header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); + header_line_p = window_wants_header_line (w); header_line_changed_p = header_line_p != matrix->header_line_p; } matrix->header_line_p = header_line_p; @@ -446,7 +446,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y if (w == NULL || (row == matrix->rows + dim.height - 1 - && WINDOW_WANTS_MODELINE_P (w)) + && window_wants_mode_line (w)) || (row == matrix->rows && matrix->header_line_p)) { row->glyphs[TEXT_AREA] @@ -491,7 +491,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y /* The mode line, if displayed, never has marginal areas. */ if ((row == matrix->rows + dim.height - 1 - && !(w && WINDOW_WANTS_MODELINE_P (w))) + && !(w && window_wants_mode_line (w))) || (row == matrix->rows && matrix->header_line_p)) { row->glyphs[TEXT_AREA] @@ -570,7 +570,7 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y the mode line, if any, since otherwise it will remain disabled in the current matrix, and expose events won't redraw it. */ - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) w->update_mode_line = 1; } else if (matrix == w->desired_matrix) @@ -5188,7 +5188,7 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p start position, i.e. it excludes the header-line row, but MATRIX_ROW includes the header-line row. Adjust for a possible header-line row. */ - it_vpos = it.vpos + WINDOW_WANTS_HEADER_LINE_P (w); + it_vpos = it.vpos + window_wants_header_line (w); if (it_vpos < w->current_matrix->nrows && (row = MATRIX_ROW (w->current_matrix, it_vpos), row->enabled_p)) diff --git a/src/frame.c b/src/frame.c index 4d17a071dc7..b2377aefb8d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -328,8 +328,8 @@ DEFUN ("frame-windows-min-size", Fframe_windows_min_size, * frame_windows_min_size: * * Return the minimum number of lines (columns if HORIZONTAL is non-nil) - * of FRAME. If PIXELWISE is non-nil, return the minimum height (width) - * in pixels. + * of FRAME. If PIXELWISE is non-nil, return the minimum inner height + * (width) of FRAME in pixels. * * This value is calculated by the function `frame-windows-min-size' in * window.el unless the `min-height' (`min-width' if HORIZONTAL is @@ -341,7 +341,7 @@ DEFUN ("frame-windows-min-size", Fframe_windows_min_size, * of `window-min-height' (`window-min-width' if HORIZONTAL is non-nil). * With IGNORE non-nil the values of these variables are ignored. * - * In either case never return a value less than 1. + * In either case, never return a value less than 1. */ static int frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, @@ -373,46 +373,179 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, } -/* Make sure windows sizes of frame F are OK. new_width and new_height - are in pixels. A value of -1 means no change is requested for that - size (but the frame may still have to be resized to accommodate - windows with their minimum sizes). This can either issue a request - to resize the frame externally (via x_set_window_size), to resize the - frame internally (via resize_frame_windows) or do nothing at all. +#ifdef HAVE_WINDOW_SYSTEM +/** + * keep_ratio: + * + * Preserve ratios of frame F which usually happens after its parent + * frame got resized. OLD_WIDTH, OLD_HEIGHT specifies the old native + * size of F's parent, NEW_WIDTH and NEW_HEIGHT its new size. + * + * Adjust F's width if F's 'keep_ratio' parameter is non-nil and, if + * it is a cons, its car is not 'height-only'. Adjust F's height if F's + * 'keep_ratio' parameter is non-nil and, if it is a cons, its car + * is not 'width-only'. + * + * Adjust F's left position if F's 'keep_ratio' parameter is non-nil + * and, if its is a cons, its cdr is non-nil and not 'top-only'. Adjust + * F's top position if F's 'keep_ratio' parameter is non-nil and, if + * its is a cons, its cdr is non-nil and not 'left-only'. + * + * Note that when positional adjustment is requested but the size of F + * should remain unaltered in the corresponding direction, this routine + * tries to constrain F to its parent frame - something which usually + * happens when the parent frame shrinks. This means, however, that + * when the parent frame is re-enlarged later, the child's original + * position will not get restored to its pre-shrinking value. + * + * This routine is currently useful for child frames only. It might be + * eventually useful when moving non-child frames between monitors with + * different resolutions. + */ +static void +keep_ratio (struct frame *f, int old_width, int old_height, + int new_width, int new_height) +{ + Lisp_Object keep_ratio = get_frame_param (f, Qkeep_ratio); - The argument INHIBIT can assume the following values: - 0 means to unconditionally call x_set_window_size even if sizes - apparently do not change. Fx_create_frame uses this to pass the - initial size to the window manager. + if (!NILP (keep_ratio)) + { + double width_factor = (double)new_width / (double)old_width; + double height_factor = (double)new_height / (double)old_height; + int pixel_width, pixel_height, pos_x, pos_y; - 1 means to call x_set_window_size if the outer frame size really - changes. Fset_frame_size, Fset_frame_height, ... use this. + if (!CONSP (keep_ratio) || !NILP (Fcdr (keep_ratio))) + { + if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qtop_only)) + pos_x = f->left_pos; + else + { + pos_x = (int)(f->left_pos * width_factor + 0.5); - 2 means to call x_set_window_size provided frame_inhibit_resize - allows it. The menu and tool bar code use this ("3" won't work - here in general because menu and tool bar are often not counted in - the frame's text height). + if (CONSP (keep_ratio) && + (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qheight_only))) + { + struct frame *p = FRAME_PARENT_FRAME (f); - 3 means call x_set_window_size if window minimum sizes must be - preserved or frame_inhibit_resize allows it. x_set_left_fringe, - x_set_scroll_bar_width, x_new_font ... use (or should use) this. + if (pos_x + f->pixel_width > p->pixel_width) + { + int p_f_width = p->pixel_width - f->pixel_width; - 4 means call x_set_window_size only if window minimum sizes must be - preserved. x_set_right_divider_width, x_set_border_width and the - code responsible for wrapping the tool bar use this. + if (p_f_width <= 0) + pos_x = 0; + else + pos_x = (int)(p_f_width * width_factor * 0.5 + 0.5); + } + } + + f->left_pos = pos_x; + } + + if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qleft_only)) + pos_y = f->top_pos; + else + { + pos_y = (int)(f->top_pos * height_factor + 0.5); + + if (CONSP (keep_ratio) && + (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qwidth_only))) + /* When positional adjustment was requested and the + width of F should remain unaltered, try to constrain + F to its parent. This means that when the parent + frame is enlarged later the child's original position + won't get restored. */ + { + struct frame *p = FRAME_PARENT_FRAME (f); + + if (pos_y + f->pixel_height > p->pixel_height) + { + int p_f_height = p->pixel_height - f->pixel_height; + + if (p_f_height <= 0) + pos_y = 0; + else + pos_y = (int)(p_f_height * height_factor * 0.5 + 0.5); + } + } - 5 means to never call x_set_window_size. change_frame_size uses - this. + f->top_pos = pos_y; + } - Note that even when x_set_window_size is not called, individual - windows may have to be resized (via `window--sanitize-window-sizes') - in order to support minimum size constraints. + x_set_offset (f, pos_x, pos_y, -1); + } - PRETEND is as for change_frame_size. PARAMETER, if non-nil, is the - symbol of the parameter changed (like `menu-bar-lines', `font', ...). - This is passed on to frame_inhibit_resize to let the latter decide on - a case-by-case basis whether the frame may be resized externally. */ + if (!CONSP (keep_ratio) || !NILP (Fcar (keep_ratio))) + { + if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qheight_only)) + pixel_width = -1; + else + { + pixel_width = (int)(f->pixel_width * width_factor + 0.5); + pixel_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixel_width); + } + + if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qwidth_only)) + pixel_height = -1; + else + { + pixel_height = (int)(f->pixel_height * height_factor + 0.5); + pixel_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixel_height); + } + + adjust_frame_size (f, pixel_width, pixel_height, 1, 0, + Qkeep_ratio); + } + } +} +#endif + + +/** + * adjust_frame_size: + * + * Adjust size of frame F. NEW_WIDTH and NEW_HEIGHT specify the new + * text size of F in pixels. A value of -1 means no change is requested + * for that direction (but the frame may still have to be resized to + * accommodate windows with their minimum sizes). This can either issue + * a request to resize the frame externally (via x_set_window_size), to + * resize the frame internally (via resize_frame_windows) or do nothing + * at all. + * + * The argument INHIBIT can assume the following values: + * + * 0 means to unconditionally call x_set_window_size even if sizes + * apparently do not change. Fx_create_frame uses this to pass the + * initial size to the window manager. + * + * 1 means to call x_set_window_size if the native frame size really + * changes. Fset_frame_size, Fset_frame_height, ... use this. + * + * 2 means to call x_set_window_size provided frame_inhibit_resize + * allows it. The menu and tool bar code use this ("3" won't work + * here in general because menu and tool bar are often not counted in + * the frame's text height). + * + * 3 means call x_set_window_size if window minimum sizes must be + * preserved or frame_inhibit_resize allows it. x_set_left_fringe, + * x_set_scroll_bar_width, x_new_font ... use (or should use) this. + * + * 4 means call x_set_window_size only if window minimum sizes must be + * preserved. x_set_right_divider_width, x_set_border_width and the + * code responsible for wrapping the tool bar use this. + * + * 5 means to never call x_set_window_size. change_frame_size uses + * this. + * + * Note that even when x_set_window_size is not called, individual + * windows may have to be resized (via `window--sanitize-window-sizes') + * in order to support minimum size constraints. + * + * PRETEND is as for change_frame_size. PARAMETER, if non-nil, is the + * symbol of the parameter changed (like `menu-bar-lines', `font', ...). + * This is passed on to frame_inhibit_resize to let the latter decide on + * a case-by-case basis whether the frame may be resized externally. + */ void adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, bool pretend, Lisp_Object parameter) @@ -636,6 +769,18 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, || new_pixel_height != old_pixel_height); unblock_input (); + +#ifdef HAVE_WINDOW_SYSTEM + { + /* Adjust size of F's child frames. */ + Lisp_Object frames, frame1; + + FOR_EACH_FRAME (frames, frame1) + if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f) + keep_ratio (XFRAME (frame1), old_pixel_width, old_pixel_height, + new_pixel_width, new_pixel_height); + } +#endif } /* Allocate basically initialized frame. */ @@ -684,6 +829,7 @@ make_frame (bool mini_p) f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; f->undecorated = false; + f->no_special_glyphs = false; #ifndef HAVE_NTGUI f->override_redirect = false; #endif @@ -2004,8 +2150,101 @@ The functions are run with one argument, the frame to be deleted. */) { return delete_frame (frame, !NILP (force) ? Qt : Qnil); } - +#ifdef HAVE_WINDOW_SYSTEM +/** + * frame_internal_border_part: + * + * Return part of internal border the coordinates X and Y relative to + * frame F are on. Return nil if the coordinates are not on the + * internal border of F. + * + * Return one of INTERNAL_BORDER_LEFT_EDGE, INTERNAL_BORDER_TOP_EDGE, + * INTERNAL_BORDER_RIGHT_EDGE or INTERNAL_BORDER_BOTTOM_EDGE when the + * mouse cursor is on the corresponding border with an offset of at + * least one canonical character height from that border's edges. + * + * If no border part could be found this way, return one of + * INTERNAL_BORDER_TOP_LEFT_CORNER, INTERNAL_BORDER_TOP_RIGHT_CORNER, + * INTERNAL_BORDER_BOTTOM_LEFT_CORNER or + * INTERNAL_BORDER_BOTTOM_RIGHT_CORNER to indicate that the mouse is in + * one of the corresponding corners. This means that for very small + * frames an `edge' return value is preferred. + */ +enum internal_border_part +frame_internal_border_part (struct frame *f, int x, int y) +{ + int border = FRAME_INTERNAL_BORDER_WIDTH (f); + int offset = FRAME_LINE_HEIGHT (f); + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + enum internal_border_part part = INTERNAL_BORDER_NONE; + + if (offset < border) + /* For very wide borders make offset at least as large as + border. */ + offset = border; + + if (offset < x && x < width - offset) + /* Top or bottom border. */ + { + if (0 <= y && y <= border) + part = INTERNAL_BORDER_TOP_EDGE; + else if (height - border <= y && y <= height) + part = INTERNAL_BORDER_BOTTOM_EDGE; + } + else if (offset < y && y < height - offset) + /* Left or right border. */ + { + if (0 <= x && x <= border) + part = INTERNAL_BORDER_LEFT_EDGE; + else if (width - border <= x && x <= width) + part = INTERNAL_BORDER_RIGHT_EDGE; + } + else + { + /* An edge. */ + int half_width = width / 2; + int half_height = height / 2; + + if (0 <= x && x <= border) + { + /* A left edge. */ + if (0 <= y && y <= half_height) + part = INTERNAL_BORDER_TOP_LEFT_CORNER; + else if (half_height < y && y <= height) + part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER; + } + else if (width - border <= x && x <= width) + { + /* A right edge. */ + if (0 <= y && y <= half_height) + part = INTERNAL_BORDER_TOP_RIGHT_CORNER; + else if (half_height < y && y <= height) + part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER; + } + else if (0 <= y && y <= border) + { + /* A top edge. */ + if (0 <= x && x <= half_width) + part = INTERNAL_BORDER_TOP_LEFT_CORNER; + else if (half_width < x && x <= width) + part = INTERNAL_BORDER_TOP_RIGHT_CORNER; + } + else if (height - border <= y && y <= height) + { + /* A bottom edge. */ + if (0 <= x && x <= half_width) + part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER; + else if (half_width < x && x <= width) + part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER; + } + } + + return part; +} +#endif + /* Return mouse position in character cell units. */ DEFUN ("mouse-position", Fmouse_position, Smouse_position, 0, 0, 0, @@ -2962,49 +3201,47 @@ For a terminal screen, the value is always 1. */) return make_number (1); } -DEFUN ("frame-pixel-height", Fframe_pixel_height, - Sframe_pixel_height, 0, 1, 0, - doc: /* Return a FRAME's height in pixels. -If FRAME is omitted or nil, the selected frame is used. The exact value -of the result depends on the window-system and toolkit in use: - -In the Gtk+ version of Emacs, it includes only any window (including -the minibuffer or echo area), mode line, and header line. It does not -include the tool bar or menu bar. - -With other graphical versions, it also includes the tool bar and the -menu bar. - -For a text terminal, it includes the menu bar. In this case, the -result is really in characters rather than pixels (i.e., is identical -to `frame-height'). */) +DEFUN ("frame-native-width", Fframe_native_width, + Sframe_native_width, 0, 1, 0, + doc: /* Return FRAME's native width in pixels. +For a terminal frame, the result really gives the width in characters. +If FRAME is omitted or nil, the selected frame is used. */) (Lisp_Object frame) { struct frame *f = decode_any_frame (frame); #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) - return make_number (FRAME_PIXEL_HEIGHT (f)); + return make_number (FRAME_PIXEL_WIDTH (f)); else #endif - return make_number (FRAME_TOTAL_LINES (f)); + return make_number (FRAME_TOTAL_COLS (f)); } -DEFUN ("frame-pixel-width", Fframe_pixel_width, - Sframe_pixel_width, 0, 1, 0, - doc: /* Return FRAME's width in pixels. -For a terminal frame, the result really gives the width in characters. -If FRAME is omitted or nil, the selected frame is used. */) +DEFUN ("frame-native-height", Fframe_native_height, + Sframe_native_height, 0, 1, 0, + doc: /* Return FRAME's native height in pixels. +If FRAME is omitted or nil, the selected frame is used. The exact value +of the result depends on the window-system and toolkit in use: + +In the Gtk+ and NS versions, it includes only any window (including the +minibuffer or echo area), mode line, and header line. It does not +include the tool bar or menu bar. With other graphical versions, it may +also include the tool bar and the menu bar. + +For a text terminal, it includes the menu bar. In this case, the +result is really in characters rather than pixels (i.e., is identical +to `frame-height'). */) (Lisp_Object frame) { struct frame *f = decode_any_frame (frame); #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) - return make_number (FRAME_PIXEL_WIDTH (f)); + return make_number (FRAME_PIXEL_HEIGHT (f)); else #endif - return make_number (FRAME_TOTAL_COLS (f)); + return make_number (FRAME_TOTAL_LINES (f)); } DEFUN ("tool-bar-pixel-width", Ftool_bar_pixel_width, @@ -3087,8 +3324,8 @@ DEFUN ("frame-fringe-width", Ffringe_width, Sfringe_width, 0, 1, 0, return make_number (FRAME_TOTAL_FRINGE_WIDTH (decode_any_frame (frame))); } -DEFUN ("frame-border-width", Fborder_width, Sborder_width, 0, 1, 0, - doc: /* Return border width of FRAME in pixels. */) +DEFUN ("frame-internal-border-width", Fframe_internal_border_width, Sframe_internal_border_width, 0, 1, 0, + doc: /* Return width of FRAME's internal border in pixels. */) (Lisp_Object frame) { return make_number (FRAME_INTERNAL_BORDER_WIDTH (decode_any_frame (frame))); @@ -3224,7 +3461,6 @@ bottom edge of FRAME's display. */) return Qt; } - /*********************************************************************** Frame Parameters @@ -3289,10 +3525,193 @@ static const struct frame_parm_table frame_parms[] = {"no-accept-focus", SYMBOL_INDEX (Qno_accept_focus)}, {"z-group", SYMBOL_INDEX (Qz_group)}, {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, + {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, }; #ifdef HAVE_WINDOW_SYSTEM +/* Enumeration type for switch in frame_float. */ +enum frame_float_type +{ + FRAME_FLOAT_WIDTH, + FRAME_FLOAT_HEIGHT, + FRAME_FLOAT_LEFT, + FRAME_FLOAT_TOP +}; + +/** + * frame_float: + * + * Process the value VAL of the float type frame parameter 'width', + * 'height', 'left', or 'top' specified via a frame_float_type + * enumeration type WHAT for frame F. Such parameters relate the outer + * size or position of F to the size of the F's display or parent frame + * which have to be both available in some way. + * + * The return value is a size or position value in pixels. VAL must be + * in the range 0.0 to 1.0 where a width/height of 0.0 means to return 0 + * and 1.0 means to return the full width/height of the display/parent. + * For positions, 0.0 means position in the left/top corner of the + * display/parent while 1.0 means to position at the right/bottom corner + * of the display/parent frame. + * + * Set PARENT_DONE and OUTER_DONE to avoid recalculation of the outer + * size or parent or display attributes when more float parameters are + * calculated in a row: -1 means not processed yet, 0 means processing + * failed, 1 means processing succeeded. + * + * Return DEFAULT_VALUE when processing fails for whatever reason with + * one exception: When calculating F's outer edges fails (probably + * because F has not been created yet) return the difference between F's + * native and text size. + */ +static int +frame_float (struct frame *f, Lisp_Object val, enum frame_float_type what, + int *parent_done, int *outer_done, int default_value) +{ + double d_val = XFLOAT_DATA (val); + + if (d_val < 0.0 || d_val > 1.0) + /* Invalid VAL. */ + return default_value; + else + { + static unsigned parent_width, parent_height; + static int parent_left, parent_top; + static unsigned outer_minus_text_width, outer_minus_text_height; + struct frame *p = FRAME_PARENT_FRAME (f); + + if (*parent_done == 1) + ; + else if (p) + { + parent_width = FRAME_PIXEL_WIDTH (p); + parent_height = FRAME_PIXEL_HEIGHT (p); + *parent_done = 1; + } + else + { + if (*parent_done == 0) + /* No workarea available. */ + return default_value; + else if (*parent_done == -1) + { + Lisp_Object monitor_attributes; + Lisp_Object workarea; + Lisp_Object frame; + + XSETFRAME (frame, f); + monitor_attributes = Fcar (call1 (Qdisplay_monitor_attributes_list, frame)); + if (NILP (monitor_attributes)) + { + /* No monitor attributes available. */ + *parent_done = 0; + + return default_value; + } + + workarea = Fcdr (Fassq (Qworkarea, monitor_attributes)); + if (NILP (workarea)) + { + /* No workarea available. */ + *parent_done = 0; + + return default_value; + } + + /* Workarea available. */ + parent_left = XINT (Fnth (make_number (0), workarea)); + parent_top = XINT (Fnth (make_number (1), workarea)); + parent_width = XINT (Fnth (make_number (2), workarea)); + parent_height = XINT (Fnth (make_number (3), workarea)); + *parent_done = 1; + } + } + + if (*outer_done == 1) + ; + else if (FRAME_UNDECORATED (f)) + { + outer_minus_text_width + = FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f); + outer_minus_text_height + = FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f); + *outer_done = 1; + } + else if (*outer_done == 0) + /* No outer size available. */ + return default_value; + else if (*outer_done == -1) + { + Lisp_Object frame, outer_edges; + + XSETFRAME (frame, f); + outer_edges = call2 (Qframe_edges, frame, Qouter_edges); + + if (!NILP (outer_edges)) + { + outer_minus_text_width + = (XINT (Fnth (make_number (2), outer_edges)) + - XINT (Fnth (make_number (0), outer_edges)) + - FRAME_TEXT_WIDTH (f)); + outer_minus_text_height + = (XINT (Fnth (make_number (3), outer_edges)) + - XINT (Fnth (make_number (1), outer_edges)) + - FRAME_TEXT_HEIGHT (f)); + } + else + { + /* If we can't get any outer edges, proceed as if the frame + were undecorated. */ + outer_minus_text_width + = FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f); + outer_minus_text_height + = FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f); + } + + *outer_done = 1; + } + + switch (what) + { + case FRAME_FLOAT_WIDTH: + return parent_width * d_val - outer_minus_text_width; + + case FRAME_FLOAT_HEIGHT: + return parent_height * d_val - outer_minus_text_height; + + case FRAME_FLOAT_LEFT: + { + int rest_width = (parent_width + - FRAME_TEXT_WIDTH (f) + - outer_minus_text_width); + + if (p) + return (rest_width <= 0 ? 0 : d_val * rest_width); + else + return (rest_width <= 0 + ? parent_left + : parent_left + d_val * rest_width); + } + case FRAME_FLOAT_TOP: + { + int rest_height = (parent_height + - FRAME_TEXT_HEIGHT (f) + - outer_minus_text_height); + + if (p) + return (rest_height <= 0 ? 0 : d_val * rest_height); + else + return (rest_height <= 0 + ? parent_top + : parent_top + d_val * rest_height); + } + default: + emacs_abort (); + } + } +} + /* Change the parameters of frame F as specified by ALIST. If a parameter is not specially recognized, do nothing special; otherwise call the `x_set_...' function for that parameter. @@ -3302,7 +3721,8 @@ static const struct frame_parm_table frame_parms[] = void x_set_frame_parameters (struct frame *f, Lisp_Object alist) { - Lisp_Object tail; + Lisp_Object tail, frame; + /* If both of these parameters are present, it's more efficient to set them both at once. So we wait until we've looked at the @@ -3327,7 +3747,9 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) #ifdef HAVE_X_WINDOWS bool icon_left_no_change = 0, icon_top_no_change = 0; #endif + int parent_done = -1, outer_done = -1; + XSETFRAME (frame, f); for (size = 0, tail = alist; CONSP (tail); tail = XCDR (tail)) size++; CHECK_LIST_END (tail, alist); @@ -3388,6 +3810,9 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels) && RANGED_INTEGERP (0, XCDR (val), INT_MAX)) width = XFASTINT (XCDR (val)); + else if (FLOATP (val)) + width = frame_float (f, val, FRAME_FLOAT_WIDTH, &parent_done, + &outer_done, -1); } else if (EQ (prop, Qheight)) { @@ -3396,6 +3821,9 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels) && RANGED_INTEGERP (0, XCDR (val), INT_MAX)) height = XFASTINT (XCDR (val)); + else if (FLOATP (val)) + height = frame_float (f, val, FRAME_FLOAT_HEIGHT, &parent_done, + &outer_done, -1); } else if (EQ (prop, Qtop)) top = val; @@ -3472,105 +3900,100 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) Don't set these parameters unless they actually differ from the window's current parameters; the window may not actually exist yet. */ - { - Lisp_Object frame; - - XSETFRAME (frame, f); - - if ((width != -1 && width != FRAME_TEXT_WIDTH (f)) - || (height != -1 && height != FRAME_TEXT_HEIGHT (f))) - /* We could consider checking f->after_make_frame here, but I - don't have the faintest idea why the following is needed at - all. With the old setting it can get a Heisenbug when - EmacsFrameResize intermittently provokes a delayed - change_frame_size in the middle of adjust_frame_size. */ - /** || (f->can_x_set_window_size && (f->new_height || f->new_width))) **/ - adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters); - - if ((!NILP (left) || !NILP (top)) - && ! (left_no_change && top_no_change) - && ! (NUMBERP (left) && XINT (left) == f->left_pos - && NUMBERP (top) && XINT (top) == f->top_pos)) - { - int leftpos = 0; - int toppos = 0; + if ((width != -1 && width != FRAME_TEXT_WIDTH (f)) + || (height != -1 && height != FRAME_TEXT_HEIGHT (f))) + /* We could consider checking f->after_make_frame here, but I + don't have the faintest idea why the following is needed at + all. With the old setting it can get a Heisenbug when + EmacsFrameResize intermittently provokes a delayed + change_frame_size in the middle of adjust_frame_size. */ + /** || (f->can_x_set_window_size && (f->new_height || f->new_width))) **/ + adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters); + + if ((!NILP (left) || !NILP (top)) + && ! (left_no_change && top_no_change) + && ! (NUMBERP (left) && XINT (left) == f->left_pos + && NUMBERP (top) && XINT (top) == f->top_pos)) + { + int leftpos = 0; + int toppos = 0; - /* Record the signs. */ - f->size_hint_flags &= ~ (XNegative | YNegative); - if (EQ (left, Qminus)) - f->size_hint_flags |= XNegative; - else if (TYPE_RANGED_INTEGERP (int, left)) - { - leftpos = XINT (left); - if (leftpos < 0) - f->size_hint_flags |= XNegative; - } - else if (CONSP (left) && EQ (XCAR (left), Qminus) - && CONSP (XCDR (left)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) - { - leftpos = - XINT (XCAR (XCDR (left))); + /* Record the signs. */ + f->size_hint_flags &= ~ (XNegative | YNegative); + if (EQ (left, Qminus)) + f->size_hint_flags |= XNegative; + else if (TYPE_RANGED_INTEGERP (int, left)) + { + leftpos = XINT (left); + if (leftpos < 0) f->size_hint_flags |= XNegative; - } - else if (CONSP (left) && EQ (XCAR (left), Qplus) - && CONSP (XCDR (left)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) - { - leftpos = XINT (XCAR (XCDR (left))); - } + } + else if (CONSP (left) && EQ (XCAR (left), Qminus) + && CONSP (XCDR (left)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) + { + leftpos = - XINT (XCAR (XCDR (left))); + f->size_hint_flags |= XNegative; + } + else if (CONSP (left) && EQ (XCAR (left), Qplus) + && CONSP (XCDR (left)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) + leftpos = XINT (XCAR (XCDR (left))); + else if (FLOATP (left)) + leftpos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done, + &outer_done, 0); - if (EQ (top, Qminus)) - f->size_hint_flags |= YNegative; - else if (TYPE_RANGED_INTEGERP (int, top)) - { - toppos = XINT (top); - if (toppos < 0) - f->size_hint_flags |= YNegative; - } - else if (CONSP (top) && EQ (XCAR (top), Qminus) - && CONSP (XCDR (top)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) - { - toppos = - XINT (XCAR (XCDR (top))); + if (EQ (top, Qminus)) + f->size_hint_flags |= YNegative; + else if (TYPE_RANGED_INTEGERP (int, top)) + { + toppos = XINT (top); + if (toppos < 0) f->size_hint_flags |= YNegative; - } - else if (CONSP (top) && EQ (XCAR (top), Qplus) - && CONSP (XCDR (top)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) - { - toppos = XINT (XCAR (XCDR (top))); - } - + } + else if (CONSP (top) && EQ (XCAR (top), Qminus) + && CONSP (XCDR (top)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) + { + toppos = - XINT (XCAR (XCDR (top))); + f->size_hint_flags |= YNegative; + } + else if (CONSP (top) && EQ (XCAR (top), Qplus) + && CONSP (XCDR (top)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) + toppos = XINT (XCAR (XCDR (top))); + else if (FLOATP (top)) + toppos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done, + &outer_done, 0); - /* Store the numeric value of the position. */ - f->top_pos = toppos; - f->left_pos = leftpos; + /* Store the numeric value of the position. */ + f->top_pos = toppos; + f->left_pos = leftpos; - f->win_gravity = NorthWestGravity; + f->win_gravity = NorthWestGravity; - /* Actually set that position, and convert to absolute. */ - x_set_offset (f, leftpos, toppos, -1); - } + /* Actually set that position, and convert to absolute. */ + x_set_offset (f, leftpos, toppos, -1); + } - if (fullscreen_change) - { - Lisp_Object old_value = get_frame_param (f, Qfullscreen); + if (fullscreen_change) + { + Lisp_Object old_value = get_frame_param (f, Qfullscreen); - frame_size_history_add - (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen)); + frame_size_history_add + (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen)); - store_frame_param (f, Qfullscreen, fullscreen); - if (!EQ (fullscreen, old_value)) - x_set_fullscreen (f, fullscreen, old_value); - } + store_frame_param (f, Qfullscreen, fullscreen); + if (!EQ (fullscreen, old_value)) + x_set_fullscreen (f, fullscreen, old_value); + } #ifdef HAVE_X_WINDOWS - if ((!NILP (icon_left) || !NILP (icon_top)) - && ! (icon_left_no_change && icon_top_no_change)) - x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top)); + if ((!NILP (icon_left) || !NILP (icon_top)) + && ! (icon_left_no_change && icon_top_no_change)) + x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top)); #endif /* HAVE_X_WINDOWS */ - } SAFE_FREE (); } @@ -3990,7 +4413,6 @@ x_set_right_divider_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) adjust_frame_glyphs (f); SET_FRAME_GARBAGED (f); } - } void @@ -4204,6 +4626,22 @@ x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) return; } + +/** + * x_set_no_special_glyphs: + * + * Set frame F's `no-special-glyphs' parameter which, if non-nil, + * suppresses the display of truncation and continuation glyphs + * outside fringes. + */ +void +x_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + FRAME_NO_SPECIAL_GLYPHS (f) = !NILP (new_value); +} + + #ifndef HAVE_NS /* Non-zero if mouse is grabbed on DPYINFO @@ -4759,6 +5197,7 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, int *x Lisp_Object height, width, user_size, top, left, user_position; long window_prompting = 0; Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); + int parent_done = -1, outer_done = -1; /* Default values if we fall through. Actually, if that happens we should get @@ -4823,6 +5262,21 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, int *x f->inhibit_horizontal_resize = true; *x_width = XINT (XCDR (width)); } + else if (FLOATP (width)) + { + double d_width = XFLOAT_DATA (width); + + if (d_width < 0.0 || d_width > 1.0) + xsignal1 (Qargs_out_of_range, width); + else + { + int new_width = frame_float (f, width, FRAME_FLOAT_WIDTH, + &parent_done, &outer_done, -1); + + if (new_width > -1) + SET_FRAME_WIDTH (f, new_width); + } + } else { CHECK_NUMBER (width); @@ -4845,6 +5299,21 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, int *x f->inhibit_vertical_resize = true; *x_height = XINT (XCDR (height)); } + else if (FLOATP (height)) + { + double d_height = XFLOAT_DATA (height); + + if (d_height < 0.0 || d_height > 1.0) + xsignal1 (Qargs_out_of_range, height); + else + { + int new_height = frame_float (f, height, FRAME_FLOAT_HEIGHT, + &parent_done, &outer_done, -1); + + if (new_height > -1) + SET_FRAME_HEIGHT (f, new_height); + } + } else { CHECK_NUMBER (height); @@ -4885,6 +5354,9 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, int *x { f->top_pos = XINT (XCAR (XCDR (top))); } + else if (FLOATP (top)) + f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done, + &outer_done, 0); else if (EQ (top, Qunbound)) f->top_pos = 0; else @@ -4913,6 +5385,9 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p, int *x { f->left_pos = XINT (XCAR (XCDR (left))); } + else if (FLOATP (left)) + f->left_pos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done, + &outer_done, 0); else if (EQ (left, Qunbound)) f->left_pos = 0; else @@ -5071,12 +5546,14 @@ syms_of_frame (void) DEFSYM (Qframep, "framep"); DEFSYM (Qframe_live_p, "frame-live-p"); DEFSYM (Qframe_windows_min_size, "frame-windows-min-size"); + DEFSYM (Qdisplay_monitor_attributes_list, "display-monitor-attributes-list"); DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total"); DEFSYM (Qexplicit_name, "explicit-name"); DEFSYM (Qheight, "height"); DEFSYM (Qicon, "icon"); DEFSYM (Qminibuffer, "minibuffer"); DEFSYM (Qundecorated, "undecorated"); + DEFSYM (Qno_special_glyphs, "no-special-glyphs"); DEFSYM (Qparent_frame, "parent-frame"); DEFSYM (Qskip_taskbar, "skip-taskbar"); DEFSYM (Qno_focus_on_map, "no-focus-on-map"); @@ -5129,6 +5606,7 @@ syms_of_frame (void) DEFSYM (Qframes, "frames"); DEFSYM (Qsource, "source"); + DEFSYM (Qframe_edges, "frame-edges"); DEFSYM (Qouter_edges, "outer-edges"); DEFSYM (Qouter_position, "outer-position"); DEFSYM (Qouter_size, "outer-size"); @@ -5220,6 +5698,11 @@ syms_of_frame (void) DEFSYM (Qmin_width, "min-width"); DEFSYM (Qmin_height, "min-height"); DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame"); + DEFSYM (Qkeep_ratio, "keep-ratio"); + DEFSYM (Qwidth_only, "width-only"); + DEFSYM (Qheight_only, "height-only"); + DEFSYM (Qleft_only, "left-only"); + DEFSYM (Qtop_only, "top-only"); { int i; @@ -5564,8 +6047,8 @@ Gtk+ tooltips are not used) and on Windows. */); defsubr (&Smodify_frame_parameters); defsubr (&Sframe_char_height); defsubr (&Sframe_char_width); - defsubr (&Sframe_pixel_height); - defsubr (&Sframe_pixel_width); + defsubr (&Sframe_native_height); + defsubr (&Sframe_native_width); defsubr (&Sframe_text_cols); defsubr (&Sframe_text_lines); defsubr (&Sframe_total_cols); @@ -5575,7 +6058,7 @@ Gtk+ tooltips are not used) and on Windows. */); defsubr (&Sscroll_bar_width); defsubr (&Sscroll_bar_height); defsubr (&Sfringe_width); - defsubr (&Sborder_width); + defsubr (&Sframe_internal_border_width); defsubr (&Sright_divider_width); defsubr (&Sbottom_divider_width); defsubr (&Stool_bar_pixel_width); diff --git a/src/frame.h b/src/frame.h index 4aa7c34a29a..2feb09b2e67 100644 --- a/src/frame.h +++ b/src/frame.h @@ -52,6 +52,19 @@ enum z_group z_group_below, z_group_above_suspended, }; + +enum internal_border_part + { + INTERNAL_BORDER_NONE, + INTERNAL_BORDER_LEFT_EDGE, + INTERNAL_BORDER_TOP_LEFT_CORNER, + INTERNAL_BORDER_TOP_EDGE, + INTERNAL_BORDER_TOP_RIGHT_CORNER, + INTERNAL_BORDER_RIGHT_EDGE, + INTERNAL_BORDER_BOTTOM_RIGHT_CORNER, + INTERNAL_BORDER_BOTTOM_EDGE, + INTERNAL_BORDER_BOTTOM_LEFT_CORNER, + }; #endif /* HAVE_WINDOW_SYSTEM */ /* The structure representing a frame. */ @@ -354,7 +367,11 @@ struct frame /* The z-group this frame's window belongs to. */ ENUM_BF (z_group) z_group : 2; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ + + /* Non-zero if display of truncation and continuation glyphs outside + the fringes is suppressed. */ + bool_bf no_special_glyphs : 1; +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether new_height and new_width shall be interpreted in pixels. */ @@ -928,6 +945,7 @@ default_pixels_per_inch_y (void) #define FRAME_SKIP_TASKBAR(f) ((f)->skip_taskbar) #define FRAME_NO_FOCUS_ON_MAP(f) ((f)->no_focus_on_map) #define FRAME_NO_ACCEPT_FOCUS(f) ((f)->no_accept_focus) +#define FRAME_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs) #define FRAME_Z_GROUP(f) ((f)->z_group) #define FRAME_Z_GROUP_NONE(f) ((f)->z_group == z_group_none) #define FRAME_Z_GROUP_ABOVE(f) ((f)->z_group == z_group_above) @@ -941,6 +959,7 @@ default_pixels_per_inch_y (void) #define FRAME_SKIP_TASKBAR(f) ((void) f, 0) #define FRAME_NO_FOCUS_ON_MAP(f) ((void) f, 0) #define FRAME_NO_ACCEPT_FOCUS(f) ((void) f, 0) +#define FRAME_NO_SPECIAL_GLYPHS(f) ((void) f, 0) #define FRAME_Z_GROUP(f) ((void) f, z_group_none) #define FRAME_Z_GROUP_NONE(f) ((void) f, true) #define FRAME_Z_GROUP_ABOVE(f) ((void) f, false) @@ -1288,19 +1307,20 @@ FRAME_TOTAL_FRINGE_WIDTH (struct frame *f) return FRAME_LEFT_FRINGE_WIDTH (f) + FRAME_RIGHT_FRINGE_WIDTH (f); } -/* Pixel-width of internal border lines */ +/* Pixel-width of internal border lines. */ INLINE int FRAME_INTERNAL_BORDER_WIDTH (struct frame *f) { return frame_dimension (f->internal_border_width); } -/* Pixel-size of window divider lines */ +/* Pixel-size of window divider lines. */ INLINE int FRAME_RIGHT_DIVIDER_WIDTH (struct frame *f) { return frame_dimension (f->right_divider_width); } + INLINE int FRAME_BOTTOM_DIVIDER_WIDTH (struct frame *f) { @@ -1498,6 +1518,7 @@ extern void x_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object); extern long x_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *); extern void x_set_alpha (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object); extern void validate_x_resource_name (void); @@ -1521,6 +1542,7 @@ extern void x_real_positions (struct frame *, int *, int *); extern void free_frame_menubar (struct frame *); extern void x_free_frame_resources (struct frame *); extern bool frame_ancestor_p (struct frame *af, struct frame *df); +extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y); #if defined HAVE_X_WINDOWS extern void x_wm_set_icon_position (struct frame *, int, int); diff --git a/src/gtkutil.c b/src/gtkutil.c index 16eb284d7c7..2d4abefa969 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1503,6 +1503,7 @@ xg_set_undecorated (struct frame *f, Lisp_Object undecorated) void xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) { +#if GTK_CHECK_VERSION (2, 18, 0) block_input (); if (FRAME_GTK_OUTER_WIDGET (f1) && FRAME_GTK_OUTER_WIDGET (f2)) { @@ -1517,6 +1518,7 @@ xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) x_sync (f1); } unblock_input (); +#endif } diff --git a/src/keyboard.c b/src/keyboard.c index 3442b18409a..9e90899c569 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5127,6 +5127,17 @@ static short const scroll_bar_parts[] = { SYMBOL_INDEX (Qrightmost), SYMBOL_INDEX (Qend_scroll), SYMBOL_INDEX (Qratio) }; +/* An array of symbol indexes of internal border parts, indexed by an enum + internal_border_part value. Note that Qnil corresponds to + internal_border_part_none and should not appear in Lisp events. */ +static short const internal_border_parts[] = { + SYMBOL_INDEX (Qnil), SYMBOL_INDEX (Qleft_edge), + SYMBOL_INDEX (Qtop_left_corner), SYMBOL_INDEX (Qtop_edge), + SYMBOL_INDEX (Qtop_right_corner), SYMBOL_INDEX (Qright_edge), + SYMBOL_INDEX (Qbottom_right_corner), SYMBOL_INDEX (Qbottom_edge), + SYMBOL_INDEX (Qbottom_left_corner) +}; + /* A vector, indexed by button number, giving the down-going location of currently depressed buttons, both scroll bar and non-scroll bar. @@ -5164,15 +5175,15 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, Lisp_Object extra_info = Qnil; /* Coordinate pixel positions to return. */ int xret = 0, yret = 0; - /* The window under frame pixel coordinates (x,y) */ - Lisp_Object window = f + /* The window or frame under frame pixel coordinates (x,y) */ + Lisp_Object window_or_frame = f ? window_from_coordinates (f, XINT (x), XINT (y), &part, 0) : Qnil; - if (WINDOWP (window)) + if (WINDOWP (window_or_frame)) { /* It's a click in window WINDOW at frame coordinates (X,Y) */ - struct window *w = XWINDOW (window); + struct window *w = XWINDOW (window_or_frame); Lisp_Object string_info = Qnil; ptrdiff_t textpos = 0; int col = -1, row = -1; @@ -5361,17 +5372,31 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y, make_number (row)), extra_info))); } - else if (f != 0) + +#ifdef HAVE_WINDOW_SYSTEM + else if (f) { /* Return mouse pixel coordinates here. */ - XSETFRAME (window, f); + XSETFRAME (window_or_frame, f); xret = XINT (x); yret = XINT (y); + + if (FRAME_LIVE_P (f) + && FRAME_INTERNAL_BORDER_WIDTH (f) > 0 + && !NILP (get_frame_param (f, Qdrag_internal_border))) + { + enum internal_border_part part + = frame_internal_border_part (f, xret, yret); + + posn = builtin_lisp_symbol (internal_border_parts[part]); + } } +#endif + else - window = Qnil; + window_or_frame = Qnil; - return Fcons (window, + return Fcons (window_or_frame, Fcons (posn, Fcons (Fcons (make_number (xret), make_number (yret)), @@ -11159,6 +11184,17 @@ syms_of_keyboard (void) Fset (Qinput_method_exit_on_first_char, Qnil); Fset (Qinput_method_use_echo_area, Qnil); + /* Symbols for dragging internal borders. */ + DEFSYM (Qdrag_internal_border, "drag-internal-border"); + DEFSYM (Qleft_edge, "left-edge"); + DEFSYM (Qtop_left_corner, "top-left-corner"); + DEFSYM (Qtop_edge, "top-edge"); + DEFSYM (Qtop_right_corner, "top-right-corner"); + DEFSYM (Qright_edge, "right-edge"); + DEFSYM (Qbottom_right_corner, "bottom-right-corner"); + DEFSYM (Qbottom_edge, "bottom-edge"); + DEFSYM (Qbottom_left_corner, "bottom-left-corner"); + /* Symbols to head events. */ DEFSYM (Qmouse_movement, "mouse-movement"); DEFSYM (Qscroll_bar_movement, "scroll-bar-movement"); diff --git a/src/minibuf.c b/src/minibuf.c index 835992fa79d..d4128ce01c1 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -874,6 +874,30 @@ read_minibuf_unwind (void) if (minibuf_level == 0) resize_mini_window (XWINDOW (window), 0); + /* Deal with frames that should be removed when exiting the + minibuffer. */ + { + Lisp_Object frames, frame1, val; + struct frame *f1; + + FOR_EACH_FRAME (frames, frame1) + { + f1 = XFRAME (frame1); + + if ((FRAME_PARENT_FRAME (f1) + || !NILP (get_frame_param (f1, Qdelete_before))) + && !NILP (val = (get_frame_param (f1, Qminibuffer_exit)))) + { + if (EQ (val, Qiconify_frame)) + Ficonify_frame (frame1); + else if (EQ (val, Qdelete_frame)) + Fdelete_frame (frame1, Qnil); + else + Fmake_frame_invisible (frame1, Qnil); + } + } + } + /* In case the previous minibuffer displayed in this miniwindow is dead, we may keep displaying this buffer (tho it's inactive), so reset it, to make sure we don't leave around bindings and stuff which only @@ -1930,6 +1954,8 @@ syms_of_minibuf (void) DEFSYM (Qactivate_input_method, "activate-input-method"); DEFSYM (Qcase_fold_search, "case-fold-search"); DEFSYM (Qmetadata, "metadata"); + /* A frame parameter. */ + DEFSYM (Qminibuffer_exit, "minibuffer-exit"); DEFVAR_LISP ("read-expression-history", Vread_expression_history, doc: /* A history list for arguments that are Lisp expressions to evaluate. diff --git a/src/nsfns.m b/src/nsfns.m index dbce279da63..68eba8b6a2e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -984,6 +984,7 @@ frame_parm_handler ns_frame_parm_handlers[] = x_set_no_accept_focus, x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; @@ -1256,6 +1257,8 @@ This function is an internal primitive--use `make-frame' instead. */) "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); init_frame_faces (f); @@ -1325,6 +1328,15 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor]; f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor]; f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor]; + FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor = [NSCursor arrowCursor]; FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor diff --git a/src/nsterm.h b/src/nsterm.h index bed0b92c796..84f7f0ab574 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -957,6 +957,14 @@ struct ns_output Cursor hourglass_cursor; Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* NS-specific */ Cursor current_pointer; diff --git a/src/w32fns.c b/src/w32fns.c index e490588d01b..b0842b5ee6c 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -5889,6 +5889,8 @@ This function is an internal primitive--use `make-frame' instead. */) NULL, NULL, RES_TYPE_BOOLEAN); x_default_parameter (f, parameters, Qno_accept_focus, Qnil, NULL, NULL, RES_TYPE_BOOLEAN); + x_default_parameter (f, parameters, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); /* Process alpha here (Bug#16619). On XP this fails with child frames. For `no-focus-on-map' frames delay processing of alpha @@ -5957,6 +5959,14 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT); f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE); f->output_data.w32->vertical_drag_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->left_edge_cursor = w32_load_cursor (IDC_SIZEWE); + f->output_data.w32->top_left_corner_cursor = w32_load_cursor (IDC_SIZENWSE); + f->output_data.w32->top_edge_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->top_right_corner_cursor = w32_load_cursor (IDC_SIZENESW); + f->output_data.w32->right_edge_cursor = w32_load_cursor (IDC_SIZEWE); + f->output_data.w32->bottom_right_corner_cursor = w32_load_cursor (IDC_SIZENWSE); + f->output_data.w32->bottom_edge_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->bottom_left_corner_cursor = w32_load_cursor (IDC_SIZENESW); f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor; @@ -7049,6 +7059,8 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qno_special_glyphs, Qt, + NULL, NULL, RES_TYPE_BOOLEAN); /* Init faces before x_default_parameter is called for the scroll-bar-width parameter because otherwise we end up in @@ -8950,33 +8962,47 @@ menu bar or tool bar of FRAME. */) if (EQ (type, Qouter_edges)) { RECT rectangle; + BOOL success = false; block_input (); /* Outer frame rectangle, including outer borders and title bar. */ - GetWindowRect (FRAME_W32_WINDOW (f), &rectangle); + success = GetWindowRect (FRAME_W32_WINDOW (f), &rectangle); unblock_input (); - return list4 (make_number (rectangle.left), - make_number (rectangle.top), - make_number (rectangle.right), - make_number (rectangle.bottom)); + if (success) + return list4 (make_number (rectangle.left), + make_number (rectangle.top), + make_number (rectangle.right), + make_number (rectangle.bottom)); + else + return Qnil; } else { RECT rectangle; POINT pt; int left, top, right, bottom; + BOOL success; block_input (); /* Inner frame rectangle, excluding borders and title bar. */ - GetClientRect (FRAME_W32_WINDOW (f), &rectangle); + success = GetClientRect (FRAME_W32_WINDOW (f), &rectangle); /* Get top-left corner of native rectangle in screen coordinates. */ + if (!success) + { + unblock_input (); + return Qnil; + } + pt.x = 0; pt.y = 0; - ClientToScreen (FRAME_W32_WINDOW (f), &pt); + success = ClientToScreen (FRAME_W32_WINDOW (f), &pt); unblock_input (); + if (!success) + return Qnil; + left = pt.x; top = pt.y; right = left + rectangle.right; @@ -10330,6 +10356,7 @@ frame_parm_handler w32_frame_parm_handlers[] = x_set_no_accept_focus, x_set_z_group, 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; void diff --git a/src/w32term.c b/src/w32term.c index 712bdae5fc3..c37805cb6ca 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5086,6 +5086,51 @@ w32_read_socket (struct terminal *terminal, } case WM_WINDOWPOSCHANGED: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + + if (f) + { + RECT rect; + int /* rows, columns, */ width, height, text_width, text_height; + + if (GetClientRect (msg.msg.hwnd, &rect) + /* GetClientRect evidently returns (0, 0, 0, 0) if + called on a minimized frame. Such "dimensions" + aren't useful anyway. */ + && !(rect.bottom == 0 + && rect.top == 0 + && rect.left == 0 + && rect.right == 0)) + { + height = rect.bottom - rect.top; + width = rect.right - rect.left; + text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width); + text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height); + /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */ + /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */ + + /* TODO: Clip size to the screen dimensions. */ + + /* Even if the number of character rows and columns + has not changed, the font size may have changed, + so we need to check the pixel dimensions as well. */ + + if (width != FRAME_PIXEL_WIDTH (f) + || height != FRAME_PIXEL_HEIGHT (f) + || text_width != FRAME_TEXT_WIDTH (f) + || text_height != FRAME_TEXT_HEIGHT (f)) + { + change_frame_size (f, text_width, text_height, 0, 1, 0, 1); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + f->win_gravity = NorthWestGravity; + } + } + } + + check_visibility = 1; + break; + case WM_ACTIVATE: case WM_ACTIVATEAPP: f = x_window_to_frame (dpyinfo, msg.msg.hwnd); @@ -6052,7 +6097,7 @@ x_calc_absolute_position (struct frame *f) int display_top = 0; struct frame *p = FRAME_PARENT_FRAME (f); - if (flags & (XNegative | YNegative)) + if (!p && flags & (XNegative | YNegative)) { Lisp_Object list; @@ -6078,20 +6123,26 @@ x_calc_absolute_position (struct frame *f) } /* Treat negative positions as relative to the rightmost bottommost - position that fits on the screen. */ + position that fits on the screen or parent frame. + + I see no need for subtracting 1 from the border widths - is there + any on the remaining platforms? Here these subtractions did put + the last pixel line/column of a frame off-display when, for + example, a (set-frame-parameter nil 'left '(- 0)) specification was + used - martin 20017-05-05. */ if (flags & XNegative) { if (p) f->left_pos = (FRAME_PIXEL_WIDTH (p) - FRAME_PIXEL_WIDTH (f) + f->left_pos - - (left_right_borders_width - 1)); + - left_right_borders_width); else f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f)) + display_left - FRAME_PIXEL_WIDTH (f) + f->left_pos - - (left_right_borders_width - 1)); + - left_right_borders_width); } if (flags & YNegative) @@ -6100,13 +6151,13 @@ x_calc_absolute_position (struct frame *f) f->top_pos = (FRAME_PIXEL_HEIGHT (p) - FRAME_PIXEL_HEIGHT (f) + f->top_pos - - (top_bottom_borders_height - 1)); + - top_bottom_borders_height); else f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f)) + display_top - FRAME_PIXEL_HEIGHT (f) + f->top_pos - - (top_bottom_borders_height - 1)); + - top_bottom_borders_height); } /* The left_pos and top_pos are now relative to the top and left diff --git a/src/w32term.h b/src/w32term.h index 371cf9005bc..9956682c5cd 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -345,6 +345,14 @@ struct w32_output Cursor hourglass_cursor; Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* Non-zero means hourglass cursor is currently displayed. */ unsigned hourglass_p : 1; diff --git a/src/window.c b/src/window.c index bf89f0e488b..4816bd69909 100644 --- a/src/window.c +++ b/src/window.c @@ -1208,13 +1208,13 @@ coordinates_in_window (register struct window *w, int x, int y) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) return ON_HORIZONTAL_SCROLL_BAR; /* On the mode or header line? */ - else if ((WINDOW_WANTS_MODELINE_P (w) + else if ((window_wants_mode_line (w) && y >= (bottom_y - CURRENT_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w) && (part = ON_MODE_LINE)) - || (WINDOW_WANTS_HEADER_LINE_P (w) + || (window_wants_header_line (w) && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w) && (part = ON_HEADER_LINE))) { @@ -1851,7 +1851,7 @@ Return nil if window display is not up-to-date. In that case, use if (EQ (line, Qheader_line)) { - if (!WINDOW_WANTS_HEADER_LINE_P (w)) + if (!window_wants_header_line (w)) return Qnil; row = MATRIX_HEADER_LINE_ROW (w->current_matrix); return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil; @@ -1898,6 +1898,129 @@ Return nil if window display is not up-to-date. In that case, use return list4i (row->height + min (0, row->y) - crop, i, row->y, crop); } +DEFUN ("window-lines-pixel-dimensions", Fwindow_lines_pixel_dimensions, Swindow_lines_pixel_dimensions, 0, 6, 0, + doc: /* Return pixel dimensions of WINDOW's lines. +The return value is a list of the x- and y-coordinates of the lower +right corner of the last character of each line. Return nil if the +current glyph matrix of WINDOW is not up-to-date. + +Optional argument WINDOW specifies the window whose lines' dimensions +shall be returned. Nil or omitted means to return the dimensions for +the selected window. + +FIRST, if non-nil, specifies the index of the first line whose +dimensions shall be returned. If FIRST is nil and BODY is non-nil, +start with the first text line of WINDOW. Otherwise, start with the +first line of WINDOW. + +LAST, if non-nil, specifies the last line whose dimensions shall be +returned. If LAST is nil and BODY is non-nil, the last line is the last +line of the body (text area) of WINDOW. Otherwise, last is the last +line of WINDOW. + +INVERSE, if nil, means that the y-pixel value returned for a specific +line specifies the distance in pixels from the left edge (body edge if +BODY is non-nil) of WINDOW to the right edge of the last glyph of that +line. INVERSE non-nil means that the y-pixel value returned for a +specific line specifies the distance in pixels from the right edge of +the last glyph of that line to the right edge (body edge if BODY is +non-nil) of WINDOW. + +LEFT non-nil means to return the x- and y-coordinates of the lower left +corner of the leftmost character on each line. This is the value that +should be used for buffers that mostly display text from right to left. + +If LEFT is non-nil and INVERSE is nil, this means that the y-pixel value +returned for a specific line specifies the distance in pixels from the +left edge of the last (leftmost) glyph of that line to the right edge +(body edge if BODY is non-nil) of WINDOW. If LEFT and INVERSE are both +non-nil, the y-pixel value returned for a specific line specifies the +distance in pixels from the left edge (body edge if BODY is non-nil) of +WINDOW to the left edge of the last (leftmost) glyph of that line. + +Normally, the value of this function is not available while Emacs is +busy, for example, when processing a command. It should be retrievable +though when run from an idle timer with a delay of zero seconds. */) + (Lisp_Object window, Lisp_Object first, Lisp_Object last, Lisp_Object body, Lisp_Object inverse, Lisp_Object left) +{ + struct window *w = decode_live_window (window); + struct buffer *b; + struct glyph_row *row, *end_row; + int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); + Lisp_Object rows = Qnil; + int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); + int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + int subtract = NILP (body) ? 0 : header_line_height; + bool invert = !NILP (inverse); + bool left_flag = !NILP (left); + + if (noninteractive || w->pseudo_window_p) + return Qnil; + + CHECK_BUFFER (w->contents); + b = XBUFFER (w->contents); + + /* Fail if current matrix is not up-to-date. */ + if (!w->window_end_valid + || windows_or_buffers_changed + || b->clip_changed + || b->prevent_redisplay_optimizations_p + || window_outdated (w)) + return Qnil; + + if (NILP (first)) + row = (NILP (body) + ? MATRIX_ROW (w->current_matrix, 0) + : MATRIX_FIRST_TEXT_ROW (w->current_matrix)); + else if (NUMBERP (first)) + { + CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows); + row = MATRIX_ROW (w->current_matrix, XINT (first)); + } + else + error ("Invalid specification of first line"); + + if (NILP (last)) + + end_row = (NILP (body) + ? MATRIX_ROW (w->current_matrix, w->current_matrix->nrows) + : MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)); + else if (NUMBERP (last)) + { + CHECK_RANGED_INTEGER (last, 0, w->current_matrix->nrows); + end_row = MATRIX_ROW (w->current_matrix, XINT (last)); + } + else + error ("Invalid specification of last line"); + + while (row <= end_row && row->enabled_p + && row->y + row->height < max_y) + { + + if (left_flag) + { + struct glyph *glyph = row->glyphs[TEXT_AREA]; + + rows = Fcons (Fcons (make_number + (invert + ? glyph->pixel_width + : window_width - glyph->pixel_width), + make_number (row->y + row->height - subtract)), + rows); + } + else + rows = Fcons (Fcons (make_number + (invert + ? window_width - row->pixel_width + : row->pixel_width), + make_number (row->y + row->height - subtract)), + rows); + row++; + } + + return Fnreverse (rows); +} + DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p, 0, 1, 0, doc: /* Return non-nil when WINDOW is dedicated to its buffer. @@ -2003,16 +2126,24 @@ return value is a list of elements of the form (PARAMETER . VALUE). */) return Fcopy_alist (decode_valid_window (window)->window_parameters); } +Lisp_Object +window_parameter (struct window *w, Lisp_Object parameter) +{ + Lisp_Object result = Fassq (parameter, w->window_parameters); + + return CDR_SAFE (result); +} + + DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter, 2, 2, 0, doc: /* Return WINDOW's value for PARAMETER. WINDOW can be any window and defaults to the selected one. */) (Lisp_Object window, Lisp_Object parameter) { - Lisp_Object result; + struct window *w = decode_any_window (window); - result = Fassq (parameter, decode_any_window (window)->window_parameters); - return CDR_SAFE (result); + return window_parameter (w, parameter); } DEFUN ("set-window-parameter", Fset_window_parameter, @@ -4740,6 +4871,69 @@ mark_window_cursors_off (struct window *w) } +/** + * window_wants_mode_line: + * + * Return 1 if window W wants a mode line and is high enough to + * accomodate it, 0 otherwise. + * + * W wants a mode line if it's a leaf window and neither a minibuffer + * nor a pseudo window. Moreover, its 'window-mode-line-format' + * parameter must not be 'none' and either that parameter or W's + * buffer's 'mode-line-format' value must be non-nil. Finally, W must + * be higher than its frame's canonical character height. + */ +bool +window_wants_mode_line (struct window *w) +{ + Lisp_Object window_mode_line_format = + window_parameter (w, Qmode_line_format); + + return ((WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_mode_line_format, Qnone) + && (!NILP (window_mode_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), mode_line_format))) + && WINDOW_PIXEL_HEIGHT (w) > WINDOW_FRAME_LINE_HEIGHT (w)) + ? 1 + : 0); +} + + +/** + * window_wants_header_line: + * + * Return 1 if window W wants a header line and is high enough to + * accomodate it, 0 otherwise. + * + * W wants a header line if it's a leaf window and neither a minibuffer + * nor a pseudo window. Moreover, its 'window-mode-line-format' + * parameter must not be 'none' and either that parameter or W's + * buffer's 'mode-line-format' value must be non-nil. Finally, W must + * be higher than its frame's canonical character height and be able to + * accomodate a mode line too if necessary (the mode line prevails). + */ +bool +window_wants_header_line (struct window *w) +{ + Lisp_Object window_header_line_format = + window_parameter (w, Qheader_line_format); + + return ((WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_header_line_format, Qnone) + && (!NILP (window_header_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format))) + && (WINDOW_PIXEL_HEIGHT (w) + > (window_wants_mode_line (w) + ? 2 * WINDOW_FRAME_LINE_HEIGHT (w) + : WINDOW_FRAME_LINE_HEIGHT (w)))) + ? 1 + : 0); +} + /* Return number of lines of text (not counting mode lines) in W. */ int @@ -4753,10 +4947,10 @@ window_internal_height (struct window *w) || WINDOWP (w->contents) || !NILP (w->next) || !NILP (w->prev) - || WINDOW_WANTS_MODELINE_P (w)) + || window_wants_mode_line (w)) --ht; - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) --ht; } @@ -7354,6 +7548,8 @@ syms_of_window (void) DEFSYM (Qfloor, "floor"); DEFSYM (Qceiling, "ceiling"); DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); + DEFSYM (Qmode_line_format, "mode-line-format"); + DEFSYM (Qheader_line_format, "header-line-format"); staticpro (&Vwindow_list); @@ -7603,6 +7799,7 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Sset_window_point); defsubr (&Sset_window_start); defsubr (&Swindow_dedicated_p); + defsubr (&Swindow_lines_pixel_dimensions); defsubr (&Sset_window_dedicated_p); defsubr (&Swindow_display_table); defsubr (&Sset_window_display_table); diff --git a/src/window.h b/src/window.h index acb8a5cabfa..e9040f816df 100644 --- a/src/window.h +++ b/src/window.h @@ -328,8 +328,9 @@ struct window /* True if this window is a minibuffer window. */ bool_bf mini : 1; - /* Meaningful only if contents is a window, true if this - internal window is used in horizontal combination. */ + /* Meaningful for internal windows only: true if this window is a + horizontal combination, false if it is a vertical + combination. */ bool_bf horizontal : 1; /* True means must regenerate mode line of this window. */ @@ -481,15 +482,14 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* True if W is a minibuffer window. */ #define MINI_WINDOW_P(W) ((W)->mini) -/* 1 if W is a non-only minibuffer window. */ -/* The first check is redundant and the second overly complicated. */ -#define MINI_NON_ONLY_WINDOW_P(W) \ - (MINI_WINDOW_P (W) \ - && (EQ (W->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))) +/* True if W is a minibuffer window on a frame that contains at least + one other window. */ +#define MINI_NON_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) && !NILP ((W)->prev)) -/* 1 if W is a minibuffer-only window. */ -#define MINI_ONLY_WINDOW_P(W) \ - (MINI_WINDOW_P (W) && NILP (W->prev)) +/* True if W is a minibuffer window that is alone on its frame. */ +#define MINI_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) && NILP ((W)->prev)) /* General window layout: @@ -518,29 +518,34 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* A handy macro. */ -/* Non-nil if W is leaf (carry the buffer). */ - +/* Non-nil if window W is leaf window (has a buffer). */ #define WINDOW_LEAF_P(W) \ (BUFFERP ((W)->contents)) -/* Non-nil if W is internal. */ +/* Non-nil if window W is internal (is a parent window). */ #define WINDOW_INTERNAL_P(W) \ (WINDOWP ((W)->contents)) -/* True if W is a member of horizontal combination. */ +/* True if window W is a horizontal combination of windows. */ #define WINDOW_HORIZONTAL_COMBINATION_P(W) \ (WINDOW_INTERNAL_P (W) && (W)->horizontal) -/* True if W is a member of vertical combination. */ +/* True if window W is a vertical combination of windows. */ #define WINDOW_VERTICAL_COMBINATION_P(W) \ (WINDOW_INTERNAL_P (W) && !(W)->horizontal) -/* WINDOW's XFRAME. */ +/* Window W's XFRAME. */ #define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) -/* Whether WINDOW is a pseudo window. */ +/* Whether window W is a pseudo window. */ #define WINDOW_PSEUDO_P(W) ((W)->pseudo_window_p) +/* Window W's buffer. */ +#define WINDOW_BUFFER(W) \ + (WINDOW_LEAF_P(W) \ + ? (W)->contents \ + : Qnil) \ + /* Return the canonical column width of the frame of window W. */ #define WINDOW_FRAME_COLUMN_WIDTH(W) \ (FRAME_COLUMN_WIDTH (WINDOW_XFRAME ((W)))) @@ -549,24 +554,24 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define WINDOW_FRAME_LINE_HEIGHT(W) \ (FRAME_LINE_HEIGHT (WINDOW_XFRAME ((W)))) -/* Return the pixel width of window W. - This includes scroll bars and fringes. */ +/* Return the pixel width of window W. This includes dividers, scroll + bars, fringes and margins, if any. */ #define WINDOW_PIXEL_WIDTH(W) (W)->pixel_width -/* Return the pixel height of window W. - This includes header and mode lines, if any. */ +/* Return the pixel height of window W. This includes dividers, scroll + bars, header and mode lines, if any. */ #define WINDOW_PIXEL_HEIGHT(W) (W)->pixel_height -/* Return the width of window W in canonical column units. - This includes scroll bars and fringes. - This value is adjusted such that the sum of the widths of all child +/* Return the width of window W in canonical column units. This + includes dividers, scroll bars, fringes and margins, if any. The + value is adjusted such that the sum of the widths of all child windows equals the width of their parent window. */ #define WINDOW_TOTAL_COLS(W) (W)->total_cols -/* Return the height of window W in canonical line units. - This includes header and mode lines, if any. - This value is adjusted such that the sum of the heights of all child - windows equals the height of their parent window. */ +/* Return the height of window W in canonical line units. This includes + dividers, scroll bars, header and mode lines, if any. The value is + adjusted such that the sum of the heights of all child windows equals + the height of their parent window. */ #define WINDOW_TOTAL_LINES(W) (W)->total_lines /* The smallest acceptable dimensions for a window. Anything smaller @@ -581,31 +586,63 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define MIN_SAFE_WINDOW_PIXEL_HEIGHT(W) \ (WINDOW_FRAME_LINE_HEIGHT (W)) +/* True if window W has no other windows to its left on its frame. */ +#define WINDOW_LEFTMOST_P(W) \ + (WINDOW_LEFT_PIXEL_EDGE (W) == 0) + +/* True if window W has no other windows above it on its frame. */ +#define WINDOW_TOPMOST_P(W) \ + (WINDOW_TOP_PIXEL_EDGE (W) == 0) + +/* True if window W has no other windows to its right on its frame. */ +#define WINDOW_RIGHTMOST_P(W) \ + (WINDOW_RIGHT_PIXEL_EDGE (W) \ + == (WINDOW_RIGHT_PIXEL_EDGE \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + +/* True if window W has no other windows below it on its frame (the + minibuffer window is not counted in this respect unless W itself is a + minibuffer window). */ +#define WINDOW_BOTTOMMOST_P(W) \ + (WINDOW_BOTTOM_PIXEL_EDGE (W) \ + == (WINDOW_BOTTOM_PIXEL_EDGE \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + +/* True if window W takes up the full width of its frame. */ +#define WINDOW_FULL_WIDTH_P(W) \ + (WINDOW_PIXEL_WIDTH (W) \ + == (WINDOW_PIXEL_WIDTH \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + /* Width of right divider of window W. */ #define WINDOW_RIGHT_DIVIDER_WIDTH(W) \ - ((WINDOW_RIGHTMOST_P (W) || MINI_WINDOW_P (W)) \ - ? 0 \ - : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W))) + (WINDOW_RIGHTMOST_P (W) \ + ? 0 : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W))) + +/* Width of bottom divider of window W. */ +#define WINDOW_BOTTOM_DIVIDER_WIDTH(W) \ + (((WINDOW_BOTTOMMOST_P (W) \ + && NILP ((XWINDOW (FRAME_ROOT_WINDOW \ + (WINDOW_XFRAME (W))))->next)) \ + || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))) \ + || (W)->pseudo_window_p) \ + ? 0 : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W))) /* Return the canonical frame column at which window W starts. This includes a left-hand scroll bar, if any. */ - #define WINDOW_LEFT_EDGE_COL(W) (W)->left_col /* Return the canonical frame column before which window W ends. This includes a right-hand scroll bar, if any. */ - #define WINDOW_RIGHT_EDGE_COL(W) \ (WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W)) /* Return the canonical frame line at which window W starts. This includes a header line, if any. */ - #define WINDOW_TOP_EDGE_LINE(W) (W)->top_line /* Return the canonical frame line before which window W ends. This includes a mode line, if any. */ - #define WINDOW_BOTTOM_EDGE_LINE(W) \ (WINDOW_TOP_EDGE_LINE (W) + WINDOW_TOTAL_LINES (W)) @@ -629,20 +666,17 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* Return the frame x-position at which window W starts. This includes a left-hand scroll bar, if any. */ - #define WINDOW_LEFT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_LEFT_PIXEL_EDGE (W)) /* Return the frame x- position before which window W ends. This includes a right-hand scroll bar, if any. */ - #define WINDOW_RIGHT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_RIGHT_PIXEL_EDGE (W)) /* True if W is a menu bar window. */ - #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) #define WINDOW_MENU_BAR_P(W) \ (WINDOWP (WINDOW_XFRAME (W)->menu_bar_window) \ @@ -661,72 +695,24 @@ wset_next_buffers (struct window *w, Lisp_Object val) #define WINDOW_TOOL_BAR_P(W) false #endif -/* Return the frame y-position at which window W starts. - This includes a header line, if any. - - PXW: With a menu or tool bar this is not symmetric to the _X values - since it _does_ include the internal border width. */ +/* Return the frame y-position at which window W starts. */ #define WINDOW_TOP_EDGE_Y(W) \ (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ + WINDOW_TOP_PIXEL_EDGE (W)) -/* Return the frame y-position before which window W ends. - This includes a mode line, if any. */ +/* Return the frame y-position before which window W ends. */ #define WINDOW_BOTTOM_EDGE_Y(W) \ (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ + WINDOW_BOTTOM_PIXEL_EDGE (W)) -/* True if window W takes up the full width of its frame. */ -#define WINDOW_FULL_WIDTH_P(W) \ - (WINDOW_PIXEL_WIDTH (W) \ - == (WINDOW_PIXEL_WIDTH \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* True if window W's has no other windows to its left in its frame. */ - -#define WINDOW_LEFTMOST_P(W) \ - (WINDOW_LEFT_PIXEL_EDGE (W) == 0) - -/* True if window W's has no other windows above in its frame. */ -#define WINDOW_TOPMOST_P(W) \ - (WINDOW_TOP_PIXEL_EDGE (W) == 0) - -/* True if window W's has no other windows to its right in its frame. */ -#define WINDOW_RIGHTMOST_P(W) \ - (WINDOW_RIGHT_PIXEL_EDGE (W) \ - == (WINDOW_RIGHT_PIXEL_EDGE \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* True if window W's has no other windows below it in its frame - (the minibuffer window is not counted in this respect). */ -#define WINDOW_BOTTOMMOST_P(W) \ - (WINDOW_BOTTOM_PIXEL_EDGE (W) \ - == (WINDOW_BOTTOM_PIXEL_EDGE \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* Return the frame column at which the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ -#define WINDOW_BOX_LEFT_EDGE_COL(W) \ - (WINDOW_LEFT_EDGE_COL (W) \ - + WINDOW_LEFT_SCROLL_BAR_COLS (W)) - -/* Return the pixel value where the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ +/* Return the pixel value where the text (or left fringe) in window W + starts. */ #define WINDOW_BOX_LEFT_PIXEL_EDGE(W) \ (WINDOW_LEFT_PIXEL_EDGE (W) \ + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (W)) -/* Return the window column before which the text in window W ends. - This is different from WINDOW_RIGHT_EDGE_COL because it does not - include a scroll bar or window-separating line on the right edge. */ -#define WINDOW_BOX_RIGHT_EDGE_COL(W) \ - (WINDOW_RIGHT_EDGE_COL (W) \ - - WINDOW_RIGHT_SCROLL_BAR_COLS (W)) - /* Return the pixel value before which the text in window W ends. This is different from the `RIGHT_EDGE' because it does not include a right-hand scroll bar or window-separating line on the right @@ -736,16 +722,16 @@ wset_next_buffers (struct window *w, Lisp_Object val) - WINDOW_RIGHT_DIVIDER_WIDTH (W) \ - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (W)) -/* Return the frame position at which the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ +/* Return the frame x-position at which the text (or left fringe) in + window W starts. This does not include a left-hand scroll bar if + any. */ #define WINDOW_BOX_LEFT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_BOX_LEFT_PIXEL_EDGE (W)) -/* Return the window column before which the text in window W ends. - This is different from WINDOW_RIGHT_EDGE_COL because it does not - include a scroll bar or window-separating line on the right edge. */ +/* Return the frame x-position before which the text in window W ends. + This does not include a scroll bar, divider or window-separating line + on the right edge. */ #define WINDOW_BOX_RIGHT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_BOX_RIGHT_PIXEL_EDGE (W)) @@ -899,16 +885,6 @@ wset_next_buffers (struct window *w, Lisp_Object val) ? WINDOW_BOX_RIGHT_EDGE_X (W) \ : WINDOW_LEFT_EDGE_X (W)) -/* Width of bottom divider of window W. */ -#define WINDOW_BOTTOM_DIVIDER_WIDTH(W) \ - (((WINDOW_BOTTOMMOST_P (W) \ - && NILP ((XWINDOW (FRAME_ROOT_WINDOW \ - (WINDOW_XFRAME (W))))->next)) \ - || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))) \ - || (W)->pseudo_window_p) \ - ? 0 \ - : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W))) - /* Height that a scroll bar in window W should have, if there is one. Measured in pixels. If scroll bars are turned off, this is still nonzero. */ @@ -942,22 +918,22 @@ wset_next_buffers (struct window *w, Lisp_Object val) /* Height in pixels of the mode line. May be zero if W doesn't have a mode line. */ #define WINDOW_MODE_LINE_HEIGHT(W) \ - (WINDOW_WANTS_MODELINE_P ((W)) \ + (window_wants_mode_line ((W)) \ ? CURRENT_MODE_LINE_HEIGHT (W) \ : 0) #define WINDOW_MODE_LINE_LINES(W) \ - WINDOW_WANTS_MODELINE_P (W) + window_wants_mode_line (W) /* Height in pixels of the header line. Zero if W doesn't have a header line. */ #define WINDOW_HEADER_LINE_HEIGHT(W) \ - (WINDOW_WANTS_HEADER_LINE_P (W) \ + (window_wants_header_line (W) \ ? CURRENT_HEADER_LINE_HEIGHT (W) \ : 0) #define WINDOW_HEADER_LINE_LINES(W) \ - WINDOW_WANTS_HEADER_LINE_P (W) + window_wants_header_line (W) /* Pixel height of window W without mode line, bottom scroll bar and bottom divider. */ @@ -1114,10 +1090,13 @@ struct glyph *get_phys_cursor_glyph (struct window *w); extern Lisp_Object Vwindow_list; extern Lisp_Object window_list (void); +extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter); extern struct window *decode_live_window (Lisp_Object); extern struct window *decode_any_window (Lisp_Object); extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool); extern void mark_window_cursors_off (struct window *); +extern bool window_wants_mode_line (struct window *); +extern bool window_wants_header_line (struct window *); extern int window_internal_height (struct window *); extern int window_body_width (struct window *w, bool); enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; @@ -1133,7 +1112,6 @@ extern void init_window_once (void); extern void init_window (void); extern void syms_of_window (void); extern void keys_of_window (void); - /* Move cursor to row/column position VPOS/HPOS, pixel coordinates Y/X. HPOS/VPOS are window-relative row and column numbers and X/Y are window-relative pixel positions. This is always done during diff --git a/src/xdisp.c b/src/xdisp.c index 34ee877e6be..784848913c0 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -921,7 +921,7 @@ window_text_bottom_y (struct window *w) height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) height -= CURRENT_MODE_LINE_HEIGHT (w); height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); @@ -978,7 +978,7 @@ window_box_height (struct window *w) the appropriate glyph row has its `mode_line_p' flag set, and if it doesn't, uses estimate_mode_line_height instead. */ - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) { struct glyph_row *ml_row = (w->current_matrix && w->current_matrix->rows @@ -990,7 +990,7 @@ window_box_height (struct window *w) height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w)); } - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) { struct glyph_row *hl_row = (w->current_matrix && w->current_matrix->rows @@ -1102,7 +1102,7 @@ window_box (struct window *w, enum glyph_row_area area, int *box_x, if (box_y) { *box_y = WINDOW_TOP_EDGE_Y (w); - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) *box_y += CURRENT_HEADER_LINE_HEIGHT (w); } } @@ -1322,15 +1322,29 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, return visible_p; /* Compute exact mode line heights. */ - if (WINDOW_WANTS_MODELINE_P (w)) - w->mode_line_height - = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), - BVAR (current_buffer, mode_line_format)); + if (window_wants_mode_line (w)) + { + Lisp_Object window_mode_line_format + = window_parameter (w, Qmode_line_format); + + w->mode_line_height + = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), + NILP (window_mode_line_format) + ? BVAR (current_buffer, mode_line_format) + : window_mode_line_format); + } - if (WINDOW_WANTS_HEADER_LINE_P (w)) - w->header_line_height - = display_mode_line (w, HEADER_LINE_FACE_ID, - BVAR (current_buffer, header_line_format)); + if (window_wants_header_line (w)) + { + Lisp_Object window_header_line_format + = window_parameter (w, Qheader_line_format); + + w->header_line_height + = display_mode_line (w, HEADER_LINE_FACE_ID, + NILP (window_header_line_format) + ? BVAR (current_buffer, header_line_format) + : window_header_line_format); + } start_display (&it, w, top); move_it_to (&it, charpos, -1, it.last_visible_y - 1, -1, @@ -2842,13 +2856,12 @@ init_iterator (struct it *it, struct window *w, /* Get dimensions of truncation and continuation glyphs. These are displayed as fringe bitmaps under X, but we need them for such - frames when the fringes are turned off. But leave the dimensions - zero for tooltip frames, as these glyphs look ugly there and also - sabotage calculations of tooltip dimensions in x-show-tip. */ + frames when the fringes are turned off. The no_special_glyphs slot + of the iterator's frame, when set, suppresses their display - by + default for tooltip frames and when set via the 'no-special-glyphs' + frame parameter. */ #ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) - && FRAMEP (tip_frame) - && it->f == XFRAME (tip_frame))) + if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs)) #endif { if (it->line_wrap == TRUNCATE) @@ -2920,7 +2933,7 @@ init_iterator (struct it *it, struct window *w, it->last_visible_x -= it->continuation_pixel_width; } - it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); + it->header_line_p = window_wants_header_line (w); it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll; } @@ -3019,7 +3032,7 @@ void start_display (struct it *it, struct window *w, struct text_pos pos) { struct glyph_row *row; - bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w); + bool first_vpos = window_wants_header_line (w); row = w->desired_matrix->rows + first_vpos; init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); @@ -15799,7 +15812,7 @@ compute_window_start_on_continuation_line (struct window *w) /* Find the start of the continued line. This should be fast because find_newline is fast (newline cache). */ - row = w->desired_matrix->rows + WINDOW_WANTS_HEADER_LINE_P (w); + row = w->desired_matrix->rows + window_wants_header_line (w); init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos), row, DEFAULT_FACE_ID); reseat_at_previous_visible_line_start (&it); @@ -15949,7 +15962,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); top_scroll_margin = this_scroll_margin; - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w); /* Start with the row the cursor was displayed during the last @@ -16732,7 +16745,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) margin, even though this part handles windows that didn't scroll at all. */ int pixel_margin = margin * frame_line_height; - bool header_line = WINDOW_WANTS_HEADER_LINE_P (w); + bool header_line = window_wants_header_line (w); /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop below, which finds the row to move point to, advances by @@ -17299,15 +17312,15 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) || (w->column_number_displayed != -1 && (w->column_number_displayed != current_column ()))) /* This means that the window has a mode line. */ - && (WINDOW_WANTS_MODELINE_P (w) - || WINDOW_WANTS_HEADER_LINE_P (w))) + && (window_wants_mode_line (w) + || window_wants_header_line (w))) { display_mode_lines (w); /* If mode line height has changed, arrange for a thorough immediate redisplay using the correct mode line height. */ - if (WINDOW_WANTS_MODELINE_P (w) + if (window_wants_mode_line (w) && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w)) { f->fonts_changed = true; @@ -17318,7 +17331,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* If header line height has changed, arrange for a thorough immediate redisplay using the correct header line height. */ - if (WINDOW_WANTS_HEADER_LINE_P (w) + if (window_wants_header_line (w) && CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w)) { f->fonts_changed = true; @@ -17583,7 +17596,7 @@ try_window_reusing_current_matrix (struct window *w) return false; /* If top-line visibility has changed, give up. */ - if (WINDOW_WANTS_HEADER_LINE_P (w) + if (window_wants_header_line (w) != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p) return false; @@ -18818,7 +18831,7 @@ try_window_id (struct window *w) = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix); int from = WINDOW_TOP_EDGE_LINE (w) + from_vpos; int end = (WINDOW_TOP_EDGE_LINE (w) - + WINDOW_WANTS_HEADER_LINE_P (w) + + window_wants_header_line (w) + window_internal_height (w)); #if defined (HAVE_GPM) || defined (MSDOS) @@ -18996,7 +19009,7 @@ try_window_id (struct window *w) { /* Displayed to end of window, but no line containing text was displayed. Lines were deleted at the end of the window. */ - bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w); + bool first_vpos = window_wants_header_line (w); int vpos = w->window_end_vpos; struct glyph_row *current_row = current_matrix->rows + vpos; struct glyph_row *desired_row = desired_matrix->rows + vpos; @@ -20696,7 +20709,7 @@ display_line (struct it *it, int cursor_vpos) ptrdiff_t min_pos = ZV + 1, max_pos = 0; ptrdiff_t min_bpos UNINIT, max_bpos UNINIT; bool pending_handle_line_prefix = false; - int header_line = WINDOW_WANTS_HEADER_LINE_P (it->w); + int header_line = window_wants_header_line (it->w); bool hscroll_this_line = (cursor_vpos >= 0 && it->vpos == cursor_vpos - header_line && hscrolling_current_line_p (it->w)); @@ -22649,20 +22662,30 @@ display_mode_lines (struct window *w) line_number_displayed = false; w->column_number_displayed = -1; - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) { + Lisp_Object window_mode_line_format + = window_parameter (w, Qmode_line_format); + struct window *sel_w = XWINDOW (old_selected_window); /* Select mode line face based on the real selected window. */ display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w), - BVAR (current_buffer, mode_line_format)); + NILP (window_mode_line_format) + ? BVAR (current_buffer, mode_line_format) + : window_mode_line_format); ++n; } - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) { + Lisp_Object window_header_line_format + = window_parameter (w, Qheader_line_format); + display_mode_line (w, HEADER_LINE_FACE_ID, - BVAR (current_buffer, header_line_format)); + NILP (window_header_line_format) + ? BVAR (current_buffer, header_line_format) + : window_header_line_format); ++n; } @@ -30442,13 +30465,67 @@ note_mouse_highlight (struct frame *f, int x, int y) && part != ON_HEADER_LINE)) clear_mouse_face (hlinfo); + /* Reset help_echo_string. It will get recomputed below. */ + help_echo_string = Qnil; + +#ifdef HAVE_WINDOW_SYSTEM + /* If the cursor is on the internal border of FRAME and FRAME's + internal border is draggable, provide some visual feedback. */ + if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0 + && !NILP (get_frame_param (f, Qdrag_internal_border))) + { + enum internal_border_part part = frame_internal_border_part (f, x, y); + + switch (part) + { + case INTERNAL_BORDER_NONE: + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + /* Reset cursor. */ + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + break; + case INTERNAL_BORDER_LEFT_EDGE: + cursor = FRAME_X_OUTPUT (f)->left_edge_cursor; + break; + case INTERNAL_BORDER_TOP_LEFT_CORNER: + cursor = FRAME_X_OUTPUT (f)->top_left_corner_cursor; + break; + case INTERNAL_BORDER_TOP_EDGE: + cursor = FRAME_X_OUTPUT (f)->top_edge_cursor; + break; + case INTERNAL_BORDER_TOP_RIGHT_CORNER: + cursor = FRAME_X_OUTPUT (f)->top_right_corner_cursor; + break; + case INTERNAL_BORDER_RIGHT_EDGE: + cursor = FRAME_X_OUTPUT (f)->right_edge_cursor; + break; + case INTERNAL_BORDER_BOTTOM_RIGHT_CORNER: + cursor = FRAME_X_OUTPUT (f)->bottom_right_corner_cursor; + break; + case INTERNAL_BORDER_BOTTOM_EDGE: + cursor = FRAME_X_OUTPUT (f)->bottom_edge_cursor; + break; + case INTERNAL_BORDER_BOTTOM_LEFT_CORNER: + cursor = FRAME_X_OUTPUT (f)->bottom_left_corner_cursor; + break; + default: + /* This should not happen. */ + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + } + + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + { + /* Do we really want a help echo here? */ + help_echo_string = build_string ("drag-mouse-1: resize frame"); + goto set_cursor; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ + /* Not on a window -> return. */ if (!WINDOWP (window)) return; - /* Reset help_echo_string. It will get recomputed below. */ - help_echo_string = Qnil; - /* Convert to window-relative pixel coordinates. */ w = XWINDOW (window); frame_to_window_pixel_xy (w, &x, &y); @@ -30486,11 +30563,13 @@ note_mouse_highlight (struct frame *f, int x, int y) { cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else if (part == ON_RIGHT_DIVIDER) { cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else if (part == ON_BOTTOM_DIVIDER) if (! WINDOW_BOTTOMMOST_P (w) @@ -30499,6 +30578,7 @@ note_mouse_highlight (struct frame *f, int x, int y) { cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -31193,8 +31273,15 @@ x_draw_right_divider (struct window *w) int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w); int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_TOP_EDGE_Y (w); - /* The bottom divider prevails. */ - int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); + int y1 = WINDOW_BOTTOM_EDGE_Y (w); + + /* If W is horizontally combined and has a right sibling, don't + draw over any bottom divider. */ + if (WINDOW_BOTTOM_DIVIDER_WIDTH (w) + && !NILP (w->parent) + && WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (w->parent)) + && !NILP (w->next)) + y1 -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); } @@ -31213,8 +31300,22 @@ x_draw_bottom_divider (struct window *w) int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); int y1 = WINDOW_BOTTOM_EDGE_Y (w); + struct window *p = !NILP (w->parent) ? XWINDOW (w->parent) : false; - FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); + /* If W is vertically combined and has a sibling below, don't draw + over any right divider. */ + if (WINDOW_RIGHT_DIVIDER_WIDTH (w) + && p + && ((WINDOW_VERTICAL_COMBINATION_P (p) + && !NILP (w->next)) + || (WINDOW_HORIZONTAL_COMBINATION_P (p) + && NILP (w->next) + && !NILP (p->parent) + && WINDOW_VERTICAL_COMBINATION_P (XWINDOW (p->parent)) + && !NILP (XWINDOW (p->parent)->next)))) + x1 -= WINDOW_RIGHT_DIVIDER_WIDTH (w); + + FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); } } @@ -31329,7 +31430,7 @@ expose_window (struct window *w, XRectangle *fr) } /* Display the mode line if there is one. */ - if (WINDOW_WANTS_MODELINE_P (w) + if (window_wants_mode_line (w) && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), row->enabled_p) && row->y < r_bottom) diff --git a/src/xfns.c b/src/xfns.c index 7be2253cc3b..d8bf9747191 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1120,6 +1120,14 @@ enum mouse_cursor { mouse_cursor_hand, mouse_cursor_horizontal_drag, mouse_cursor_vertical_drag, + mouse_cursor_left_edge, + mouse_cursor_top_left_corner, + mouse_cursor_top_edge, + mouse_cursor_top_right_corner, + mouse_cursor_right_edge, + mouse_cursor_bottom_right_corner, + mouse_cursor_bottom_edge, + mouse_cursor_bottom_left_corner, mouse_cursor_max }; @@ -1139,13 +1147,21 @@ struct mouse_cursor_types { /* This array must stay in sync with enum mouse_cursor above! */ static const struct mouse_cursor_types mouse_cursor_types[] = { - { "text", &Vx_pointer_shape, XC_xterm }, - { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, - { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, - { "modeline", &Vx_mode_pointer_shape, XC_xterm }, - { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, - { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, - { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, + { "text", &Vx_pointer_shape, XC_xterm }, + { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, + { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, + { "modeline", &Vx_mode_pointer_shape, XC_xterm }, + { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, + { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, + { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, + { NULL, &Vx_window_left_edge_shape, XC_left_side }, + { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner }, + { NULL, &Vx_window_top_edge_shape, XC_top_side }, + { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner }, + { NULL, &Vx_window_right_edge_shape, XC_right_side }, + { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner }, + { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side }, + { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner }, }; struct mouse_cursor_data { @@ -1296,6 +1312,14 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) INSTALL_CURSOR (hand_cursor, hand); INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag); INSTALL_CURSOR (vertical_drag_cursor, vertical_drag); + INSTALL_CURSOR (left_edge_cursor, left_edge); + INSTALL_CURSOR (top_left_corner_cursor, top_left_corner); + INSTALL_CURSOR (top_edge_cursor, top_edge); + INSTALL_CURSOR (top_right_corner_cursor, top_right_corner); + INSTALL_CURSOR (right_edge_cursor, right_edge); + INSTALL_CURSOR (bottom_right_corner_cursor, bottom_right_corner); + INSTALL_CURSOR (bottom_edge_cursor, bottom_edge); + INSTALL_CURSOR (bottom_left_corner_cursor, bottom_left_corner); #undef INSTALL_CURSOR @@ -3814,6 +3838,8 @@ This function is an internal primitive--use `make-frame' instead. */) "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, "scrollBarForeground", @@ -5286,7 +5312,7 @@ Frames are listed from topmost (first) to bottommost (last). */) static void x_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) { -#ifdef USE_GTK +#if defined (USE_GTK) && GTK_CHECK_VERSION (2, 18, 0) block_input (); xg_frame_restack (f1, f2, above_flag); unblock_input (); @@ -6196,6 +6222,8 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); /* Init faces before x_default_parameter is called for the scroll-bar-width parameter because otherwise we end up in @@ -7486,6 +7514,7 @@ frame_parm_handler x_frame_parm_handlers[] = x_set_no_accept_focus, x_set_z_group, x_set_override_redirect, + x_set_no_special_glyphs, }; void @@ -7564,6 +7593,62 @@ This variable takes effect when you create a new frame or when you set the mouse color. */); Vx_window_vertical_drag_shape = Qnil; + DEFVAR_LISP ("x-window-left-edge-cursor", + Vx_window_left_edge_shape, + doc: /* Pointer shape indicating a left x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_left_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-top-left-corner-cursor", + Vx_window_top_left_corner_shape, + doc: /* Pointer shape indicating a top left x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_left_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-top-edge-cursor", + Vx_window_top_edge_shape, + doc: /* Pointer shape indicating a top x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-top-right-corner-cursor", + Vx_window_top_right_corner_shape, + doc: /* Pointer shape indicating a top right x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_right_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-right-edge-cursor", + Vx_window_right_edge_shape, + doc: /* Pointer shape indicating a right x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_right_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-right-corner-cursor", + Vx_window_bottom_right_corner_shape, + doc: /* Pointer shape indicating a bottom right x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_right_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-edge-cursor", + Vx_window_bottom_edge_shape, + doc: /* Pointer shape indicating a bottom x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-left-corner-cursor", + Vx_window_bottom_left_corner_shape, + doc: /* Pointer shape indicating a bottom left x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_left_corner_shape = Qnil; + DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, doc: /* A string indicating the foreground color of the cursor box. */); Vx_cursor_fore_pixel = Qnil; diff --git a/src/xterm.c b/src/xterm.c index c8836b7ca78..a214cd81031 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11757,6 +11757,22 @@ x_free_frame_resources (struct frame *f) XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor); if (f->output_data.x->vertical_drag_cursor != 0) XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor); + if (f->output_data.x->left_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->left_edge_cursor); + if (f->output_data.x->top_left_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_left_corner_cursor); + if (f->output_data.x->top_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_edge_cursor); + if (f->output_data.x->top_right_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_right_corner_cursor); + if (f->output_data.x->right_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->right_edge_cursor); + if (f->output_data.x->bottom_right_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_right_corner_cursor); + if (f->output_data.x->bottom_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_edge_cursor); + if (f->output_data.x->bottom_left_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor); XFlush (FRAME_X_DISPLAY (f)); } diff --git a/src/xterm.h b/src/xterm.h index a75257006fd..803feda99f3 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -637,6 +637,14 @@ struct x_output Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; Cursor current_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* Window whose cursor is hourglass_cursor. This window is temporarily mapped to display an hourglass cursor. */ -- cgit v1.2.1 From b2f81598670d19684e65ce4587a0ebaf92443b27 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 25 Jun 2017 12:46:50 -0700 Subject: Port recent frame changes to GCC 7 * src/frame.c (keep_ratio): New arg P. Caller changed. Since it is non-null, it avoids a GCC 7 warning that FRAME_PARENT_FRAME might return null. This also avoids a run-time test. --- src/frame.c | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/frame.c b/src/frame.c index b2377aefb8d..1e5e4bbdb48 100644 --- a/src/frame.c +++ b/src/frame.c @@ -378,7 +378,7 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, * keep_ratio: * * Preserve ratios of frame F which usually happens after its parent - * frame got resized. OLD_WIDTH, OLD_HEIGHT specifies the old native + * frame P got resized. OLD_WIDTH, OLD_HEIGHT specifies the old native * size of F's parent, NEW_WIDTH and NEW_HEIGHT its new size. * * Adjust F's width if F's 'keep_ratio' parameter is non-nil and, if @@ -403,8 +403,8 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, * different resolutions. */ static void -keep_ratio (struct frame *f, int old_width, int old_height, - int new_width, int new_height) +keep_ratio (struct frame *f, struct frame *p, int old_width, int old_height, + int new_width, int new_height) { Lisp_Object keep_ratio = get_frame_param (f, Qkeep_ratio); @@ -423,20 +423,17 @@ keep_ratio (struct frame *f, int old_width, int old_height, { pos_x = (int)(f->left_pos * width_factor + 0.5); - if (CONSP (keep_ratio) && - (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qheight_only))) + if (CONSP (keep_ratio) + && (NILP (Fcar (keep_ratio)) + || EQ (Fcar (keep_ratio), Qheight_only)) + && p->pixel_width - f->pixel_width < pos_x) { - struct frame *p = FRAME_PARENT_FRAME (f); + int p_f_width = p->pixel_width - f->pixel_width; - if (pos_x + f->pixel_width > p->pixel_width) - { - int p_f_width = p->pixel_width - f->pixel_width; - - if (p_f_width <= 0) - pos_x = 0; - else - pos_x = (int)(p_f_width * width_factor * 0.5 + 0.5); - } + if (p_f_width <= 0) + pos_x = 0; + else + pos_x = (int)(p_f_width * width_factor * 0.5 + 0.5); } f->left_pos = pos_x; @@ -448,25 +445,22 @@ keep_ratio (struct frame *f, int old_width, int old_height, { pos_y = (int)(f->top_pos * height_factor + 0.5); - if (CONSP (keep_ratio) && - (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qwidth_only))) + if (CONSP (keep_ratio) + && (NILP (Fcar (keep_ratio)) + || EQ (Fcar (keep_ratio), Qwidth_only)) + && p->pixel_height - f->pixel_height < pos_y) /* When positional adjustment was requested and the width of F should remain unaltered, try to constrain F to its parent. This means that when the parent frame is enlarged later the child's original position won't get restored. */ { - struct frame *p = FRAME_PARENT_FRAME (f); + int p_f_height = p->pixel_height - f->pixel_height; - if (pos_y + f->pixel_height > p->pixel_height) - { - int p_f_height = p->pixel_height - f->pixel_height; - - if (p_f_height <= 0) - pos_y = 0; - else - pos_y = (int)(p_f_height * height_factor * 0.5 + 0.5); - } + if (p_f_height <= 0) + pos_y = 0; + else + pos_y = (int)(p_f_height * height_factor * 0.5 + 0.5); } f->top_pos = pos_y; @@ -777,8 +771,8 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, FOR_EACH_FRAME (frames, frame1) if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f) - keep_ratio (XFRAME (frame1), old_pixel_width, old_pixel_height, - new_pixel_width, new_pixel_height); + keep_ratio (XFRAME (frame1), f, old_pixel_width, old_pixel_height, + new_pixel_width, new_pixel_height); } #endif } -- cgit v1.2.1 From c05e3aafc86869ba826809effd8ef7e9e5650f83 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 25 Jun 2017 12:49:01 -0700 Subject: Parenthesize frame.h macro definitions * src/frame.h (FRAME_TOOL_BAR_POSITION) (FRAME_VERTICAL_SCROLL_BAR_TYPE, FRAME_HAS_VERTICAL_SCROLL_BARS) (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT) (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT) (FRAME_OVERRIDE_REDIRECT, FRAME_UNDECORATED, FRAME_PARENT_FRAME) (FRAME_SKIP_TASKBAR, FRAME_NO_FOCUS_ON_MAP) (FRAME_NO_ACCEPT_FOCUS, FRAME_NO_SPECIAL_GLYPHS, FRAME_Z_GROUP) (FRAME_Z_GROUP_NONE, FRAME_Z_GROUP_ABOVE, FRAME_Z_GROUP_BELOW) (FRAME_HAS_HORIZONTAL_SCROLL_BARS): Parenthesize macro definiens to allow arbitrary expression arguments. --- src/frame.h | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/frame.h b/src/frame.h index 2feb09b2e67..154dc9a3bb4 100644 --- a/src/frame.h +++ b/src/frame.h @@ -841,7 +841,7 @@ default_pixels_per_inch_y (void) #ifdef USE_GTK #define FRAME_TOOL_BAR_POSITION(f) (f)->tool_bar_position #else -#define FRAME_TOOL_BAR_POSITION(f) ((void) f, Qtop) +#define FRAME_TOOL_BAR_POSITION(f) ((void) (f), Qtop) #endif /* Number of lines of frame F used for the tool-bar. */ @@ -925,16 +925,17 @@ default_pixels_per_inch_y (void) ((f)->vertical_scroll_bar_type == vertical_scroll_bar_right) #else /* not HAVE_WINDOW_SYSTEM */ /* If there is no window system, there are no scroll bars. */ -#define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((void) f, vertical_scroll_bar_none) -#define FRAME_HAS_VERTICAL_SCROLL_BARS(f) ((void) f, 0) -#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) f, 0) -#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0) +#define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) \ + ((void) (f), vertical_scroll_bar_none) +#define FRAME_HAS_VERTICAL_SCROLL_BARS(f) ((void) (f), 0) +#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) (f), 0) +#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) (f), 0) #endif /* HAVE_WINDOW_SYSTEM */ #if defined (HAVE_WINDOW_SYSTEM) #define FRAME_UNDECORATED(f) ((f)->undecorated) #ifdef HAVE_NTGUI -#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) +#define FRAME_OVERRIDE_REDIRECT(f) ((void) (f), 0) #else #define FRAME_OVERRIDE_REDIRECT(f) ((f)->override_redirect) #endif @@ -953,17 +954,17 @@ default_pixels_per_inch_y (void) ((f)->z_group == z_group_above_suspended) #define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below) #else /* not HAVE_WINDOW_SYSTEM */ -#define FRAME_UNDECORATED(f) ((void) f, 0) -#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) -#define FRAME_PARENT_FRAME(f) ((void) f, NULL) -#define FRAME_SKIP_TASKBAR(f) ((void) f, 0) -#define FRAME_NO_FOCUS_ON_MAP(f) ((void) f, 0) -#define FRAME_NO_ACCEPT_FOCUS(f) ((void) f, 0) -#define FRAME_NO_SPECIAL_GLYPHS(f) ((void) f, 0) -#define FRAME_Z_GROUP(f) ((void) f, z_group_none) -#define FRAME_Z_GROUP_NONE(f) ((void) f, true) -#define FRAME_Z_GROUP_ABOVE(f) ((void) f, false) -#define FRAME_Z_GROUP_BELOW(f) ((void) f, false) +#define FRAME_UNDECORATED(f) ((void) (f), 0) +#define FRAME_OVERRIDE_REDIRECT(f) ((void) (f), 0) +#define FRAME_PARENT_FRAME(f) ((void) (f), NULL) +#define FRAME_SKIP_TASKBAR(f) ((void) (f), 0) +#define FRAME_NO_FOCUS_ON_MAP(f) ((void) (f), 0) +#define FRAME_NO_ACCEPT_FOCUS(f) ((void) (f), 0) +#define FRAME_NO_SPECIAL_GLYPHS(f) ((void) (f), 0) +#define FRAME_Z_GROUP(f) ((void) (f), z_group_none) +#define FRAME_Z_GROUP_NONE(f) ((void) (f), true) +#define FRAME_Z_GROUP_ABOVE(f) ((void) (f), false) +#define FRAME_Z_GROUP_BELOW(f) ((void) (f), false) #endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ @@ -971,7 +972,7 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) \ ((f)->horizontal_scroll_bars) #else -#define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) ((void) f, 0) +#define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) ((void) (f), 0) #endif /* Width that a scroll bar in frame F should have, if there is one. -- cgit v1.2.1 From b2bff45d0f27b3d8c3dfbf6df51dd7adbcb9d9fc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 25 Jun 2017 12:52:37 -0700 Subject: Omit null-pointer test in intervals.h FRAME * src/intervals.h (ROOT_INTERVAL_P, ONLY_INTERVAL_P) (INTERVAL_LAST_POS): Omit unnecessary parens. (LENGTH): Omit test for null pointer. The argument is never null. The unnecessary test causes GCC 7.1.0 to assume that the argument might be null, and therefore to issue false alarms when the argument is dereferenced in other expressions. --- src/intervals.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/intervals.h b/src/intervals.h index db91b3f21a0..a0da6f37801 100644 --- a/src/intervals.h +++ b/src/intervals.h @@ -85,10 +85,10 @@ struct interval #define LEAF_INTERVAL_P(i) ((i)->left == NULL && (i)->right == NULL) /* True if this interval has no parent and is therefore the root. */ -#define ROOT_INTERVAL_P(i) (NULL_PARENT (i)) +#define ROOT_INTERVAL_P(i) NULL_PARENT (i) /* True if this interval is the only interval in the interval tree. */ -#define ONLY_INTERVAL_P(i) (ROOT_INTERVAL_P ((i)) && LEAF_INTERVAL_P ((i))) +#define ONLY_INTERVAL_P(i) (ROOT_INTERVAL_P (i) && LEAF_INTERVAL_P (i)) /* True if this interval has both left and right children. */ #define BOTH_KIDS_P(i) ((i)->left != NULL && (i)->right != NULL) @@ -98,13 +98,13 @@ struct interval #define TOTAL_LENGTH(i) ((i) == NULL ? 0 : (i)->total_length) /* The size of text represented by this interval alone. */ -#define LENGTH(i) ((i) == NULL ? 0 : (TOTAL_LENGTH ((i)) \ - - TOTAL_LENGTH ((i)->right) \ - - TOTAL_LENGTH ((i)->left))) +#define LENGTH(i) ((i)->total_length \ + - TOTAL_LENGTH ((i)->right) \ + - TOTAL_LENGTH ((i)->left)) /* The position of the character just past the end of I. Note that the position cache i->position must be valid for this to work. */ -#define INTERVAL_LAST_POS(i) ((i)->position + LENGTH ((i))) +#define INTERVAL_LAST_POS(i) ((i)->position + LENGTH (i)) /* The total size of the left subtree of this interval. */ #define LEFT_TOTAL_LENGTH(i) ((i)->left ? (i)->left->total_length : 0) -- cgit v1.2.1 From 53777093c1d84fd9cbea1cd47df02ac6d2d6049b Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Mon, 26 Jun 2017 11:24:25 +0200 Subject: ; * src/emacs-module.c (module_make_string): Add another FIXME --- src/emacs-module.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/emacs-module.c b/src/emacs-module.c index 2693a4529d6..9e072029cc1 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -575,6 +575,8 @@ module_make_string (emacs_env *env, const char *str, ptrdiff_t length) MODULE_FUNCTION_BEGIN (module_nil); if (! (0 <= length && length <= STRING_BYTES_BOUND)) xsignal0 (Qoverflow_error); + /* FIXME: AUTO_STRING_WITH_LEN requires STR to be null-terminated, + but we shouldn’t require that. */ AUTO_STRING_WITH_LEN (lstr, str, length); return lisp_to_value (env, code_convert_string_norecord (lstr, Qutf_8, false)); -- cgit v1.2.1 From 4a5653cd2859308ada4bbf5ffc9fb9b283eef31a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 27 Jun 2017 11:45:22 -0400 Subject: Avoid segfaults when some display vector is an empty string * src/xdisp.c (next_element_from_display_vector): Don't try accessing the dpvec[] array if its size is zero. (Bug#27504) --- src/xdisp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/xdisp.c b/src/xdisp.c index 784848913c0..8bc5d81f448 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -7768,9 +7768,8 @@ next_element_from_display_vector (struct it *it) /* KFS: This code used to check ip->dpvec[0] instead of the current element. That seemed totally bogus - so I changed it... */ - gc = it->dpvec[it->current.dpvec_index]; - - if (GLYPH_CODE_P (gc)) + if (it->dpend - it->dpvec > 0 /* empty dpvec[] is invalid */ + && (gc = it->dpvec[it->current.dpvec_index], GLYPH_CODE_P (gc))) { struct face *this_face, *prev_face, *next_face; -- cgit v1.2.1 From eb9d3eca801c1ea847956a96fafd29eef9bbe5d1 Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Sat, 11 Feb 2017 18:13:54 -0500 Subject: Escape control characters in backtraces (Bug#6991) * src/print.c (syms_of_print): Add new variable, print-escape-control-characters. (print_object): Print control characters with octal escape codes when print-escape-control-characters is true. * lisp/subr.el (backtrace): * lisp/emacs-lisp/debug.el (debugger-setup-buffer): Bind `print-escape-control-characters' to t. --- src/print.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/print.c b/src/print.c index 6bf8af9ef93..50c75d7712c 100644 --- a/src/print.c +++ b/src/print.c @@ -1870,21 +1870,36 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) } else { + bool still_need_nonhex = false; /* If we just had a hex escape, and this character could be taken as part of it, output `\ ' to prevent that. */ - if (need_nonhex && c_isxdigit (c)) - print_c_string ("\\ ", printcharfun); - - if (c == '\n' && print_escape_newlines - ? (c = 'n', true) - : c == '\f' && print_escape_newlines - ? (c = 'f', true) - : c == '\"' || c == '\\') - printchar ('\\', printcharfun); - - printchar (c, printcharfun); - need_nonhex = false; + if (c_isxdigit (c)) + { + if (need_nonhex) + print_c_string ("\\ ", printcharfun); + printchar (c, printcharfun); + } + else if (c == '\n' && print_escape_newlines + ? (c = 'n', true) + : c == '\f' && print_escape_newlines + ? (c = 'f', true) + : c == '\0' && print_escape_control_characters + ? (c = '0', still_need_nonhex = true) + : c == '\"' || c == '\\') + { + printchar ('\\', printcharfun); + printchar (c, printcharfun); + } + else if (print_escape_control_characters && c_iscntrl (c)) + { + char outbuf[1 + 3 + 1]; + int len = sprintf (outbuf, "\\%03o", c + 0u); + strout (outbuf, len, len, printcharfun); + } + else + printchar (c, printcharfun); + need_nonhex = still_need_nonhex; } } printchar ('\"', printcharfun); @@ -2329,6 +2344,11 @@ A value of nil means no limit. See also `eval-expression-print-level'. */); Also print formfeeds as `\\f'. */); print_escape_newlines = 0; + DEFVAR_BOOL ("print-escape-control-characters", print_escape_control_characters, + doc: /* Non-nil means print control characters in strings as `\\OOO'. +\(OOO is the octal representation of the character code.)*/); + print_escape_control_characters = 0; + DEFVAR_BOOL ("print-escape-nonascii", print_escape_nonascii, doc: /* Non-nil means print unibyte non-ASCII chars in strings as \\OOO. \(OOO is the octal representation of the character code.) @@ -2418,6 +2438,7 @@ priorities. */); DEFSYM (Qprint_escape_newlines, "print-escape-newlines"); DEFSYM (Qprint_escape_multibyte, "print-escape-multibyte"); DEFSYM (Qprint_escape_nonascii, "print-escape-nonascii"); + DEFSYM (Qprint_escape_control_characters, "print-escape-control-characters"); print_prune_charset_plist = Qnil; staticpro (&print_prune_charset_plist); -- cgit v1.2.1 From 0ad5fd4b6cac1824e50e5e8c1a43878825e7d3de Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sat, 1 Jul 2017 12:58:49 +0100 Subject: Fix threads on NS (bug#25265) src/nsterm.h (ns_select): Compiler doesn't like sigmask being const. (ns_run_loop_break) [HAVE_PTHREAD]: New function. src/nsterm.m (ns_select): Call thread_select from within ns_select. (ns_run_loop_break) [HAVE_PTHREAD]: New function. (ns_send_appdefined): Don't wait for main thread when sending app defined event. src/process.c (wait_reading_process_output): Call thread_select from within ns_select. src/systhread.c (sys_cond_broadcast) [HAVE_NS]: Break ns_select out of its event loop using ns_run_loop_break. --- src/nsterm.h | 7 +++++-- src/nsterm.m | 26 ++++++++++++++++++++++---- src/process.c | 13 ++++++------- src/systhread.c | 11 +++++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/nsterm.h b/src/nsterm.h index 84f7f0ab574..0f1b36db7b2 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -1233,8 +1233,11 @@ extern void x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, extern void x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timespec const *timeout, - sigset_t const *sigmask); + fd_set *exceptfds, struct timespec *timeout, + sigset_t *sigmask); +#ifdef HAVE_PTHREAD +extern void ns_run_loop_break (void); +#endif extern unsigned long ns_get_rgb_color (struct frame *f, float r, float g, float b, float a); diff --git a/src/nsterm.m b/src/nsterm.m index e05dbf45fbc..bf83550b3d7 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -4068,7 +4068,7 @@ ns_send_appdefined (int value) app->nextappdefined = value; [app performSelectorOnMainThread:@selector (sendFromMainThread:) withObject:nil - waitUntilDone:YES]; + waitUntilDone:NO]; return; } @@ -4293,8 +4293,8 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) int ns_select (int nfds, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timespec const *timeout, - sigset_t const *sigmask) + fd_set *exceptfds, struct timespec *timeout, + sigset_t *sigmask) /* -------------------------------------------------------------------------- Replacement for select, checking for events -------------------------------------------------------------------------- */ @@ -4327,7 +4327,13 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, if (NSApp == nil || ![NSThread isMainThread] || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0)) - return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask); + return thread_select(pselect, nfds, readfds, writefds, + exceptfds, timeout, sigmask); + else + { + struct timespec t = {0, 0}; + thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask); + } [outerpool release]; outerpool = [[NSAutoreleasePool alloc] init]; @@ -4430,6 +4436,18 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, return result; } +#ifdef HAVE_PTHREAD +void +ns_run_loop_break () +/* Break out of the NS run loop in ns_select or ns_read_socket. */ +{ + NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break"); + + /* If we don't have a GUI, don't send the event. */ + if (NSApp != NULL) + ns_send_appdefined(-1); +} +#endif /* ========================================================================== diff --git a/src/process.c b/src/process.c index 2a1c2eecde3..abd017bb907 100644 --- a/src/process.c +++ b/src/process.c @@ -5371,14 +5371,13 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, nfds = xg_select (max_desc + 1, &Available, (check_write ? &Writeok : 0), NULL, &timeout, NULL); +#elif defined HAVE_NS + /* And NS builds call thread_select in ns_select. */ + nfds = ns_select (max_desc + 1, + &Available, (check_write ? &Writeok : 0), + NULL, &timeout, NULL); #else /* !HAVE_GLIB */ - nfds = thread_select ( -# ifdef HAVE_NS - ns_select -# else - pselect -# endif - , max_desc + 1, + nfds = thread_select (pselect, max_desc + 1, &Available, (check_write ? &Writeok : 0), NULL, &timeout, NULL); diff --git a/src/systhread.c b/src/systhread.c index a84060c18f0..aee12a9b482 100644 --- a/src/systhread.c +++ b/src/systhread.c @@ -20,6 +20,10 @@ along with GNU Emacs. If not, see . */ #include #include "lisp.h" +#ifdef HAVE_NS +#include "nsterm.h" +#endif + #ifndef THREADS_ENABLED void @@ -130,6 +134,13 @@ void sys_cond_broadcast (sys_cond_t *cond) { pthread_cond_broadcast (cond); +#ifdef HAVE_NS + /* Send an app defined event to break out of the NS run loop. + It seems that if ns_select is running the NS run loop, this + broadcast has no effect until the loop is done, breaking a couple + of tests in thread-tests.el. */ + ns_run_loop_break (); +#endif } void -- cgit v1.2.1 From 0489f2ca5a01445d3abb39aea18d54257fedd5f1 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Sat, 1 Jul 2017 19:57:41 +0200 Subject: Improve C++98 compatibility * src/emacs-module.h.in (emacs_funcall_exit): Lose trailing comma. C++98 doesn't allow trailing commas in enumerations. --- src/emacs-module.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in index 339234fdb51..ec8db61f069 100644 --- a/src/emacs-module.h.in +++ b/src/emacs-module.h.in @@ -80,7 +80,7 @@ enum emacs_funcall_exit emacs_funcall_exit_signal = 1, /* Function has exit using `throw'. */ - emacs_funcall_exit_throw = 2, + emacs_funcall_exit_throw = 2 }; struct emacs_env_25 -- cgit v1.2.1 From c2f518cd73834099a67637cd69b4162e0e41f0e5 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Sat, 1 Jul 2017 19:58:57 +0200 Subject: Also mark module init function as noexcept if possible * src/emacs-module.h.in (emacs_module_init): Mark as noexcept if possible. --- src/emacs-module.h.in | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in index ec8db61f069..40b6448d27e 100644 --- a/src/emacs-module.h.in +++ b/src/emacs-module.h.in @@ -97,6 +97,7 @@ struct emacs_env_26 /* Every module should define a function as follows. */ extern int emacs_module_init (struct emacs_runtime *ert) + EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); #ifdef __cplusplus -- cgit v1.2.1 From 11cbedc68725a7a38d292180bbcda41d2aa3e0fc Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Sat, 1 Jul 2017 20:00:34 +0200 Subject: * src/module-env-25.h (copy_string_contents): Fix comment. --- src/module-env-25.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/module-env-25.h b/src/module-env-25.h index 17e67004b24..675010b995b 100644 --- a/src/module-env-25.h +++ b/src/module-env-25.h @@ -92,7 +92,7 @@ SIZE must point to the total size of the buffer. If BUFFER is NULL or if SIZE is not big enough, write the required buffer size - to SIZE and return false. + to SIZE and return true. Note that SIZE must include the last null byte (e.g. "abc" needs a buffer of size 4). -- cgit v1.2.1 From 3bab927884c4b795f8545b632328b5d3b632eed3 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Sun, 2 Jul 2017 13:15:52 +0200 Subject: Remove FIXME comments about sentinel values These FIXMEs can't be addressed because they would require breaking changes to the module API. Furthermore, other module functions don't return sentinel values as well, so users generally have to call non_local_exit_check anyway. * src/emacs-module.c (module_set_user_ptr) (module_set_user_finalizer, module_vec_set, module_vec_size): Remove FIXME comments. --- src/emacs-module.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/emacs-module.c b/src/emacs-module.c index 9e072029cc1..7b1a402eeff 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -601,7 +601,6 @@ module_get_user_ptr (emacs_env *env, emacs_value uptr) static void module_set_user_ptr (emacs_env *env, emacs_value uptr, void *ptr) { - /* FIXME: This function should return bool because it can fail. */ MODULE_FUNCTION_BEGIN (); Lisp_Object lisp = value_to_lisp (uptr); CHECK_USER_PTR (lisp); @@ -621,7 +620,6 @@ static void module_set_user_finalizer (emacs_env *env, emacs_value uptr, emacs_finalizer_function fin) { - /* FIXME: This function should return bool because it can fail. */ MODULE_FUNCTION_BEGIN (); Lisp_Object lisp = value_to_lisp (uptr); CHECK_USER_PTR (lisp); @@ -640,7 +638,6 @@ check_vec_index (Lisp_Object lvec, ptrdiff_t i) static void module_vec_set (emacs_env *env, emacs_value vec, ptrdiff_t i, emacs_value val) { - /* FIXME: This function should return bool because it can fail. */ MODULE_FUNCTION_BEGIN (); Lisp_Object lvec = value_to_lisp (vec); check_vec_index (lvec, i); @@ -659,7 +656,6 @@ module_vec_get (emacs_env *env, emacs_value vec, ptrdiff_t i) static ptrdiff_t module_vec_size (emacs_env *env, emacs_value vec) { - /* FIXME: Return a sentinel value (e.g., -1) on error. */ MODULE_FUNCTION_BEGIN (0); Lisp_Object lvec = value_to_lisp (vec); CHECK_VECTOR (lvec); -- cgit v1.2.1