diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 1 | ||||
| -rw-r--r-- | src/buffer.c | 21 | ||||
| -rw-r--r-- | src/eval.c | 59 | ||||
| -rw-r--r-- | src/ftcrfont.c | 6 | ||||
| -rw-r--r-- | src/indent.c | 60 | ||||
| -rw-r--r-- | src/keyboard.c | 25 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/timefns.c | 71 | ||||
| -rw-r--r-- | src/window.c | 9 | ||||
| -rw-r--r-- | src/xdisp.c | 203 | ||||
| -rw-r--r-- | src/xfns.c | 19 | ||||
| -rw-r--r-- | src/xterm.c | 250 |
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). |
| 847 | elnlisp := \ | 847 | elnlisp := \ |
| 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. | |||
| 6442 | There is no reason to change that value except for debugging purposes. */); | 6443 | There 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 | |||
| 6449 | The value should be a positive integer. | ||
| 6450 | |||
| 6451 | Shortcuts in the display code intended to speed up redisplay for long | ||
| 6452 | and truncated lines will automatically be enabled when a line's | ||
| 6453 | horizontal scroll amount is or about to become larger than the value | ||
| 6454 | of this variable. | ||
| 6455 | |||
| 6456 | This variable has effect only in buffers which contain one or more | ||
| 6457 | lines whose length is above `long-line-threshold', which see. | ||
| 6458 | To disable redisplay shortcuts for long truncated line, set this | ||
| 6459 | variable to `most-positive-fixnum'. | ||
| 6460 | |||
| 6461 | There 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! */ |
| 58 | Lisp_Object Vsignaling_function; | 58 | Lisp_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. */ | ||
| 64 | static 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. */ |
| 61 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; | 67 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; |
| 62 | Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; | 68 | Lisp_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. */ | ||
| 1720 | bool 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. | ||
| 4335 | The 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. |
| 4283 | This is nil when the debugger is called under circumstances where it | 4340 | This 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 | |||
| 306 | will have a variable width). | 306 | will have a variable width). |
| 307 | Ignores finite width of frame, which means that this function may return | 307 | Ignores finite width of frame, which means that this function may return |
| 308 | values greater than (frame-width). | 308 | values greater than (frame-width). |
| 309 | In a buffer with very long lines, the value can be zero, because calculating | 309 | In a buffer with very long lines, the value will be an approximation, |
| 310 | the exact number is very expensive. | 310 | because calculating the exact number is very expensive. |
| 311 | Whether the line is visible (if `selective-display' is t) has no effect; | 311 | Whether the line is visible (if `selective-display' is t) has no effect; |
| 312 | however, ^M is treated as end of line when `selective-display' is t. | 312 | however, ^M is treated as end of line when `selective-display' is t. |
| 313 | Text that has an invisible property is considered as having width 0, unless | 313 | Text 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) | |||
| 1841 | static Lisp_Object | 1842 | static Lisp_Object |
| 1842 | safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args) | 1843 | safe_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 | ||
| 1919 | void | ||
| 1920 | safe_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. |
| 12642 | The command loop sets this to nil before each command, | 12654 | The command loop sets this to nil before each command, |
| 12643 | and tests the value when the command returns. | 12655 | and tests the value when the command returns. |
| 12644 | Buffer modification stores t in this variable. */); | 12656 | If an editing command sets this non-nil, deactivate the mark after |
| 12657 | the command returns. | ||
| 12658 | |||
| 12659 | Buffer modifications store t in this variable. | ||
| 12660 | |||
| 12661 | By default, deactivating the mark will save the contents of the region | ||
| 12662 | according 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; | |||
| 4530 | extern Lisp_Object Vsignaling_function; | 4530 | extern Lisp_Object Vsignaling_function; |
| 4531 | extern Lisp_Object inhibit_lisp_code; | 4531 | extern Lisp_Object inhibit_lisp_code; |
| 4532 | extern bool signal_quit_p (Lisp_Object); | 4532 | extern bool signal_quit_p (Lisp_Object); |
| 4533 | extern 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); | |||
| 4831 | extern bool detect_input_pending_run_timers (bool); | 4832 | extern bool detect_input_pending_run_timers (bool); |
| 4832 | extern void safe_run_hooks (Lisp_Object); | 4833 | extern void safe_run_hooks (Lisp_Object); |
| 4833 | extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *); | 4834 | extern void safe_run_hooks_maybe_narrowed (Lisp_Object, struct window *); |
| 4835 | extern void safe_run_hooks_2 (Lisp_Object, Lisp_Object, Lisp_Object); | ||
| 4834 | extern void cmd_error_internal (Lisp_Object, const char *); | 4836 | extern void cmd_error_internal (Lisp_Object, const char *); |
| 4835 | extern Lisp_Object command_loop_2 (Lisp_Object); | 4837 | extern Lisp_Object command_loop_2 (Lisp_Object); |
| 4836 | extern Lisp_Object read_menu_command (void); | 4838 | extern 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 | ||
| 1716 | DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0, | 1731 | DEFUN ("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. |
| 1718 | With optional FORM, convert to that timestamp form. | ||
| 1719 | Truncate the returned value toward minus infinity. | 1733 | Truncate the returned value toward minus infinity. |
| 1720 | 1734 | ||
| 1721 | If FORM is nil (the default), return the same form as `current-time'. | ||
| 1722 | If FORM is a positive integer, return a pair of integers (TICKS . FORM), | 1735 | If FORM is a positive integer, return a pair of integers (TICKS . FORM), |
| 1723 | where TICKS is the number of clock ticks and FORM is the clock frequency | 1736 | where TICKS is the number of clock ticks and FORM is the clock frequency |
| 1724 | in ticks per second. If FORM is t, return (TICKS . PHZ), where | 1737 | in ticks per second. |
| 1725 | PHZ 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', | 1739 | If FORM is t, return (TICKS . PHZ), where PHZ is a suitable clock |
| 1727 | return an integer list (HIGH LOW USEC PSEC), where HIGH has the most | 1740 | frequency in ticks per second. |
| 1728 | significant bits of the seconds, LOW has the least significant 16 | 1741 | |
| 1729 | bits, and USEC and PSEC are the microsecond and picosecond counts. */) | 1742 | If FORM is `integer', return an integer count of seconds. |
| 1743 | |||
| 1744 | If FORM is `list', return an integer list (HIGH LOW USEC PSEC), where | ||
| 1745 | HIGH has the most significant bits of the seconds, LOW has the least | ||
| 1746 | significant 16 bits, and USEC and PSEC are the microsecond and | ||
| 1747 | picosecond counts. | ||
| 1748 | |||
| 1749 | If FORM is nil, the behavior depends on `current-time-list', | ||
| 1750 | but 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) | |||
| 11040 | int | 11040 | int |
| 11041 | partial_line_height (struct it *it_origin) | 11041 | partial_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 | |||
| 11086 | static enum move_it_result | ||
| 11087 | fast_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 | ||
| 11068 | bool | 11122 | bool |
| @@ -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 | ||
| 19319 | DEFUN ("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. | ||
| 19322 | See `long-line-threshold' and `large-hscroll-threshold' for what these | ||
| 19323 | optimizations 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. */ |
| 1399 | static bool x_dnd_last_tooltip_valid; | 1399 | static 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. */ | ||
| 1404 | static int x_dnd_pointer_device; | ||
| 1405 | |||
| 1406 | /* The keyboard device attached to that pointer device. */ | ||
| 1407 | static 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. */ |
| 1403 | struct x_client_list_window | 1412 | struct 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 | |||
| 4724 | static void | ||
| 4725 | x_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 | |||
| 4708 | static void | 4778 | static void |
| 4709 | x_dnd_cleanup_drag_and_drop (void *frame) | 4779 | x_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, | |||
| 25947 | void | 26134 | void |
| 25948 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | 26135 | frame_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 | |||
| 28955 | x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost, | 29140 | x_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. */ |