aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDmitry Gutov2022-08-15 02:22:59 +0300
committerDmitry Gutov2022-08-15 02:22:59 +0300
commitee3a674c7c9e39fe7ff296ce1f9830fc45520de8 (patch)
treee8ba1e7be54314f208454e80e3d31044c913f3eb /src
parentfe0e53d963899a16e0dd1bbc1ba10a6b59f7989e (diff)
parent0a8e88fd83db5398d36064a7f87cff5b57da7284 (diff)
downloademacs-scratch/font_lock_large_files.tar.gz
emacs-scratch/font_lock_large_files.zip
Merge branch 'master' into scratch/font_lock_large_filesscratch/font_lock_large_files
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in1
-rw-r--r--src/buffer.c21
-rw-r--r--src/eval.c59
-rw-r--r--src/ftcrfont.c6
-rw-r--r--src/indent.c60
-rw-r--r--src/keyboard.c25
-rw-r--r--src/lisp.h2
-rw-r--r--src/timefns.c71
-rw-r--r--src/window.c9
-rw-r--r--src/xdisp.c203
-rw-r--r--src/xfns.c19
-rw-r--r--src/xterm.c250
12 files changed, 595 insertions, 131 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 92a8790efdc..a7024bda461 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -845,7 +845,6 @@ ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
845## List of *.eln files we need to produce in addition to the preloaded 845## List of *.eln files we need to produce in addition to the preloaded
846## ones in $(lisp). 846## ones in $(lisp).
847elnlisp := \ 847elnlisp := \
848 emacs-lisp/autoload.eln \
849 emacs-lisp/byte-opt.eln \ 848 emacs-lisp/byte-opt.eln \
850 emacs-lisp/bytecomp.eln \ 849 emacs-lisp/bytecomp.eln \
851 emacs-lisp/cconv.eln \ 850 emacs-lisp/cconv.eln \
diff --git a/src/buffer.c b/src/buffer.c
index e5601af5051..98066a2eb60 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1160,7 +1160,8 @@ is first appended to NAME, to speed up finding a non-existent buffer. */)
1160 genbase = name; 1160 genbase = name;
1161 else 1161 else
1162 { 1162 {
1163 char number[sizeof "-999999"]; 1163 enum { bug_52711 = true }; /* https://bugs.gnu.org/57211 */
1164 char number[bug_52711 ? INT_BUFSIZE_BOUND (int) + 1 : sizeof "-999999"];
1164 EMACS_INT r = get_random (); 1165 EMACS_INT r = get_random ();
1165 eassume (0 <= r); 1166 eassume (0 <= r);
1166 int i = r % 1000000; 1167 int i = r % 1000000;
@@ -6442,6 +6443,24 @@ If nil, these display shortcuts will always remain disabled.
6442There is no reason to change that value except for debugging purposes. */); 6443There is no reason to change that value except for debugging purposes. */);
6443 XSETFASTINT (Vlong_line_threshold, 10000); 6444 XSETFASTINT (Vlong_line_threshold, 10000);
6444 6445
6446 DEFVAR_INT ("large-hscroll-threshold", large_hscroll_threshold,
6447 doc: /* Horizontal scroll of truncated lines above which to use redisplay shortcuts.
6448
6449The value should be a positive integer.
6450
6451Shortcuts in the display code intended to speed up redisplay for long
6452and truncated lines will automatically be enabled when a line's
6453horizontal scroll amount is or about to become larger than the value
6454of this variable.
6455
6456This variable has effect only in buffers which contain one or more
6457lines whose length is above `long-line-threshold', which see.
6458To disable redisplay shortcuts for long truncated line, set this
6459variable to `most-positive-fixnum'.
6460
6461There is no reason to change that value except for debugging purposes. */);
6462 large_hscroll_threshold = 10000;
6463
6445 defsubr (&Sbuffer_live_p); 6464 defsubr (&Sbuffer_live_p);
6446 defsubr (&Sbuffer_list); 6465 defsubr (&Sbuffer_list);
6447 defsubr (&Sget_buffer); 6466 defsubr (&Sget_buffer);
diff --git a/src/eval.c b/src/eval.c
index d82d05797b2..56b42966623 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -57,6 +57,12 @@ Lisp_Object Vrun_hooks;
57/* FIXME: We should probably get rid of this! */ 57/* FIXME: We should probably get rid of this! */
58Lisp_Object Vsignaling_function; 58Lisp_Object Vsignaling_function;
59 59
60/* The handler structure which will catch errors in Lisp hooks called
61 from redisplay. We do not use it for this; we compare it with the
62 handler which is about to be used in signal_or_quit, and if it
63 matches, cause a backtrace to be generated. */
64static struct handler *redisplay_deep_handler;
65
60/* These would ordinarily be static, but they need to be visible to GDB. */ 66/* These would ordinarily be static, but they need to be visible to GDB. */
61bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; 67bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE;
62Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; 68Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE;
@@ -246,6 +252,7 @@ init_eval (void)
246 lisp_eval_depth = 0; 252 lisp_eval_depth = 0;
247 /* This is less than the initial value of num_nonmacro_input_events. */ 253 /* This is less than the initial value of num_nonmacro_input_events. */
248 when_entered_debugger = -1; 254 when_entered_debugger = -1;
255 redisplay_deep_handler = NULL;
249} 256}
250 257
251/* Ensure that *M is at least A + B if possible, or is its maximum 258/* Ensure that *M is at least A + B if possible, or is its maximum
@@ -333,7 +340,8 @@ call_debugger (Lisp_Object arg)
333 /* Interrupting redisplay and resuming it later is not safe under 340 /* Interrupting redisplay and resuming it later is not safe under
334 all circumstances. So, when the debugger returns, abort the 341 all circumstances. So, when the debugger returns, abort the
335 interrupted redisplay by going back to the top-level. */ 342 interrupted redisplay by going back to the top-level. */
336 if (debug_while_redisplaying) 343 if (debug_while_redisplaying
344 && !EQ (Vdebugger, Qdebug_early))
337 Ftop_level (); 345 Ftop_level ();
338 346
339 return unbind_to (count, val); 347 return unbind_to (count, val);
@@ -1556,12 +1564,16 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
1556 ptrdiff_t nargs, 1564 ptrdiff_t nargs,
1557 Lisp_Object *args)) 1565 Lisp_Object *args))
1558{ 1566{
1567 struct handler *old_deep = redisplay_deep_handler;
1559 struct handler *c = push_handler (handlers, CONDITION_CASE); 1568 struct handler *c = push_handler (handlers, CONDITION_CASE);
1569 if (redisplaying_p)
1570 redisplay_deep_handler = c;
1560 if (sys_setjmp (c->jmp)) 1571 if (sys_setjmp (c->jmp))
1561 { 1572 {
1562 Lisp_Object val = handlerlist->val; 1573 Lisp_Object val = handlerlist->val;
1563 clobbered_eassert (handlerlist == c); 1574 clobbered_eassert (handlerlist == c);
1564 handlerlist = handlerlist->next; 1575 handlerlist = handlerlist->next;
1576 redisplay_deep_handler = old_deep;
1565 return hfun (val, nargs, args); 1577 return hfun (val, nargs, args);
1566 } 1578 }
1567 else 1579 else
@@ -1569,6 +1581,7 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
1569 Lisp_Object val = bfun (nargs, args); 1581 Lisp_Object val = bfun (nargs, args);
1570 eassert (handlerlist == c); 1582 eassert (handlerlist == c);
1571 handlerlist = c->next; 1583 handlerlist = c->next;
1584 redisplay_deep_handler = old_deep;
1572 return val; 1585 return val;
1573 } 1586 }
1574} 1587}
@@ -1701,6 +1714,11 @@ quit (void)
1701 return signal_or_quit (Qquit, Qnil, true); 1714 return signal_or_quit (Qquit, Qnil, true);
1702} 1715}
1703 1716
1717/* Has an error in redisplay giving rise to a backtrace occurred as
1718 yet in the current command? This gets reset in the command
1719 loop. */
1720bool backtrace_yet = false;
1721
1704/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal. 1722/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal.
1705 If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be 1723 If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be
1706 Qquit and DATA should be Qnil, and this function may return. 1724 Qquit and DATA should be Qnil, and this function may return.
@@ -1816,6 +1834,40 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1816 unbind_to (count, Qnil); 1834 unbind_to (count, Qnil);
1817 } 1835 }
1818 1836
1837 /* If an error is signalled during a Lisp hook in redisplay, write a
1838 backtrace into the buffer *Redisplay-trace*. */
1839 if (!debugger_called && !NILP (error_symbol)
1840 && backtrace_on_redisplay_error
1841 && (NILP (clause) || h == redisplay_deep_handler)
1842 && NILP (Vinhibit_debugger)
1843 && !NILP (Ffboundp (Qdebug_early)))
1844 {
1845 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
1846 specpdl_ref count = SPECPDL_INDEX ();
1847 ptrdiff_t counti = specpdl_ref_to_count (count);
1848 AUTO_STRING (redisplay_trace, "*Redisplay_trace*");
1849 Lisp_Object redisplay_trace_buffer;
1850 AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* */
1851 Lisp_Object delayed_warning;
1852 max_ensure_room (&max_specpdl_size, counti, 200);
1853 redisplay_trace_buffer = Fget_buffer_create (redisplay_trace, Qnil);
1854 current_buffer = XBUFFER (redisplay_trace_buffer);
1855 if (!backtrace_yet) /* Are we on the first backtrace of the command? */
1856 Ferase_buffer ();
1857 else
1858 Finsert (1, &gap);
1859 backtrace_yet = true;
1860 specbind (Qstandard_output, redisplay_trace_buffer);
1861 specbind (Qdebugger, Qdebug_early);
1862 call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
1863 unbind_to (count, Qnil);
1864 delayed_warning = make_string
1865 ("Error in a redisplay Lisp hook. See buffer *Redisplay_trace*", 61);
1866
1867 Vdelayed_warnings_list = Fcons (list2 (Qerror, delayed_warning),
1868 Vdelayed_warnings_list);
1869 }
1870
1819 if (!NILP (clause)) 1871 if (!NILP (clause))
1820 { 1872 {
1821 Lisp_Object unwind_data 1873 Lisp_Object unwind_data
@@ -4278,6 +4330,11 @@ Does not apply if quit is handled by a `condition-case'. */);
4278 DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call, 4330 DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call,
4279 doc: /* Non-nil means enter debugger before next `eval', `apply' or `funcall'. */); 4331 doc: /* Non-nil means enter debugger before next `eval', `apply' or `funcall'. */);
4280 4332
4333 DEFVAR_BOOL ("backtrace-on-redisplay-error", backtrace_on_redisplay_error,
4334 doc: /* Non-nil means create a backtrace if a lisp error occurs in redisplay.
4335The backtrace is written to buffer *Redisplay-trace*. */);
4336 backtrace_on_redisplay_error = false;
4337
4281 DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue, 4338 DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue,
4282 doc: /* Non-nil means debugger may continue execution. 4339 doc: /* Non-nil means debugger may continue execution.
4283This is nil when the debugger is called under circumstances where it 4340This is nil when the debugger is called under circumstances where it
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 119ec284094..e089f9dea85 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -677,7 +677,11 @@ ftcrhbfont_begin_hb_font (struct font *font, double *position_unit)
677 677
678 ftcrfont_info->ft_size = ft_face->size; 678 ftcrfont_info->ft_size = ft_face->size;
679 hb_font_t *hb_font = fthbfont_begin_hb_font (font, position_unit); 679 hb_font_t *hb_font = fthbfont_begin_hb_font (font, position_unit);
680 if (ftcrfont_info->bitmap_position_unit) 680 /* HarfBuzz 5 correctly scales bitmap-only fonts without position
681 unit adjustment.
682 (https://github.com/harfbuzz/harfbuzz/issues/489) */
683 if (!hb_version_atleast (5, 0, 0)
684 && ftcrfont_info->bitmap_position_unit)
681 *position_unit = ftcrfont_info->bitmap_position_unit; 685 *position_unit = ftcrfont_info->bitmap_position_unit;
682 686
683 return hb_font; 687 return hb_font;
diff --git a/src/indent.c b/src/indent.c
index d2dfaee254e..cb368024d97 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -306,8 +306,8 @@ and point (e.g., control characters will have a width of 2 or 4, tabs
306will have a variable width). 306will have a variable width).
307Ignores finite width of frame, which means that this function may return 307Ignores finite width of frame, which means that this function may return
308values greater than (frame-width). 308values greater than (frame-width).
309In a buffer with very long lines, the value can be zero, because calculating 309In a buffer with very long lines, the value will be an approximation,
310the exact number is very expensive. 310because calculating the exact number is very expensive.
311Whether the line is visible (if `selective-display' is t) has no effect; 311Whether the line is visible (if `selective-display' is t) has no effect;
312however, ^M is treated as end of line when `selective-display' is t. 312however, ^M is treated as end of line when `selective-display' is t.
313Text that has an invisible property is considered as having width 0, unless 313Text that has an invisible property is considered as having width 0, unless
@@ -316,8 +316,6 @@ Text that has an invisible property is considered as having width 0, unless
316{ 316{
317 Lisp_Object temp; 317 Lisp_Object temp;
318 318
319 if (current_buffer->long_line_optimizations_p)
320 return make_fixnum (0);
321 XSETFASTINT (temp, current_column ()); 319 XSETFASTINT (temp, current_column ());
322 return temp; 320 return temp;
323} 321}
@@ -346,6 +344,14 @@ current_column (void)
346 && MODIFF == last_known_column_modified) 344 && MODIFF == last_known_column_modified)
347 return last_known_column; 345 return last_known_column;
348 346
347 ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
348 NULL, NULL, 1);
349
350 /* Avoid becoming abysmally slow for very long lines. */
351 if (current_buffer->long_line_optimizations_p
352 && !NILP (Vlong_line_threshold)
353 && PT - line_beg > XFIXNUM (Vlong_line_threshold))
354 return PT - line_beg; /* this is an approximation! */
349 /* If the buffer has overlays, text properties, 355 /* If the buffer has overlays, text properties,
350 or multibyte characters, use a more general algorithm. */ 356 or multibyte characters, use a more general algorithm. */
351 if (buffer_intervals (current_buffer) 357 if (buffer_intervals (current_buffer)
@@ -561,13 +567,53 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
561 ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos; 567 ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
562 568
563 scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1); 569 scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
564 next_boundary = scan;
565 prev_pos = scan;
566 prev_bpos = scan_byte;
567 570
568 window = Fget_buffer_window (Fcurrent_buffer (), Qnil); 571 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
569 w = ! NILP (window) ? XWINDOW (window) : NULL; 572 w = ! NILP (window) ? XWINDOW (window) : NULL;
570 573
574 if (current_buffer->long_line_optimizations_p)
575 {
576 bool lines_truncated = false;
577
578 if (!NILP (BVAR (current_buffer, truncate_lines)))
579 lines_truncated = true;
580 else if (w && FIXNUMP (Vtruncate_partial_width_windows))
581 lines_truncated =
582 w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
583 else if (w && !NILP (Vtruncate_partial_width_windows))
584 lines_truncated =
585 w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w)));
586 /* Special optimization for buffers with long and truncated
587 lines: assumes that each character is a single column. */
588 if (lines_truncated)
589 {
590 ptrdiff_t bolpos = scan;
591 /* The newline which ends this line or ZV. */
592 ptrdiff_t eolpos =
593 find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
594
595 scan = bolpos + goal;
596 if (scan > end)
597 scan = end;
598 if (scan > eolpos)
599 scan = (eolpos == ZV ? ZV : eolpos - 1);
600 col = scan - bolpos;
601 if (col > large_hscroll_threshold)
602 {
603 prev_col = col - 1;
604 prev_pos = scan - 1;
605 prev_bpos = CHAR_TO_BYTE (scan);
606 goto endloop;
607 }
608 /* Restore the values we've overwritten above. */
609 scan = bolpos;
610 col = 0;
611 }
612 }
613 next_boundary = scan;
614 prev_pos = scan;
615 prev_bpos = scan_byte;
616
571 memset (&cmp_it, 0, sizeof cmp_it); 617 memset (&cmp_it, 0, sizeof cmp_it);
572 cmp_it.id = -1; 618 cmp_it.id = -1;
573 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil); 619 composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
diff --git a/src/keyboard.c b/src/keyboard.c
index 4ad6e4e6bd1..8a2b7d58c4b 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1331,6 +1331,7 @@ command_loop_1 (void)
1331 display_malloc_warning (); 1331 display_malloc_warning ();
1332 1332
1333 Vdeactivate_mark = Qnil; 1333 Vdeactivate_mark = Qnil;
1334 backtrace_yet = false;
1334 1335
1335 /* Don't ignore mouse movements for more than a single command 1336 /* Don't ignore mouse movements for more than a single command
1336 loop. (This flag is set in xdisp.c whenever the tool bar is 1337 loop. (This flag is set in xdisp.c whenever the tool bar is
@@ -1841,7 +1842,7 @@ safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args)
1841static Lisp_Object 1842static Lisp_Object
1842safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args) 1843safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
1843{ 1844{
1844 eassert (nargs == 2); 1845 eassert (nargs >= 2 && nargs <= 4);
1845 AUTO_STRING (format, "Error in %s (%S): %S"); 1846 AUTO_STRING (format, "Error in %s (%S): %S");
1846 Lisp_Object hook = args[0]; 1847 Lisp_Object hook = args[0];
1847 Lisp_Object fun = args[1]; 1848 Lisp_Object fun = args[1];
@@ -1915,6 +1916,17 @@ safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w)
1915 unbind_to (count, Qnil); 1916 unbind_to (count, Qnil);
1916} 1917}
1917 1918
1919void
1920safe_run_hooks_2 (Lisp_Object hook, Lisp_Object arg1, Lisp_Object arg2)
1921{
1922 specpdl_ref count = SPECPDL_INDEX ();
1923
1924 specbind (Qinhibit_quit, Qt);
1925 run_hook_with_args (4, ((Lisp_Object []) {hook, hook, arg1, arg2}),
1926 safe_run_hook_funcall);
1927 unbind_to (count, Qnil);
1928}
1929
1918 1930
1919/* Nonzero means polling for input is temporarily suppressed. */ 1931/* Nonzero means polling for input is temporarily suppressed. */
1920 1932
@@ -12638,10 +12650,17 @@ cancels any modification. */);
12638 12650
12639 DEFSYM (Qdeactivate_mark, "deactivate-mark"); 12651 DEFSYM (Qdeactivate_mark, "deactivate-mark");
12640 DEFVAR_LISP ("deactivate-mark", Vdeactivate_mark, 12652 DEFVAR_LISP ("deactivate-mark", Vdeactivate_mark,
12641 doc: /* If an editing command sets this to t, deactivate the mark afterward. 12653 doc: /* Whether to deactivate the mark after an editing command.
12642The command loop sets this to nil before each command, 12654The command loop sets this to nil before each command,
12643and tests the value when the command returns. 12655and tests the value when the command returns.
12644Buffer modification stores t in this variable. */); 12656If an editing command sets this non-nil, deactivate the mark after
12657the command returns.
12658
12659Buffer modifications store t in this variable.
12660
12661By default, deactivating the mark will save the contents of the region
12662according to `select-active-regions', unless this is set to the symbol
12663`dont-save'. */);
12645 Vdeactivate_mark = Qnil; 12664 Vdeactivate_mark = Qnil;
12646 Fmake_variable_buffer_local (Qdeactivate_mark); 12665 Fmake_variable_buffer_local (Qdeactivate_mark);
12647 12666
diff --git a/src/lisp.h b/src/lisp.h
index fe6e98843d1..2f73ba4c617 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4530,6 +4530,7 @@ extern Lisp_Object Vrun_hooks;
4530extern Lisp_Object Vsignaling_function; 4530extern Lisp_Object Vsignaling_function;
4531extern Lisp_Object inhibit_lisp_code; 4531extern Lisp_Object inhibit_lisp_code;
4532extern bool signal_quit_p (Lisp_Object); 4532extern bool signal_quit_p (Lisp_Object);
4533extern bool backtrace_yet;
4533 4534
4534/* To run a normal hook, use the appropriate function from the list below. 4535/* To run a normal hook, use the appropriate function from the list below.
4535 The calling convention: 4536 The calling convention:
@@ -4831,6 +4832,7 @@ extern bool detect_input_pending_ignore_squeezables (void);
4831extern bool detect_input_pending_run_timers (bool); 4832extern bool detect_input_pending_run_timers (bool);
4832extern void safe_run_hooks (Lisp_Object); 4833extern void safe_run_hooks (Lisp_Object);
4833extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *); 4834extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *);
4835extern void safe_run_hooks_2 (Lisp_Object, Lisp_Object, Lisp_Object);
4834extern void cmd_error_internal (Lisp_Object, const char *); 4836extern void cmd_error_internal (Lisp_Object, const char *);
4835extern Lisp_Object command_loop_2 (Lisp_Object); 4837extern Lisp_Object command_loop_2 (Lisp_Object);
4836extern Lisp_Object read_menu_command (void); 4838extern Lisp_Object read_menu_command (void);
diff --git a/src/timefns.c b/src/timefns.c
index 1112f174763..eed2edf1cc0 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -401,6 +401,10 @@ decode_float_time (double t, struct lisp_time *result)
401 else 401 else
402 { 402 {
403 int scale = double_integer_scale (t); 403 int scale = double_integer_scale (t);
404 /* FIXME: `double_integer_scale` often returns values that are
405 "pessimistic" (i.e. larger than necessary), so 3.5 gets converted
406 to (7881299347898368 . 2251799813685248) rather than (7 . 2).
407 On 64bit systems, this should not matter very much, tho. */
404 eassume (scale < flt_radix_power_size); 408 eassume (scale < flt_radix_power_size);
405 409
406 if (scale < 0) 410 if (scale < 0)
@@ -818,17 +822,6 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only,
818 822
819 if (NILP (specified_time)) 823 if (NILP (specified_time))
820 form = TIMEFORM_NIL; 824 form = TIMEFORM_NIL;
821 else if (FLOATP (specified_time))
822 {
823 double d = XFLOAT_DATA (specified_time);
824 if (!isfinite (d))
825 time_error (isnan (d) ? EDOM : EOVERFLOW);
826 if (result)
827 decode_float_time (d, result);
828 else
829 *dresult = d;
830 return TIMEFORM_FLOAT;
831 }
832 else if (CONSP (specified_time)) 825 else if (CONSP (specified_time))
833 { 826 {
834 high = XCAR (specified_time); 827 high = XCAR (specified_time);
@@ -868,6 +861,22 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only,
868 if (! INTEGERP (low)) 861 if (! INTEGERP (low))
869 form = TIMEFORM_INVALID; 862 form = TIMEFORM_INVALID;
870 } 863 }
864 else if (FASTER_TIMEFNS && INTEGERP (specified_time))
865 {
866 decode_ticks_hz (specified_time, make_fixnum (1), result, dresult);
867 return form;
868 }
869 else if (FLOATP (specified_time))
870 {
871 double d = XFLOAT_DATA (specified_time);
872 if (!isfinite (d))
873 time_error (isnan (d) ? EDOM : EOVERFLOW);
874 if (result)
875 decode_float_time (d, result);
876 else
877 *dresult = d;
878 return TIMEFORM_FLOAT;
879 }
871 880
872 int err = decode_time_components (form, high, low, usec, psec, 881 int err = decode_time_components (form, high, low, usec, psec,
873 result, dresult); 882 result, dresult);
@@ -1202,10 +1211,16 @@ time_cmp (Lisp_Object a, Lisp_Object b)
1202 return 0; 1211 return 0;
1203 1212
1204 /* Compare (X . Z) to (Y . Z) quickly if X and Y are fixnums. 1213 /* Compare (X . Z) to (Y . Z) quickly if X and Y are fixnums.
1205 Do not inspect Z, as it is OK to not signal if A and B are invalid. */ 1214 Do not inspect Z, as it is OK to not signal if A and B are invalid.
1206 if (FASTER_TIMEFNS && CONSP (a) && CONSP (b) && BASE_EQ (XCDR (a), XCDR (b)) 1215 Also, compare X to Y quickly if X and Y are fixnums. */
1207 && FIXNUMP (XCAR (a)) && FIXNUMP (XCAR (b))) 1216 if (FASTER_TIMEFNS)
1208 return XFIXNUM (XCAR (a)) - XFIXNUM (XCAR (b)); 1217 {
1218 Lisp_Object x = a, y = b;
1219 if (CONSP (a) && CONSP (b) && BASE_EQ (XCDR (a), XCDR (b)))
1220 x = XCAR (a), y = XCAR (b);
1221 if (FIXNUMP (x) && FIXNUMP (y))
1222 return XFIXNUM (x) - XFIXNUM (y);
1223 }
1209 1224
1210 /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing 1225 /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing
1211 ATICKS * BHZ to BTICKS * AHZ. */ 1226 ATICKS * BHZ to BTICKS * AHZ. */
@@ -1714,21 +1729,29 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
1714} 1729}
1715 1730
1716DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0, 1731DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0,
1717 doc: /* Convert TIME value to a Lisp timestamp. 1732 doc: /* Convert TIME value to a Lisp timestamp of the given FORM.
1718With optional FORM, convert to that timestamp form.
1719Truncate the returned value toward minus infinity. 1733Truncate the returned value toward minus infinity.
1720 1734
1721If FORM is nil (the default), return the same form as `current-time'.
1722If FORM is a positive integer, return a pair of integers (TICKS . FORM), 1735If FORM is a positive integer, return a pair of integers (TICKS . FORM),
1723where TICKS is the number of clock ticks and FORM is the clock frequency 1736where TICKS is the number of clock ticks and FORM is the clock frequency
1724in ticks per second. If FORM is t, return (TICKS . PHZ), where 1737in ticks per second.
1725PHZ is a suitable clock frequency in ticks per second. If FORM is 1738
1726`integer', return an integer count of seconds. If FORM is `list', 1739If FORM is t, return (TICKS . PHZ), where PHZ is a suitable clock
1727return an integer list (HIGH LOW USEC PSEC), where HIGH has the most 1740frequency in ticks per second.
1728significant bits of the seconds, LOW has the least significant 16 1741
1729bits, and USEC and PSEC are the microsecond and picosecond counts. */) 1742If FORM is `integer', return an integer count of seconds.
1743
1744If FORM is `list', return an integer list (HIGH LOW USEC PSEC), where
1745HIGH has the most significant bits of the seconds, LOW has the least
1746significant 16 bits, and USEC and PSEC are the microsecond and
1747picosecond counts.
1748
1749If FORM is nil, the behavior depends on `current-time-list',
1750but new code should not rely on it. */)
1730 (Lisp_Object time, Lisp_Object form) 1751 (Lisp_Object time, Lisp_Object form)
1731{ 1752{
1753 /* FIXME: Any reason why we don't offer a `float` output format option as
1754 well, since we accept it as input? */
1732 struct lisp_time t; 1755 struct lisp_time t;
1733 enum timeform input_form = decode_lisp_time (time, false, &t, 0); 1756 enum timeform input_form = decode_lisp_time (time, false, &t, 0);
1734 if (NILP (form)) 1757 if (NILP (form))
diff --git a/src/window.c b/src/window.c
index afb8f75537b..c8fcb3a607f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6575,9 +6575,12 @@ and redisplay normally--don't erase and redraw the frame. */)
6575 in case scroll_margin is buffer-local. */ 6575 in case scroll_margin is buffer-local. */
6576 this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES); 6576 this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES);
6577 6577
6578 /* Don't use redisplay code for initial frames, as the necessary 6578 /* Don't use the display code for initial frames, as the necessary
6579 data structures might not be set up yet then. */ 6579 data structures might not be set up yet then. Also don't use it
6580 if (!FRAME_INITIAL_P (XFRAME (w->frame))) 6580 for buffers with very long lines, as it tremdously slows down
6581 redisplay, especially when lines are truncated. */
6582 if (!FRAME_INITIAL_P (XFRAME (w->frame))
6583 && !current_buffer->long_line_optimizations_p)
6581 { 6584 {
6582 specpdl_ref count = SPECPDL_INDEX (); 6585 specpdl_ref count = SPECPDL_INDEX ();
6583 6586
diff --git a/src/xdisp.c b/src/xdisp.c
index 1fcff2c2e3b..1e8f70b2db9 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -11040,6 +11040,15 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
11040int 11040int
11041partial_line_height (struct it *it_origin) 11041partial_line_height (struct it *it_origin)
11042{ 11042{
11043 /* In a buffer with very long and truncated lines, we ignore the
11044 possibly-partial height of the last line in the window: it is too
11045 expensive to compute that (since in most cases that involves
11046 going all the way to ZV), and the effect of ignoring it is
11047 relatively minor. */
11048 if (XBUFFER (it_origin->w->contents)->long_line_optimizations_p
11049 && it_origin->line_wrap == TRUNCATE)
11050 return 0;
11051
11043 int partial_height; 11052 int partial_height;
11044 void *it_data = NULL; 11053 void *it_data = NULL;
11045 struct it it; 11054 struct it it;
@@ -11063,6 +11072,51 @@ partial_line_height (struct it *it_origin)
11063 return partial_height; 11072 return partial_height;
11064} 11073}
11065 11074
11075/* Approximate move_it_in_display_line_to for very long and truncated
11076 display lines, when moving horizontally. This is used when the
11077 buffer's long_line_optimizations_p flag is set. It ignores various
11078 complications, like different font sizes, invisible text, display
11079 and overlay strings, and, to some degree, bidirectional text. So
11080 caveat emptor!
11081
11082 Starting from IT's position, reseat IT after skipping NCHARS
11083 characters or to the next newline/ZV, whichever comes first. Return
11084 what move_it_in_display_line_to would have returned in this case. */
11085
11086static enum move_it_result
11087fast_move_it_horizontally (struct it *it, ptrdiff_t nchars)
11088{
11089 ptrdiff_t nl_bytepos;
11090 ptrdiff_t nl_pos = find_newline_no_quit (IT_CHARPOS (*it), IT_BYTEPOS (*it),
11091 1, &nl_bytepos);
11092 struct text_pos new_pos;
11093 enum move_it_result move_result;
11094
11095 if (nl_pos - IT_CHARPOS (*it) > nchars)
11096 {
11097 SET_TEXT_POS (new_pos,
11098 IT_CHARPOS (*it) + nchars,
11099 CHAR_TO_BYTE (IT_CHARPOS (*it) + nchars));
11100 move_result = MOVE_X_REACHED;
11101 }
11102 else
11103 {
11104 if (nl_bytepos < ZV_BYTE
11105 || (nl_bytepos > BEGV_BYTE
11106 && FETCH_BYTE (nl_bytepos - 1) == '\n'))
11107 {
11108 nl_pos--;
11109 nl_bytepos--;
11110 move_result = MOVE_NEWLINE_OR_CR;
11111 }
11112 else
11113 move_result = MOVE_POS_MATCH_OR_ZV;
11114 SET_TEXT_POS (new_pos, nl_pos, nl_bytepos);
11115 }
11116 reseat (it, new_pos, false);
11117 return move_result;
11118}
11119
11066/* Return true if IT points into the middle of a display vector. */ 11120/* Return true if IT points into the middle of a display vector. */
11067 11121
11068bool 11122bool
@@ -13106,8 +13160,7 @@ mode_line_update_needed (struct window *w)
13106{ 13160{
13107 return (w->column_number_displayed != -1 13161 return (w->column_number_displayed != -1
13108 && !(PT == w->last_point && !window_outdated (w)) 13162 && !(PT == w->last_point && !window_outdated (w))
13109 && (!current_buffer->long_line_optimizations_p 13163 && (w->column_number_displayed != current_column ()));
13110 && w->column_number_displayed != current_column ()));
13111} 13164}
13112 13165
13113/* True if window start of W is frozen and may not be changed during 13166/* True if window start of W is frozen and may not be changed during
@@ -15776,7 +15829,20 @@ hscroll_window_tree (Lisp_Object window)
15776 it.first_visible_x = window_hscroll_limited (w, it.f) 15829 it.first_visible_x = window_hscroll_limited (w, it.f)
15777 * FRAME_COLUMN_WIDTH (it.f); 15830 * FRAME_COLUMN_WIDTH (it.f);
15778 it.last_visible_x = DISP_INFINITY; 15831 it.last_visible_x = DISP_INFINITY;
15779 move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); 15832
15833 ptrdiff_t nchars = pt - IT_CHARPOS (it);
15834 if (current_buffer->long_line_optimizations_p
15835 && nchars > large_hscroll_threshold)
15836 {
15837 /* Special optimization for very long and truncated
15838 lines which need to be hscrolled far to the left:
15839 jump directly to the (approximate) first position
15840 that is visible, instead of slowly walking there. */
15841 fast_move_it_horizontally (&it, nchars);
15842 it.current_x += nchars * FRAME_COLUMN_WIDTH (it.f);
15843 }
15844 else
15845 move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
15780 /* If the line ends in an overlay string with a newline, 15846 /* If the line ends in an overlay string with a newline,
15781 we might infloop, because displaying the window will 15847 we might infloop, because displaying the window will
15782 want to put the cursor after the overlay, i.e. at X 15848 want to put the cursor after the overlay, i.e. at X
@@ -15789,7 +15855,14 @@ hscroll_window_tree (Lisp_Object window)
15789 if (hscl) 15855 if (hscl)
15790 it.first_visible_x = (window_hscroll_limited (w, it.f) 15856 it.first_visible_x = (window_hscroll_limited (w, it.f)
15791 * FRAME_COLUMN_WIDTH (it.f)); 15857 * FRAME_COLUMN_WIDTH (it.f));
15792 move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); 15858 if (current_buffer->long_line_optimizations_p
15859 && nchars > large_hscroll_threshold)
15860 {
15861 fast_move_it_horizontally (&it, nchars - 1);
15862 it.current_x += (nchars - 1) * FRAME_COLUMN_WIDTH (it.f);
15863 }
15864 else
15865 move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS);
15793 } 15866 }
15794 current_buffer = saved_current_buffer; 15867 current_buffer = saved_current_buffer;
15795 15868
@@ -16727,9 +16800,23 @@ redisplay_internal (void)
16727 it.current_y = this_line_y; 16800 it.current_y = this_line_y;
16728 it.vpos = this_line_vpos; 16801 it.vpos = this_line_vpos;
16729 16802
16730 /* The call to move_it_to stops in front of PT, but 16803 if (current_buffer->long_line_optimizations_p
16731 moves over before-strings. */ 16804 && it.line_wrap == TRUNCATE
16732 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); 16805 && PT - CHARPOS (tlbufpos) > large_hscroll_threshold)
16806 {
16807 /* When lines are very long and truncated, jumping to
16808 the next visible line is much faster than slowly
16809 iterating there. */
16810 reseat_at_next_visible_line_start (&it, false);
16811 if (IT_CHARPOS (it) <= PT) /* point moved off this line */
16812 it.vpos = this_line_vpos + 1;
16813 }
16814 else
16815 {
16816 /* The call to move_it_to stops in front of PT, but
16817 moves over before-strings. */
16818 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
16819 }
16733 16820
16734 if (it.vpos == this_line_vpos 16821 if (it.vpos == this_line_vpos
16735 && (row = MATRIX_ROW (w->current_matrix, this_line_vpos), 16822 && (row = MATRIX_ROW (w->current_matrix, this_line_vpos),
@@ -18119,8 +18206,8 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
18119 { 18206 {
18120 specpdl_ref count = SPECPDL_INDEX (); 18207 specpdl_ref count = SPECPDL_INDEX ();
18121 specbind (Qinhibit_quit, Qt); 18208 specbind (Qinhibit_quit, Qt);
18122 run_hook_with_args_2 (Qwindow_scroll_functions, window, 18209 safe_run_hooks_2
18123 make_fixnum (CHARPOS (startp))); 18210 (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp)));
18124 unbind_to (count, Qnil); 18211 unbind_to (count, Qnil);
18125 SET_TEXT_POS_FROM_MARKER (startp, w->start); 18212 SET_TEXT_POS_FROM_MARKER (startp, w->start);
18126 /* In case the hook functions switch buffers. */ 18213 /* In case the hook functions switch buffers. */
@@ -19229,6 +19316,16 @@ window_start_acceptable_p (Lisp_Object window, ptrdiff_t startp)
19229 return true; 19316 return true;
19230} 19317}
19231 19318
19319DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p, Slong_line_optimizations_p,
19320 0, 0, 0,
19321 doc: /* Return non-nil if long-line optimizations are in effect in current buffer.
19322See `long-line-threshold' and `large-hscroll-threshold' for what these
19323optimizations mean and when they are in effect. */)
19324 (void)
19325{
19326 return current_buffer->long_line_optimizations_p ? Qt : Qnil;
19327}
19328
19232/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only 19329/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only
19233 selected_window is redisplayed. 19330 selected_window is redisplayed.
19234 19331
@@ -19504,33 +19601,36 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
19504 ptrdiff_t it_charpos; 19601 ptrdiff_t it_charpos;
19505 19602
19506 w->optional_new_start = false; 19603 w->optional_new_start = false;
19507 start_display (&it, w, startp); 19604 if (!w->force_start)
19508 move_it_to (&it, PT, 0, it.last_visible_y, -1, 19605 {
19509 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); 19606 start_display (&it, w, startp);
19510 /* Record IT's position now, since line_bottom_y might change 19607 move_it_to (&it, PT, 0, it.last_visible_y, -1,
19511 that. */ 19608 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
19512 it_charpos = IT_CHARPOS (it); 19609 /* Record IT's position now, since line_bottom_y might
19513 /* Make sure we set the force_start flag only if the cursor row 19610 change that. */
19514 will be fully visible. Otherwise, the code under force_start 19611 it_charpos = IT_CHARPOS (it);
19515 label below will try to move point back into view, which is 19612 /* Make sure we set the force_start flag only if the cursor
19516 not what the code which sets optional_new_start wants. */ 19613 row will be fully visible. Otherwise, the code under
19517 if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y) 19614 force_start label below will try to move point back into
19518 && !w->force_start) 19615 view, which is not what the code which sets
19519 { 19616 optional_new_start wants. */
19520 if (it_charpos == PT) 19617 if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
19521 w->force_start = true; 19618 {
19522 /* IT may overshoot PT if text at PT is invisible. */ 19619 if (it_charpos == PT)
19523 else if (it_charpos > PT && CHARPOS (startp) <= PT) 19620 w->force_start = true;
19524 w->force_start = true; 19621 /* IT may overshoot PT if text at PT is invisible. */
19622 else if (it_charpos > PT && CHARPOS (startp) <= PT)
19623 w->force_start = true;
19525#ifdef GLYPH_DEBUG 19624#ifdef GLYPH_DEBUG
19526 if (w->force_start) 19625 if (w->force_start)
19527 { 19626 {
19528 if (window_frozen_p (w)) 19627 if (window_frozen_p (w))
19529 debug_method_add (w, "set force_start from frozen window start"); 19628 debug_method_add (w, "set force_start from frozen window start");
19530 else 19629 else
19531 debug_method_add (w, "set force_start from optional_new_start"); 19630 debug_method_add (w, "set force_start from optional_new_start");
19532 } 19631 }
19533#endif 19632#endif
19633 }
19534 } 19634 }
19535 } 19635 }
19536 19636
@@ -20256,7 +20356,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
20256 || w->base_line_pos > 0 20356 || w->base_line_pos > 0
20257 /* Column number is displayed and different from the one displayed. */ 20357 /* Column number is displayed and different from the one displayed. */
20258 || (w->column_number_displayed != -1 20358 || (w->column_number_displayed != -1
20259 && !current_buffer->long_line_optimizations_p
20260 && (w->column_number_displayed != current_column ()))) 20359 && (w->column_number_displayed != current_column ())))
20261 /* This means that the window has a mode line. */ 20360 /* This means that the window has a mode line. */
20262 && (window_wants_mode_line (w) 20361 && (window_wants_mode_line (w)
@@ -24496,8 +24595,26 @@ display_line (struct it *it, int cursor_vpos)
24496 it->first_visible_x += x_incr; 24595 it->first_visible_x += x_incr;
24497 it->last_visible_x += x_incr; 24596 it->last_visible_x += x_incr;
24498 } 24597 }
24499 move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x, 24598 if (current_buffer->long_line_optimizations_p
24500 MOVE_TO_POS | MOVE_TO_X); 24599 && it->line_wrap == TRUNCATE
24600 && window_hscroll_limited (it->w, it->f) > large_hscroll_threshold)
24601 {
24602 /* Special optimization for very long and truncated lines
24603 which are hscrolled far to the left: jump directly to the
24604 (approximate) position that is visible, instead of slowly
24605 walking there. */
24606 ptrdiff_t chars_to_skip =
24607 it->first_visible_x / FRAME_COLUMN_WIDTH (it->f);
24608 move_result = fast_move_it_horizontally (it, chars_to_skip);
24609
24610 if (move_result == MOVE_X_REACHED)
24611 it->current_x = it->first_visible_x;
24612 else /* use arbitrary value < first_visible_x */
24613 it->current_x = it->first_visible_x - FRAME_COLUMN_WIDTH (it->f);
24614 }
24615 else
24616 move_result = move_it_in_display_line_to (it, ZV, it->first_visible_x,
24617 MOVE_TO_POS | MOVE_TO_X);
24501 /* If we are under a large hscroll, move_it_in_display_line_to 24618 /* If we are under a large hscroll, move_it_in_display_line_to
24502 could hit the end of the line without reaching 24619 could hit the end of the line without reaching
24503 first_visible_x. Pretend that we did reach it. This is 24620 first_visible_x. Pretend that we did reach it. This is
@@ -27758,17 +27875,6 @@ decode_mode_spec (struct window *w, register int c, int field_width,
27758 even crash emacs.) */ 27875 even crash emacs.) */
27759 if (mode_line_target == MODE_LINE_TITLE) 27876 if (mode_line_target == MODE_LINE_TITLE)
27760 return ""; 27877 return "";
27761 else if (b->long_line_optimizations_p)
27762 {
27763 char *p = decode_mode_spec_buf;
27764 int pad = width - 2;
27765 while (pad-- > 0)
27766 *p++ = ' ';
27767 *p++ = '?';
27768 *p++ = '?';
27769 *p = '\0';
27770 return decode_mode_spec_buf;
27771 }
27772 else 27878 else
27773 { 27879 {
27774 ptrdiff_t col = current_column (); 27880 ptrdiff_t col = current_column ();
@@ -36112,6 +36218,7 @@ be let-bound around code that needs to disable messages temporarily. */);
36112 defsubr (&Sbidi_find_overridden_directionality); 36218 defsubr (&Sbidi_find_overridden_directionality);
36113 defsubr (&Sdisplay__line_is_continued_p); 36219 defsubr (&Sdisplay__line_is_continued_p);
36114 defsubr (&Sget_display_property); 36220 defsubr (&Sget_display_property);
36221 defsubr (&Slong_line_optimizations_p);
36115 36222
36116 DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); 36223 DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
36117 DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); 36224 DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
diff --git a/src/xfns.c b/src/xfns.c
index 2845ecca6a9..6ed93ee42ca 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6851,17 +6851,16 @@ The coordinates X and Y are interpreted in pixels relative to a position
6851#ifdef HAVE_XINPUT2 6851#ifdef HAVE_XINPUT2
6852 int deviceid; 6852 int deviceid;
6853 6853
6854 if (FRAME_DISPLAY_INFO (f)->supports_xi2) 6854 deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device;
6855
6856 if (FRAME_DISPLAY_INFO (f)->supports_xi2
6857 && deviceid != -1)
6855 { 6858 {
6856 XGrabServer (FRAME_X_DISPLAY (f)); 6859 x_catch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
6857 if (XIGetClientPointer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 6860 XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None,
6858 &deviceid)) 6861 FRAME_DISPLAY_INFO (f)->root_window,
6859 { 6862 0, 0, 0, 0, xval, yval);
6860 XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, 6863 x_uncatch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
6861 FRAME_DISPLAY_INFO (f)->root_window,
6862 0, 0, 0, 0, xval, yval);
6863 }
6864 XUngrabServer (FRAME_X_DISPLAY (f));
6865 } 6864 }
6866 else 6865 else
6867#endif 6866#endif
diff --git a/src/xterm.c b/src/xterm.c
index ab43a8ec517..5047f3066be 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1398,6 +1398,15 @@ static int x_dnd_last_tooltip_x, x_dnd_last_tooltip_y;
1398/* Whether or not those values are actually known yet. */ 1398/* Whether or not those values are actually known yet. */
1399static bool x_dnd_last_tooltip_valid; 1399static bool x_dnd_last_tooltip_valid;
1400 1400
1401#ifdef HAVE_XINPUT2
1402/* The master pointer device being used for the drag-and-drop
1403 operation. */
1404static int x_dnd_pointer_device;
1405
1406/* The keyboard device attached to that pointer device. */
1407static int x_dnd_keyboard_device;
1408#endif
1409
1401/* Structure describing a single window that can be the target of 1410/* Structure describing a single window that can be the target of
1402 drag-and-drop operations. */ 1411 drag-and-drop operations. */
1403struct x_client_list_window 1412struct x_client_list_window
@@ -4705,6 +4714,67 @@ x_restore_events_after_dnd (struct frame *f, XWindowAttributes *wa)
4705 dpyinfo->Xatom_XdndTypeList); 4714 dpyinfo->Xatom_XdndTypeList);
4706} 4715}
4707 4716
4717#ifdef HAVE_XINPUT2
4718
4719/* Cancel the current drag-and-drop operation, sending leave messages
4720 to any relevant toplevels. This is called from the event loop when
4721 an event is received telling Emacs to gracefully cancel the
4722 drag-and-drop operation. */
4723
4724static void
4725x_dnd_cancel_dnd_early (void)
4726{
4727 struct frame *f;
4728 xm_drop_start_message dmsg;
4729
4730 eassert (x_dnd_frame && x_dnd_in_progress);
4731
4732 f = x_dnd_frame;
4733
4734 if (x_dnd_last_seen_window != None
4735 && x_dnd_last_protocol_version != -1)
4736 x_dnd_send_leave (x_dnd_frame,
4737 x_dnd_last_seen_window);
4738 else if (x_dnd_last_seen_window != None
4739 && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
4740 && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
4741 && x_dnd_motif_setup_p)
4742 {
4743 dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
4744 XM_DRAG_REASON_DROP_START);
4745 dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
4746 dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time;
4747 dmsg.side_effects
4748 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
4749 x_dnd_wanted_action),
4750 XM_DROP_SITE_VALID, x_dnd_motif_operations,
4751 XM_DROP_ACTION_DROP_CANCEL);
4752 dmsg.x = 0;
4753 dmsg.y = 0;
4754 dmsg.index_atom = x_dnd_motif_atom;
4755 dmsg.source_window = FRAME_X_WINDOW (f);
4756
4757 x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
4758 x_dnd_last_seen_window,
4759 FRAME_DISPLAY_INFO (f)->last_user_time);
4760 xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
4761 x_dnd_last_seen_window, &dmsg);
4762 }
4763
4764 x_dnd_last_seen_window = None;
4765 x_dnd_last_seen_toplevel = None;
4766 x_dnd_in_progress = false;
4767 x_dnd_waiting_for_finish = false;
4768 x_dnd_return_frame_object = NULL;
4769 x_dnd_movement_frame = NULL;
4770 x_dnd_wheel_frame = NULL;
4771 x_dnd_frame = NULL;
4772 x_dnd_action = None;
4773 x_dnd_action_symbol = Qnil;
4774}
4775
4776#endif
4777
4708static void 4778static void
4709x_dnd_cleanup_drag_and_drop (void *frame) 4779x_dnd_cleanup_drag_and_drop (void *frame)
4710{ 4780{
@@ -11909,6 +11979,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
11909 struct x_display_info *event_display; 11979 struct x_display_info *event_display;
11910#endif 11980#endif
11911 unsigned int additional_mask; 11981 unsigned int additional_mask;
11982#ifdef HAVE_XINPUT2
11983 struct xi_device_t *device;
11984#endif
11912 11985
11913 base = SPECPDL_INDEX (); 11986 base = SPECPDL_INDEX ();
11914 11987
@@ -12089,6 +12162,33 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
12089 x_dnd_wheel_frame = NULL; 12162 x_dnd_wheel_frame = NULL;
12090 x_dnd_init_type_lists = false; 12163 x_dnd_init_type_lists = false;
12091 x_dnd_need_send_drop = false; 12164 x_dnd_need_send_drop = false;
12165
12166#ifdef HAVE_XINPUT2
12167
12168 if (FRAME_DISPLAY_INFO (f)->supports_xi2)
12169 {
12170 /* Only accept input from the last master pointer to have interacted
12171 with Emacs. This prevents another pointer device getting our
12172 idea of the button state messed up. */
12173 if (FRAME_DISPLAY_INFO (f)->client_pointer_device != -1)
12174 x_dnd_pointer_device
12175 = FRAME_DISPLAY_INFO (f)->client_pointer_device;
12176 else
12177 /* This returns Bool but cannot actually fail. */
12178 XIGetClientPointer (FRAME_X_DISPLAY (f), None,
12179 &x_dnd_pointer_device);
12180
12181 x_dnd_keyboard_device = -1;
12182
12183 device = xi_device_from_id (FRAME_DISPLAY_INFO (f),
12184 x_dnd_pointer_device);
12185
12186 if (device)
12187 x_dnd_keyboard_device = device->attachment;
12188 }
12189
12190#endif
12191
12092#ifdef HAVE_XKB 12192#ifdef HAVE_XKB
12093 x_dnd_keyboard_state = 0; 12193 x_dnd_keyboard_state = 0;
12094 12194
@@ -12882,6 +12982,13 @@ xi_disable_devices (struct x_display_info *dpyinfo,
12882 { 12982 {
12883 if (to_disable[j] == dpyinfo->devices[i].device_id) 12983 if (to_disable[j] == dpyinfo->devices[i].device_id)
12884 { 12984 {
12985 if (x_dnd_in_progress
12986 /* If the drag-and-drop pointer device is being
12987 disabled, then cancel the drag and drop
12988 operation. */
12989 && to_disable[j] == x_dnd_pointer_device)
12990 x_dnd_cancel_dnd_early ();
12991
12885 /* Free any scroll valuators that might be on this 12992 /* Free any scroll valuators that might be on this
12886 device. */ 12993 device. */
12887#ifdef HAVE_XINPUT2_1 12994#ifdef HAVE_XINPUT2_1
@@ -14164,11 +14271,13 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
14164 ev->window = FRAME_X_WINDOW (f); 14271 ev->window = FRAME_X_WINDOW (f);
14165 ev->format = 32; 14272 ev->format = 32;
14166 14273
14167 /* A 32-bit X client on a 64-bit X server can pass a window pointer 14274 /* A 32-bit X client can pass a window pointer through the X server
14168 as-is. A 64-bit client on a 32-bit X server is in trouble 14275 as-is.
14169 because a pointer does not fit and would be truncated while 14276
14170 passing through the server. So use two slots and hope that X12 14277 A 64-bit client is in trouble because a pointer does not fit in
14171 will resolve such issues someday. */ 14278 the 32 bits given for ClientMessage data and will be truncated by
14279 Xlib. So use two slots and hope that X12 will resolve such
14280 issues someday. */
14172 ev->data.l[0] = iw >> 31 >> 1; 14281 ev->data.l[0] = iw >> 31 >> 1;
14173 ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift; 14282 ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift;
14174 ev->data.l[2] = part; 14283 ev->data.l[2] = part;
@@ -17316,6 +17425,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17316 union buffered_input_event inev; 17425 union buffered_input_event inev;
17317 int count = 0; 17426 int count = 0;
17318 int do_help = 0; 17427 int do_help = 0;
17428#ifdef HAVE_XINPUT2
17429 struct xi_device_t *gen_help_device;
17430 Time gen_help_time;
17431#endif
17319 ptrdiff_t nbytes = 0; 17432 ptrdiff_t nbytes = 0;
17320 struct frame *any, *f = NULL; 17433 struct frame *any, *f = NULL;
17321 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight; 17434 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
@@ -17345,6 +17458,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17345 EVENT_INIT (inev.ie); 17458 EVENT_INIT (inev.ie);
17346 inev.ie.kind = NO_EVENT; 17459 inev.ie.kind = NO_EVENT;
17347 inev.ie.arg = Qnil; 17460 inev.ie.arg = Qnil;
17461#ifdef HAVE_XINPUT2
17462 gen_help_device = NULL;
17463#endif
17348 17464
17349 /* Ignore events coming from various extensions, such as XFIXES and 17465 /* Ignore events coming from various extensions, such as XFIXES and
17350 XKB. */ 17466 XKB. */
@@ -17870,6 +17986,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17870 if (!x_window_to_frame (dpyinfo, event->xselection.requestor)) 17986 if (!x_window_to_frame (dpyinfo, event->xselection.requestor))
17871 goto OTHER; 17987 goto OTHER;
17872#endif /* not USE_X_TOOLKIT and not USE_GTK */ 17988#endif /* not USE_X_TOOLKIT and not USE_GTK */
17989#ifdef HAVE_GTK3
17990 /* GTK 3 apparently chokes on these events since they have no
17991 associated device. (bug#56869, another bug as well that I
17992 can't find) */
17993 *finish = X_EVENT_DROP;
17994#endif
17873 x_handle_selection_notify (&event->xselection); 17995 x_handle_selection_notify (&event->xselection);
17874 break; 17996 break;
17875 17997
@@ -17878,6 +18000,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17878 if (!x_window_to_frame (dpyinfo, event->xselectionclear.window)) 18000 if (!x_window_to_frame (dpyinfo, event->xselectionclear.window))
17879 goto OTHER; 18001 goto OTHER;
17880#endif /* not USE_X_TOOLKIT and not USE_GTK */ 18002#endif /* not USE_X_TOOLKIT and not USE_GTK */
18003#ifdef HAVE_GTK3
18004 *finish = X_EVENT_DROP;
18005#endif
17881 { 18006 {
17882 const XSelectionClearEvent *eventp = &event->xselectionclear; 18007 const XSelectionClearEvent *eventp = &event->xselectionclear;
17883 18008
@@ -17904,6 +18029,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
17904 if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner)) 18029 if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
17905 goto OTHER; 18030 goto OTHER;
17906#endif /* USE_X_TOOLKIT */ 18031#endif /* USE_X_TOOLKIT */
18032#ifdef HAVE_GTK3
18033 *finish = X_EVENT_DROP;
18034#endif
17907 { 18035 {
17908 const XSelectionRequestEvent *eventp = &event->xselectionrequest; 18036 const XSelectionRequestEvent *eventp = &event->xselectionrequest;
17909 18037
@@ -18446,6 +18574,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
18446#endif 18574#endif
18447 18575
18448 if (x_dnd_in_progress 18576 if (x_dnd_in_progress
18577 /* When _NET_WM_CLIENT_LIST stacking is being used, changes
18578 in that property are watched for, and it's not necessary
18579 to update the state in response to ordinary window
18580 substructure events. */
18581 && !x_dnd_use_toplevels
18449 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 18582 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
18450 x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); 18583 x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
18451 18584
@@ -20280,6 +20413,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
20280 20413
20281 case CirculateNotify: 20414 case CirculateNotify:
20282 if (x_dnd_in_progress 20415 if (x_dnd_in_progress
20416 /* When _NET_WM_CLIENT_LIST stacking is being used, changes
20417 in that property are watched for, and it's not necessary
20418 to update the state in response to ordinary window
20419 substructure events. */
20420 && !x_dnd_use_toplevels
20283 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 20421 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
20284 x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); 20422 x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
20285 goto OTHER; 20423 goto OTHER;
@@ -20876,6 +21014,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
20876 operation, don't send an event. We only have 21014 operation, don't send an event. We only have
20877 to set the user time. */ 21015 to set the user time. */
20878 if (x_dnd_in_progress 21016 if (x_dnd_in_progress
21017 /* If another master device moved the
21018 pointer, we should put a wheel event on
21019 the keyboard buffer as usual. It will be
21020 run once the drag-and-drop operation
21021 completes. */
21022 && xev->deviceid == x_dnd_pointer_device
20879 && (command_loop_level + minibuf_level 21023 && (command_loop_level + minibuf_level
20880 <= x_dnd_recursion_depth) 21024 <= x_dnd_recursion_depth)
20881 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 21025 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
@@ -20968,6 +21112,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
20968 `x-dnd-movement-function`. */ 21112 `x-dnd-movement-function`. */
20969 && (command_loop_level + minibuf_level 21113 && (command_loop_level + minibuf_level
20970 <= x_dnd_recursion_depth) 21114 <= x_dnd_recursion_depth)
21115 && xev->deviceid == x_dnd_pointer_device
20971 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 21116 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
20972 { 21117 {
20973 Window target, toplevel; 21118 Window target, toplevel;
@@ -21270,7 +21415,15 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21270 has changed, generate a HELP_EVENT. */ 21415 has changed, generate a HELP_EVENT. */
21271 if (!NILP (help_echo_string) 21416 if (!NILP (help_echo_string)
21272 || !NILP (previous_help_echo_string)) 21417 || !NILP (previous_help_echo_string))
21273 do_help = 1; 21418 {
21419 /* Also allow the focus and client pointer to be
21420 adjusted accordingly, in case a help tooltip is
21421 shown. */
21422 gen_help_device = device;
21423 gen_help_time = xev->time;
21424
21425 do_help = 1;
21426 }
21274 goto XI_OTHER; 21427 goto XI_OTHER;
21275 } 21428 }
21276 21429
@@ -21294,6 +21447,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21294 if (x_dnd_in_progress 21447 if (x_dnd_in_progress
21295 && (command_loop_level + minibuf_level 21448 && (command_loop_level + minibuf_level
21296 <= x_dnd_recursion_depth) 21449 <= x_dnd_recursion_depth)
21450 && xev->deviceid == x_dnd_pointer_device
21297 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) 21451 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
21298 { 21452 {
21299 f = mouse_or_wdesc_frame (dpyinfo, xev->event); 21453 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
@@ -21333,6 +21487,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21333 } 21487 }
21334#endif 21488#endif
21335 21489
21490 if (f && device)
21491 xi_handle_interaction (dpyinfo, f, device,
21492 xev->time);
21493
21336 if (xev->evtype == XI_ButtonPress 21494 if (xev->evtype == XI_ButtonPress
21337 && x_dnd_last_seen_window != None) 21495 && x_dnd_last_seen_window != None)
21338 { 21496 {
@@ -21579,11 +21737,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21579 xev->send_event); 21737 xev->send_event);
21580 21738
21581 source = xi_device_from_id (dpyinfo, xev->sourceid); 21739 source = xi_device_from_id (dpyinfo, xev->sourceid);
21740 device = xi_device_from_id (dpyinfo, xev->deviceid);
21582 21741
21583#ifdef HAVE_XWIDGETS 21742#ifdef HAVE_XWIDGETS
21584 xvw = xwidget_view_from_window (xev->event); 21743 xvw = xwidget_view_from_window (xev->event);
21585 if (xvw) 21744 if (xvw)
21586 { 21745 {
21746 /* If the user interacts with a frame that's focused
21747 on another device, but not the current focus
21748 frame, make it the focus frame. */
21749 if (device)
21750 xi_handle_interaction (dpyinfo, xvw->frame,
21751 device, xev->time);
21752
21587 xwidget_button (xvw, xev->evtype == XI_ButtonPress, 21753 xwidget_button (xvw, xev->evtype == XI_ButtonPress,
21588 lrint (xev->event_x), lrint (xev->event_y), 21754 lrint (xev->event_x), lrint (xev->event_y),
21589 xev->detail, xi_convert_event_state (xev), 21755 xev->detail, xi_convert_event_state (xev),
@@ -21603,8 +21769,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21603 } 21769 }
21604#endif 21770#endif
21605 21771
21606 device = xi_device_from_id (dpyinfo, xev->deviceid);
21607
21608 if (!device) 21772 if (!device)
21609 goto XI_OTHER; 21773 goto XI_OTHER;
21610 21774
@@ -22162,7 +22326,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22162 inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, state); 22326 inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, state);
22163 22327
22164#ifdef XK_F1 22328#ifdef XK_F1
22165 if (x_dnd_in_progress && keysym == XK_F1) 22329 if (x_dnd_in_progress
22330 && xev->deviceid == x_dnd_keyboard_device
22331 && keysym == XK_F1)
22166 { 22332 {
22167 x_dnd_xm_use_help = true; 22333 x_dnd_xm_use_help = true;
22168 goto xi_done_keysym; 22334 goto xi_done_keysym;
@@ -22426,11 +22592,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22426 22592
22427 case XI_HierarchyChanged: 22593 case XI_HierarchyChanged:
22428 { 22594 {
22429 XIHierarchyEvent *hev = (XIHierarchyEvent *) xi_event; 22595 XIHierarchyEvent *hev;
22430 XIDeviceInfo *info; 22596 XIDeviceInfo *info;
22431 int i, ndevices, n_disabled, *disabled; 22597 int i, ndevices, n_disabled, *disabled;
22432 struct xi_device_t *device; 22598 struct xi_device_t *device;
22599 bool any_changed;
22433 22600
22601 any_changed = false;
22602 hev = (XIHierarchyEvent *) xi_event;
22434 disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info); 22603 disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info);
22435 n_disabled = 0; 22604 n_disabled = 0;
22436 22605
@@ -22440,8 +22609,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22440 { 22609 {
22441 /* Handle all disabled devices now, to prevent 22610 /* Handle all disabled devices now, to prevent
22442 things happening out-of-order later. */ 22611 things happening out-of-order later. */
22443 xi_disable_devices (dpyinfo, disabled, n_disabled); 22612
22444 n_disabled = 0; 22613 if (ndevices)
22614 {
22615 xi_disable_devices (dpyinfo, disabled, n_disabled);
22616 n_disabled = 0;
22617
22618 /* This flag really just means that disabled
22619 devices were handled early and should be
22620 used in conjunction with n_disabled. */
22621 any_changed = true;
22622 }
22445 22623
22446 x_catch_errors (dpyinfo->display); 22624 x_catch_errors (dpyinfo->display);
22447 info = XIQueryDevice (dpyinfo->display, hev->info[i].deviceid, 22625 info = XIQueryDevice (dpyinfo->display, hev->info[i].deviceid,
@@ -22492,9 +22670,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22492 event. */ 22670 event. */
22493 xi_disable_devices (dpyinfo, disabled, n_disabled); 22671 xi_disable_devices (dpyinfo, disabled, n_disabled);
22494 22672
22495 /* Now that the device hierarchy has been changed, 22673 /* If the device hierarchy has been changed, recompute
22496 recompute focus. */ 22674 focus. This might seem like a micro-optimization but
22497 xi_handle_focus_change (dpyinfo); 22675 it actually keeps the focus from changing in some
22676 cases where it would be undesierable. */
22677 if (any_changed || n_disabled)
22678 xi_handle_focus_change (dpyinfo);
22498 22679
22499 goto XI_OTHER; 22680 goto XI_OTHER;
22500 } 22681 }
@@ -23182,6 +23363,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
23182 if (do_help > 0) 23363 if (do_help > 0)
23183 { 23364 {
23184 any_help_event_p = true; 23365 any_help_event_p = true;
23366#ifdef HAVE_XINPUT2
23367 if (gen_help_device)
23368 xi_handle_interaction (dpyinfo, f,
23369 gen_help_device,
23370 gen_help_time);
23371#endif
23185 gen_help_event (help_echo_string, frame, help_echo_window, 23372 gen_help_event (help_echo_string, frame, help_echo_window,
23186 help_echo_object, help_echo_pos); 23373 help_echo_object, help_echo_pos);
23187 } 23374 }
@@ -25947,27 +26134,25 @@ x_set_window_size (struct frame *f, bool change_gravity,
25947void 26134void
25948frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) 26135frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
25949{ 26136{
25950 block_input ();
25951#ifdef HAVE_XINPUT2 26137#ifdef HAVE_XINPUT2
25952 int deviceid; 26138 int deviceid;
25953 26139
25954 if (FRAME_DISPLAY_INFO (f)->supports_xi2) 26140 deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device;
26141
26142 if (FRAME_DISPLAY_INFO (f)->supports_xi2
26143 && deviceid != -1)
25955 { 26144 {
25956 if (XIGetClientPointer (FRAME_X_DISPLAY (f), 26145 block_input ();
25957 FRAME_X_WINDOW (f), 26146 x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
25958 &deviceid)) 26147 XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None,
25959 { 26148 FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y);
25960 x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); 26149 x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f));
25961 XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, 26150 unblock_input ();
25962 FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y);
25963 x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f));
25964 }
25965 } 26151 }
25966 else 26152 else
25967#endif 26153#endif
25968 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f), 26154 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
25969 0, 0, 0, 0, pix_x, pix_y); 26155 0, 0, 0, 0, pix_x, pix_y);
25970 unblock_input ();
25971} 26156}
25972 26157
25973/* Raise frame F. */ 26158/* Raise frame F. */
@@ -28955,7 +29140,7 @@ void
28955x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost, 29140x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
28956 Lisp_Object current_owner) 29141 Lisp_Object current_owner)
28957{ 29142{
28958 Lisp_Object tail, frame, new_owner, tem; 29143 Lisp_Object tail, frame, new_owner;
28959 Time timestamp; 29144 Time timestamp;
28960 Window *owners; 29145 Window *owners;
28961 Atom *names; 29146 Atom *names;
@@ -28985,7 +29170,7 @@ x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
28985 29170
28986 FOR_EACH_TAIL_SAFE (tail) 29171 FOR_EACH_TAIL_SAFE (tail)
28987 { 29172 {
28988 tem = XCAR (tail); 29173 Lisp_Object tem = XCAR (tail);
28989 ++nowners; 29174 ++nowners;
28990 29175
28991 /* The selection is really lost (since we cannot find a new 29176 /* The selection is really lost (since we cannot find a new
@@ -29019,7 +29204,7 @@ x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
29019 29204
29020 FOR_EACH_TAIL_SAFE (tail) 29205 FOR_EACH_TAIL_SAFE (tail)
29021 { 29206 {
29022 tem = XCAR (tail); 29207 Lisp_Object tem = XCAR (tail);
29023 29208
29024 /* Now check if we still don't own that selection, which can 29209 /* Now check if we still don't own that selection, which can
29025 happen if another program set itself as the owner. */ 29210 happen if another program set itself as the owner. */
@@ -29039,9 +29224,10 @@ x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
29039 29224
29040 FOR_EACH_TAIL_SAFE (tail) 29225 FOR_EACH_TAIL_SAFE (tail)
29041 { 29226 {
29227 Lisp_Object tem = XCAR (tail);
29228
29042 reply = xcb_get_selection_owner_reply (dpyinfo->xcb_connection, 29229 reply = xcb_get_selection_owner_reply (dpyinfo->xcb_connection,
29043 cookies[nowners++], &error); 29230 cookies[nowners++], &error);
29044
29045 if (reply) 29231 if (reply)
29046 owners[nowners - 1] = reply->owner; 29232 owners[nowners - 1] = reply->owner;
29047 else 29233 else
@@ -29071,7 +29257,7 @@ x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost,
29071 29257
29072 FOR_EACH_TAIL_SAFE (tail) 29258 FOR_EACH_TAIL_SAFE (tail)
29073 { 29259 {
29074 tem = XCAR (tail); 29260 Lisp_Object tem = XCAR (tail);
29075 29261
29076 /* If the selection isn't owned by us anymore, note that the 29262 /* If the selection isn't owned by us anymore, note that the
29077 selection was lost. */ 29263 selection was lost. */