diff options
| author | Philip Kaludercic | 2022-08-12 16:05:05 +0200 |
|---|---|---|
| committer | Philip Kaludercic | 2022-08-12 16:05:05 +0200 |
| commit | 1823349e6a61b2997b27cdb1ff42c69739693455 (patch) | |
| tree | ed09268f8e57ab9196ff59df000c5f1268e09853 /src | |
| parent | faa7f03b0c5b6d2c51bb185cf5a0f422ba0fb956 (diff) | |
| parent | 829b131e5b3ad3b077be9d31215770b251341c68 (diff) | |
| download | emacs-1823349e6a61b2997b27cdb1ff42c69739693455.tar.gz emacs-1823349e6a61b2997b27cdb1ff42c69739693455.zip | |
Merge remote-tracking branch 'origin/master' into feature/package+vc
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 19 | ||||
| -rw-r--r-- | src/buffer.c | 5 | ||||
| -rw-r--r-- | src/bytecode.c | 4 | ||||
| -rw-r--r-- | src/callint.c | 118 | ||||
| -rw-r--r-- | src/callproc.c | 39 | ||||
| -rw-r--r-- | src/composite.c | 71 | ||||
| -rw-r--r-- | src/dispextern.h | 2 | ||||
| -rw-r--r-- | src/editfns.c | 54 | ||||
| -rw-r--r-- | src/eval.c | 71 | ||||
| -rw-r--r-- | src/frame.c | 6 | ||||
| -rw-r--r-- | src/ftcrfont.c | 8 | ||||
| -rw-r--r-- | src/haiku_support.cc | 33 | ||||
| -rw-r--r-- | src/haiku_support.h | 1 | ||||
| -rw-r--r-- | src/haikufns.c | 18 | ||||
| -rw-r--r-- | src/haikuterm.c | 88 | ||||
| -rw-r--r-- | src/haikuterm.h | 5 | ||||
| -rw-r--r-- | src/indent.c | 10 | ||||
| -rw-r--r-- | src/keyboard.c | 82 | ||||
| -rw-r--r-- | src/lisp.h | 11 | ||||
| -rw-r--r-- | src/lread.c | 160 | ||||
| -rw-r--r-- | src/marker.c | 5 | ||||
| -rw-r--r-- | src/nsfns.m | 1 | ||||
| -rw-r--r-- | src/pgtkfns.c | 1 | ||||
| -rw-r--r-- | src/print.c | 324 | ||||
| -rw-r--r-- | src/process.c | 156 | ||||
| -rw-r--r-- | src/process.h | 5 | ||||
| -rw-r--r-- | src/puresize.h | 2 | ||||
| -rw-r--r-- | src/sysdep.c | 5 | ||||
| -rw-r--r-- | src/timefns.c | 97 | ||||
| -rw-r--r-- | src/w32fns.c | 1 | ||||
| -rw-r--r-- | src/xdisp.c | 88 | ||||
| -rw-r--r-- | src/xfns.c | 87 | ||||
| -rw-r--r-- | src/xmenu.c | 26 | ||||
| -rw-r--r-- | src/xsettings.c | 7 | ||||
| -rw-r--r-- | src/xsettings.h | 2 | ||||
| -rw-r--r-- | src/xterm.c | 1373 | ||||
| -rw-r--r-- | src/xterm.h | 99 |
37 files changed, 2068 insertions, 1016 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 7d15b7afd51..92a8790efdc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -635,30 +635,23 @@ Emacs.pdmp: $(pdmp) | |||
| 635 | endif | 635 | endif |
| 636 | 636 | ||
| 637 | ifeq ($(DUMPING),pdumper) | 637 | ifeq ($(DUMPING),pdumper) |
| 638 | $(pdmp): emacs$(EXEEXT) | 638 | $(pdmp): emacs$(EXEEXT) $(lispsource)/loaddefs.el $(lispsource)/loaddefs.elc |
| 639 | LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ | 639 | LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup --temacs=pdump \ |
| 640 | --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) | 640 | --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) |
| 641 | cp -f $@ $(bootstrap_pdmp) | 641 | cp -f $@ $(bootstrap_pdmp) |
| 642 | endif | 642 | endif |
| 643 | 643 | ||
| 644 | ## We run make-docfile twice because the command line may get too long | ||
| 645 | ## on some systems. Unfortunately, no-one has any idea | ||
| 646 | ## exactly how long the maximum safe command line length is on all the | ||
| 647 | ## various systems that Emacs supports. | ||
| 648 | ## | ||
| 649 | ## $(SOME_MACHINE_OBJECTS) comes before $(obj) because some files may | 644 | ## $(SOME_MACHINE_OBJECTS) comes before $(obj) because some files may |
| 650 | ## or may not be included in $(obj), but they are always included in | 645 | ## or may not be included in $(obj), but they are always included in |
| 651 | ## $(SOME_MACHINE_OBJECTS). Since a file is processed when it is mentioned | 646 | ## $(SOME_MACHINE_OBJECTS). Since a file is processed when it is mentioned |
| 652 | ## for the first time, this prevents any variation between configurations | 647 | ## for the first time, this prevents any variation between configurations |
| 653 | ## in the contents of the DOC file. | 648 | ## in the contents of the DOC file. |
| 654 | ## | 649 | ## |
| 655 | $(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) $(lispsource)/loaddefs.el | 650 | $(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) |
| 656 | $(AM_V_GEN)$(MKDIR_P) $(etc) | 651 | $(AM_V_GEN)$(MKDIR_P) $(etc) |
| 657 | $(AM_V_at)rm -f $(etc)/DOC | 652 | $(AM_V_at)rm -f $(etc)/DOC |
| 658 | $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \ | 653 | $(AM_V_at)$(libsrc)/make-docfile -d $(srcdir) \ |
| 659 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC | 654 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC |
| 660 | $(AM_V_at)$(libsrc)/make-docfile -a $(etc)/DOC -d $(lispsource) \ | ||
| 661 | loaddefs.el | ||
| 662 | 655 | ||
| 663 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ | 656 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ |
| 664 | $(lib)/libgnu.a | 657 | $(lib)/libgnu.a |
| @@ -888,13 +881,7 @@ elnlisp := $(addprefix ${lispsource}/,${elnlisp}) $(lisp:.elc=.eln) | |||
| 888 | fi | 881 | fi |
| 889 | endif | 882 | endif |
| 890 | 883 | ||
| 891 | ## VCSWITNESS points to the file that holds info about the current checkout. | 884 | $(lispsource)/loaddefs.el: | bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) |
| 892 | ## We use it as a heuristic to decide when to rebuild loaddefs.el. | ||
| 893 | ## If empty it is ignored; the parent makefile can set it to some other value. | ||
| 894 | VCSWITNESS = | ||
| 895 | |||
| 896 | $(lispsource)/loaddefs.el: $(VCSWITNESS) | \ | ||
| 897 | bootstrap-emacs$(EXEEXT) $(bootstrap_pdmp) | ||
| 898 | $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)" | 885 | $(MAKE) -C ../lisp autoloads EMACS="$(bootstrap_exe)" |
| 899 | 886 | ||
| 900 | ## Dump an Emacs executable named bootstrap-emacs containing the | 887 | ## Dump an Emacs executable named bootstrap-emacs containing the |
diff --git a/src/buffer.c b/src/buffer.c index a07194aef72..e5601af5051 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -6431,12 +6431,15 @@ will run for `clone-indirect-buffer' calls as well. */); | |||
| 6431 | 6431 | ||
| 6432 | DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold, | 6432 | DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold, |
| 6433 | doc: /* Line length above which to use redisplay shortcuts. | 6433 | doc: /* Line length above which to use redisplay shortcuts. |
| 6434 | |||
| 6434 | The value should be a positive integer or nil. | 6435 | The value should be a positive integer or nil. |
| 6435 | If the value is an integer, shortcuts in the display code intended | 6436 | If the value is an integer, shortcuts in the display code intended |
| 6436 | to speed up redisplay for long lines will automatically be enabled | 6437 | to speed up redisplay for long lines will automatically be enabled |
| 6437 | in buffers which contain one or more lines whose length is above | 6438 | in buffers which contain one or more lines whose length is above |
| 6438 | this threshold. | 6439 | this threshold. |
| 6439 | If nil, these display shortcuts will always remain disabled. */); | 6440 | If nil, these display shortcuts will always remain disabled. |
| 6441 | |||
| 6442 | There is no reason to change that value except for debugging purposes. */); | ||
| 6440 | XSETFASTINT (Vlong_line_threshold, 10000); | 6443 | XSETFASTINT (Vlong_line_threshold, 10000); |
| 6441 | 6444 | ||
| 6442 | defsubr (&Sbuffer_live_p); | 6445 | defsubr (&Sbuffer_live_p); |
diff --git a/src/bytecode.c b/src/bytecode.c index 2b1eccdc518..d75767bb0c5 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -1480,8 +1480,8 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template, | |||
| 1480 | 1480 | ||
| 1481 | CASE (Bnarrow_to_region): | 1481 | CASE (Bnarrow_to_region): |
| 1482 | { | 1482 | { |
| 1483 | Lisp_Object v2 = POP, v1 = POP; | 1483 | Lisp_Object v1 = POP; |
| 1484 | TOP = Fnarrow_to_region (TOP, v1, v2); | 1484 | TOP = Fnarrow_to_region (TOP, v1); |
| 1485 | NEXT; | 1485 | NEXT; |
| 1486 | } | 1486 | } |
| 1487 | 1487 | ||
diff --git a/src/callint.c b/src/callint.c index ffa3b231eb5..c974967459c 100644 --- a/src/callint.c +++ b/src/callint.c | |||
| @@ -161,73 +161,33 @@ check_mark (bool for_region) | |||
| 161 | xsignal0 (Qmark_inactive); | 161 | xsignal0 (Qmark_inactive); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /* If the list of args INPUT was produced with an explicit call to | 164 | /* If FUNCTION has an `interactive-args' spec, replace relevant |
| 165 | `list', look for elements that were computed with | 165 | elements in VALUES with those forms instead. |
| 166 | (region-beginning) or (region-end), and put those expressions into | ||
| 167 | VALUES instead of the present values. | ||
| 168 | 166 | ||
| 169 | This function doesn't return a value because it modifies elements | 167 | This function doesn't return a value because it modifies elements |
| 170 | of VALUES to do its job. */ | 168 | of VALUES to do its job. */ |
| 171 | 169 | ||
| 172 | static void | 170 | static void |
| 173 | fix_command (Lisp_Object input, Lisp_Object function, Lisp_Object values) | 171 | fix_command (Lisp_Object function, Lisp_Object values) |
| 174 | { | 172 | { |
| 175 | /* FIXME: Instead of this ugly hack, we should provide a way for an | 173 | /* Quick exit if there's no values to alter. */ |
| 176 | interactive spec to return an expression/function that will re-build the | 174 | if (!CONSP (values)) |
| 177 | args without user intervention. */ | 175 | return; |
| 178 | if (CONSP (input)) | 176 | |
| 177 | Lisp_Object reps = Fget (function, Qinteractive_args); | ||
| 178 | |||
| 179 | if (CONSP (reps)) | ||
| 179 | { | 180 | { |
| 180 | Lisp_Object car; | 181 | int i = 0; |
| 182 | Lisp_Object vals = values; | ||
| 181 | 183 | ||
| 182 | car = XCAR (input); | 184 | while (!NILP (vals)) |
| 183 | /* Skip through certain special forms. */ | ||
| 184 | while (EQ (car, Qlet) || EQ (car, Qletx) | ||
| 185 | || EQ (car, Qsave_excursion) | ||
| 186 | || EQ (car, Qprogn)) | ||
| 187 | { | 185 | { |
| 188 | while (CONSP (XCDR (input))) | 186 | Lisp_Object rep = Fassq (make_fixnum (i), reps); |
| 189 | input = XCDR (input); | 187 | if (!NILP (rep)) |
| 190 | input = XCAR (input); | 188 | Fsetcar (vals, XCDR (rep)); |
| 191 | if (!CONSP (input)) | 189 | vals = XCDR (vals); |
| 192 | break; | 190 | ++i; |
| 193 | car = XCAR (input); | ||
| 194 | } | ||
| 195 | if (EQ (car, Qlist)) | ||
| 196 | { | ||
| 197 | Lisp_Object intail, valtail; | ||
| 198 | for (intail = Fcdr (input), valtail = values; | ||
| 199 | CONSP (valtail); | ||
| 200 | intail = Fcdr (intail), valtail = XCDR (valtail)) | ||
| 201 | { | ||
| 202 | Lisp_Object elt; | ||
| 203 | elt = Fcar (intail); | ||
| 204 | if (CONSP (elt)) | ||
| 205 | { | ||
| 206 | Lisp_Object presflag, carelt; | ||
| 207 | carelt = XCAR (elt); | ||
| 208 | /* If it is (if X Y), look at Y. */ | ||
| 209 | if (EQ (carelt, Qif) | ||
| 210 | && NILP (Fnthcdr (make_fixnum (3), elt))) | ||
| 211 | elt = Fnth (make_fixnum (2), elt); | ||
| 212 | /* If it is (when ... Y), look at Y. */ | ||
| 213 | else if (EQ (carelt, Qwhen)) | ||
| 214 | { | ||
| 215 | while (CONSP (XCDR (elt))) | ||
| 216 | elt = XCDR (elt); | ||
| 217 | elt = Fcar (elt); | ||
| 218 | } | ||
| 219 | |||
| 220 | /* If the function call we're looking at | ||
| 221 | is a special preserved one, copy the | ||
| 222 | whole expression for this argument. */ | ||
| 223 | if (CONSP (elt)) | ||
| 224 | { | ||
| 225 | presflag = Fmemq (Fcar (elt), preserved_fns); | ||
| 226 | if (!NILP (presflag)) | ||
| 227 | Fsetcar (valtail, Fcar (intail)); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | 191 | } |
| 232 | } | 192 | } |
| 233 | 193 | ||
| @@ -235,31 +195,28 @@ fix_command (Lisp_Object input, Lisp_Object function, Lisp_Object values) | |||
| 235 | optional, remove them from the list. This makes navigating the | 195 | optional, remove them from the list. This makes navigating the |
| 236 | history less confusing, since it doesn't contain a lot of | 196 | history less confusing, since it doesn't contain a lot of |
| 237 | parameters that aren't used. */ | 197 | parameters that aren't used. */ |
| 238 | if (CONSP (values)) | 198 | Lisp_Object arity = Ffunc_arity (function); |
| 199 | /* We don't want to do this simplification if we have an &rest | ||
| 200 | function, because (cl-defun foo (a &optional (b 'zot)) ..) | ||
| 201 | etc. */ | ||
| 202 | if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity))) | ||
| 239 | { | 203 | { |
| 240 | Lisp_Object arity = Ffunc_arity (function); | 204 | Lisp_Object final = Qnil; |
| 241 | /* We don't want to do this simplification if we have an &rest | 205 | ptrdiff_t final_i = 0, i = 0; |
| 242 | function, because (cl-defun foo (a &optional (b 'zot)) ..) | 206 | for (Lisp_Object tail = values; |
| 243 | etc. */ | 207 | CONSP (tail); |
| 244 | if (FIXNUMP (XCAR (arity)) && FIXNUMP (XCDR (arity))) | 208 | tail = XCDR (tail), ++i) |
| 245 | { | 209 | { |
| 246 | Lisp_Object final = Qnil; | 210 | if (!NILP (XCAR (tail))) |
| 247 | ptrdiff_t final_i = 0, i = 0; | ||
| 248 | for (Lisp_Object tail = values; | ||
| 249 | CONSP (tail); | ||
| 250 | tail = XCDR (tail), ++i) | ||
| 251 | { | 211 | { |
| 252 | if (!NILP (XCAR (tail))) | 212 | final = tail; |
| 253 | { | 213 | final_i = i; |
| 254 | final = tail; | ||
| 255 | final_i = i; | ||
| 256 | } | ||
| 257 | } | 214 | } |
| 258 | |||
| 259 | /* Chop the trailing optional values. */ | ||
| 260 | if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1) | ||
| 261 | XSETCDR (final, Qnil); | ||
| 262 | } | 215 | } |
| 216 | |||
| 217 | /* Chop the trailing optional values. */ | ||
| 218 | if (final_i > 0 && final_i >= XFIXNUM (XCAR (arity)) - 1) | ||
| 219 | XSETCDR (final, Qnil); | ||
| 263 | } | 220 | } |
| 264 | } | 221 | } |
| 265 | 222 | ||
| @@ -360,7 +317,6 @@ invoke it (via an `interactive' spec that contains, for instance, an | |||
| 360 | { | 317 | { |
| 361 | Lisp_Object funval = Findirect_function (function, Qt); | 318 | Lisp_Object funval = Findirect_function (function, Qt); |
| 362 | uintmax_t events = num_input_events; | 319 | uintmax_t events = num_input_events; |
| 363 | Lisp_Object input = specs; | ||
| 364 | /* Compute the arg values using the user's expression. */ | 320 | /* Compute the arg values using the user's expression. */ |
| 365 | specs = Feval (specs, | 321 | specs = Feval (specs, |
| 366 | CONSP (funval) && EQ (Qclosure, XCAR (funval)) | 322 | CONSP (funval) && EQ (Qclosure, XCAR (funval)) |
| @@ -371,7 +327,7 @@ invoke it (via an `interactive' spec that contains, for instance, an | |||
| 371 | Make a copy of the list of values, for the command history, | 327 | Make a copy of the list of values, for the command history, |
| 372 | and turn them into things we can eval. */ | 328 | and turn them into things we can eval. */ |
| 373 | Lisp_Object values = quotify_args (Fcopy_sequence (specs)); | 329 | Lisp_Object values = quotify_args (Fcopy_sequence (specs)); |
| 374 | fix_command (input, function, values); | 330 | fix_command (function, values); |
| 375 | call4 (intern ("add-to-history"), intern ("command-history"), | 331 | call4 (intern ("add-to-history"), intern ("command-history"), |
| 376 | Fcons (function, values), Qnil, Qt); | 332 | Fcons (function, values), Qnil, Qt); |
| 377 | } | 333 | } |
| @@ -950,4 +906,6 @@ use `event-start', `event-end', and `event-click-count'. */); | |||
| 950 | defsubr (&Scall_interactively); | 906 | defsubr (&Scall_interactively); |
| 951 | defsubr (&Sfuncall_interactively); | 907 | defsubr (&Sfuncall_interactively); |
| 952 | defsubr (&Sprefix_numeric_value); | 908 | defsubr (&Sprefix_numeric_value); |
| 909 | |||
| 910 | DEFSYM (Qinteractive_args, "interactive-args"); | ||
| 953 | } | 911 | } |
diff --git a/src/callproc.c b/src/callproc.c index dd162f36a6c..e8e4c48b5be 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -650,7 +650,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, | |||
| 650 | 650 | ||
| 651 | child_errno | 651 | child_errno |
| 652 | = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env, | 652 | = emacs_spawn (&pid, filefd, fd_output, fd_error, new_argv, env, |
| 653 | SSDATA (current_dir), NULL, &oldset); | 653 | SSDATA (current_dir), NULL, false, false, &oldset); |
| 654 | eassert ((child_errno == 0) == (0 < pid)); | 654 | eassert ((child_errno == 0) == (0 < pid)); |
| 655 | 655 | ||
| 656 | if (pid > 0) | 656 | if (pid > 0) |
| @@ -1412,14 +1412,15 @@ emacs_posix_spawn_init_attributes (posix_spawnattr_t *attributes, | |||
| 1412 | int | 1412 | int |
| 1413 | emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | 1413 | emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, |
| 1414 | char **argv, char **envp, const char *cwd, | 1414 | char **argv, char **envp, const char *cwd, |
| 1415 | const char *pty, const sigset_t *oldset) | 1415 | const char *pty_name, bool pty_in, bool pty_out, |
| 1416 | const sigset_t *oldset) | ||
| 1416 | { | 1417 | { |
| 1417 | #if USABLE_POSIX_SPAWN | 1418 | #if USABLE_POSIX_SPAWN |
| 1418 | /* Prefer the simpler `posix_spawn' if available. `posix_spawn' | 1419 | /* Prefer the simpler `posix_spawn' if available. `posix_spawn' |
| 1419 | doesn't yet support setting up pseudoterminals, so we fall back | 1420 | doesn't yet support setting up pseudoterminals, so we fall back |
| 1420 | to `vfork' if we're supposed to use a pseudoterminal. */ | 1421 | to `vfork' if we're supposed to use a pseudoterminal. */ |
| 1421 | 1422 | ||
| 1422 | bool use_posix_spawn = pty == NULL; | 1423 | bool use_posix_spawn = pty_name == NULL; |
| 1423 | 1424 | ||
| 1424 | posix_spawn_file_actions_t actions; | 1425 | posix_spawn_file_actions_t actions; |
| 1425 | posix_spawnattr_t attributes; | 1426 | posix_spawnattr_t attributes; |
| @@ -1473,7 +1474,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1473 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 1474 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| 1474 | pid_t *volatile newpid_volatile = newpid; | 1475 | pid_t *volatile newpid_volatile = newpid; |
| 1475 | const char *volatile cwd_volatile = cwd; | 1476 | const char *volatile cwd_volatile = cwd; |
| 1476 | const char *volatile pty_volatile = pty; | 1477 | const char *volatile ptyname_volatile = pty_name; |
| 1478 | bool volatile ptyin_volatile = pty_in; | ||
| 1479 | bool volatile ptyout_volatile = pty_out; | ||
| 1477 | char **volatile argv_volatile = argv; | 1480 | char **volatile argv_volatile = argv; |
| 1478 | int volatile stdin_volatile = std_in; | 1481 | int volatile stdin_volatile = std_in; |
| 1479 | int volatile stdout_volatile = std_out; | 1482 | int volatile stdout_volatile = std_out; |
| @@ -1485,7 +1488,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1485 | /* Darwin doesn't let us run setsid after a vfork, so use fork when | 1488 | /* Darwin doesn't let us run setsid after a vfork, so use fork when |
| 1486 | necessary. Below, we reset SIGCHLD handling after a vfork, as | 1489 | necessary. Below, we reset SIGCHLD handling after a vfork, as |
| 1487 | apparently macOS can mistakenly deliver SIGCHLD to the child. */ | 1490 | apparently macOS can mistakenly deliver SIGCHLD to the child. */ |
| 1488 | if (pty != NULL) | 1491 | if (pty_in || pty_out) |
| 1489 | pid = fork (); | 1492 | pid = fork (); |
| 1490 | else | 1493 | else |
| 1491 | pid = VFORK (); | 1494 | pid = VFORK (); |
| @@ -1495,7 +1498,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1495 | 1498 | ||
| 1496 | newpid = newpid_volatile; | 1499 | newpid = newpid_volatile; |
| 1497 | cwd = cwd_volatile; | 1500 | cwd = cwd_volatile; |
| 1498 | pty = pty_volatile; | 1501 | pty_name = ptyname_volatile; |
| 1502 | pty_in = ptyin_volatile; | ||
| 1503 | pty_out = ptyout_volatile; | ||
| 1499 | argv = argv_volatile; | 1504 | argv = argv_volatile; |
| 1500 | std_in = stdin_volatile; | 1505 | std_in = stdin_volatile; |
| 1501 | std_out = stdout_volatile; | 1506 | std_out = stdout_volatile; |
| @@ -1506,13 +1511,12 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1506 | if (pid == 0) | 1511 | if (pid == 0) |
| 1507 | #endif /* not WINDOWSNT */ | 1512 | #endif /* not WINDOWSNT */ |
| 1508 | { | 1513 | { |
| 1509 | bool pty_flag = pty != NULL; | ||
| 1510 | /* Make the pty be the controlling terminal of the process. */ | 1514 | /* Make the pty be the controlling terminal of the process. */ |
| 1511 | #ifdef HAVE_PTYS | 1515 | #ifdef HAVE_PTYS |
| 1512 | dissociate_controlling_tty (); | 1516 | dissociate_controlling_tty (); |
| 1513 | 1517 | ||
| 1514 | /* Make the pty's terminal the controlling terminal. */ | 1518 | /* Make the pty's terminal the controlling terminal. */ |
| 1515 | if (pty_flag && std_in >= 0) | 1519 | if (pty_in && std_in >= 0) |
| 1516 | { | 1520 | { |
| 1517 | #ifdef TIOCSCTTY | 1521 | #ifdef TIOCSCTTY |
| 1518 | /* We ignore the return value | 1522 | /* We ignore the return value |
| @@ -1521,7 +1525,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1521 | #endif | 1525 | #endif |
| 1522 | } | 1526 | } |
| 1523 | #if defined (LDISC1) | 1527 | #if defined (LDISC1) |
| 1524 | if (pty_flag && std_in >= 0) | 1528 | if (pty_in && std_in >= 0) |
| 1525 | { | 1529 | { |
| 1526 | struct termios t; | 1530 | struct termios t; |
| 1527 | tcgetattr (std_in, &t); | 1531 | tcgetattr (std_in, &t); |
| @@ -1531,7 +1535,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1531 | } | 1535 | } |
| 1532 | #else | 1536 | #else |
| 1533 | #if defined (NTTYDISC) && defined (TIOCSETD) | 1537 | #if defined (NTTYDISC) && defined (TIOCSETD) |
| 1534 | if (pty_flag && std_in >= 0) | 1538 | if (pty_in && std_in >= 0) |
| 1535 | { | 1539 | { |
| 1536 | /* Use new line discipline. */ | 1540 | /* Use new line discipline. */ |
| 1537 | int ldisc = NTTYDISC; | 1541 | int ldisc = NTTYDISC; |
| @@ -1548,18 +1552,21 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1548 | both TIOCSCTTY is defined. */ | 1552 | both TIOCSCTTY is defined. */ |
| 1549 | /* Now close the pty (if we had it open) and reopen it. | 1553 | /* Now close the pty (if we had it open) and reopen it. |
| 1550 | This makes the pty the controlling terminal of the subprocess. */ | 1554 | This makes the pty the controlling terminal of the subprocess. */ |
| 1551 | if (pty_flag) | 1555 | if (pty_name) |
| 1552 | { | 1556 | { |
| 1553 | 1557 | ||
| 1554 | /* I wonder if emacs_close (emacs_open (pty, ...)) | 1558 | /* I wonder if emacs_close (emacs_open (pty, ...)) |
| 1555 | would work? */ | 1559 | would work? */ |
| 1556 | if (std_in >= 0) | 1560 | if (pty_in && std_in >= 0) |
| 1557 | emacs_close (std_in); | 1561 | emacs_close (std_in); |
| 1558 | std_out = std_in = emacs_open_noquit (pty, O_RDWR, 0); | 1562 | int ptyfd = emacs_open_noquit (pty_name, O_RDWR, 0); |
| 1559 | 1563 | if (pty_in) | |
| 1564 | std_in = ptyfd; | ||
| 1565 | if (pty_out) | ||
| 1566 | std_out = ptyfd; | ||
| 1560 | if (std_in < 0) | 1567 | if (std_in < 0) |
| 1561 | { | 1568 | { |
| 1562 | emacs_perror (pty); | 1569 | emacs_perror (pty_name); |
| 1563 | _exit (EXIT_CANCELED); | 1570 | _exit (EXIT_CANCELED); |
| 1564 | } | 1571 | } |
| 1565 | 1572 | ||
| @@ -1599,7 +1606,7 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1599 | /* Stop blocking SIGCHLD in the child. */ | 1606 | /* Stop blocking SIGCHLD in the child. */ |
| 1600 | unblock_child_signal (oldset); | 1607 | unblock_child_signal (oldset); |
| 1601 | 1608 | ||
| 1602 | if (pty_flag) | 1609 | if (pty_out) |
| 1603 | child_setup_tty (std_out); | 1610 | child_setup_tty (std_out); |
| 1604 | #endif | 1611 | #endif |
| 1605 | 1612 | ||
diff --git a/src/composite.c b/src/composite.c index 0f90b92a785..22422cca090 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -24,6 +24,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 24 | 24 | ||
| 25 | #include <config.h> | 25 | #include <config.h> |
| 26 | 26 | ||
| 27 | #include <stdlib.h> /* for qsort */ | ||
| 28 | |||
| 27 | #include "lisp.h" | 29 | #include "lisp.h" |
| 28 | #include "character.h" | 30 | #include "character.h" |
| 29 | #include "composite.h" | 31 | #include "composite.h" |
| @@ -1021,7 +1023,11 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos, | |||
| 1021 | /* But we don't know where to stop the searching. */ | 1023 | /* But we don't know where to stop the searching. */ |
| 1022 | endpos = NILP (string) ? BEGV - 1 : -1; | 1024 | endpos = NILP (string) ? BEGV - 1 : -1; |
| 1023 | /* Usually we don't reach ENDPOS because we stop searching | 1025 | /* Usually we don't reach ENDPOS because we stop searching |
| 1024 | at an uncomposable character (NL, LRE, etc). */ | 1026 | at an uncomposable character (NL, LRE, etc). In buffers |
| 1027 | with long lines, however, NL might be far away, so | ||
| 1028 | pretend that the buffer is smaller. */ | ||
| 1029 | if (current_buffer->long_line_optimizations_p) | ||
| 1030 | endpos = get_closer_narrowed_begv (cmp_it->parent_it->w, charpos); | ||
| 1025 | } | 1031 | } |
| 1026 | } | 1032 | } |
| 1027 | cmp_it->id = -1; | 1033 | cmp_it->id = -1; |
| @@ -1580,7 +1586,6 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, | |||
| 1580 | Lisp_Object window; | 1586 | Lisp_Object window; |
| 1581 | struct window *w; | 1587 | struct window *w; |
| 1582 | bool need_adjustment = 0; | 1588 | bool need_adjustment = 0; |
| 1583 | ptrdiff_t narrowed_begv; | ||
| 1584 | 1589 | ||
| 1585 | window = Fget_buffer_window (Fcurrent_buffer (), Qnil); | 1590 | window = Fget_buffer_window (Fcurrent_buffer (), Qnil); |
| 1586 | if (NILP (window)) | 1591 | if (NILP (window)) |
| @@ -1597,11 +1602,14 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim, | |||
| 1597 | } | 1602 | } |
| 1598 | else | 1603 | else |
| 1599 | head = backlim; | 1604 | head = backlim; |
| 1600 | /* In buffers with very long lines, this function becomes very | 1605 | if (current_buffer->long_line_optimizations_p) |
| 1601 | slow. Pretend that the buffer is narrowed to make it fast. */ | 1606 | { |
| 1602 | narrowed_begv = get_narrowed_begv (w, window_point (w)); | 1607 | /* In buffers with very long lines, this function becomes very |
| 1603 | if (narrowed_begv && pos > narrowed_begv) | 1608 | slow. Pretend that the buffer is narrowed to make it fast. */ |
| 1604 | head = narrowed_begv; | 1609 | ptrdiff_t begv = get_closer_narrowed_begv (w, window_point (w)); |
| 1610 | if (pos > begv) | ||
| 1611 | head = begv; | ||
| 1612 | } | ||
| 1605 | tail = ZV; | 1613 | tail = ZV; |
| 1606 | stop = GPT; | 1614 | stop = GPT; |
| 1607 | cur.pos_byte = CHAR_TO_BYTE (cur.pos); | 1615 | cur.pos_byte = CHAR_TO_BYTE (cur.pos); |
| @@ -2048,6 +2056,54 @@ See `find-composition' for more details. */) | |||
| 2048 | return Fcons (make_fixnum (start), Fcons (make_fixnum (end), tail)); | 2056 | return Fcons (make_fixnum (start), Fcons (make_fixnum (end), tail)); |
| 2049 | } | 2057 | } |
| 2050 | 2058 | ||
| 2059 | static int | ||
| 2060 | compare_composition_rules (const void *r1, const void *r2) | ||
| 2061 | { | ||
| 2062 | Lisp_Object vec1 = *(Lisp_Object *)r1, vec2 = *(Lisp_Object *)r2; | ||
| 2063 | |||
| 2064 | return XFIXNAT (AREF (vec2, 1)) - XFIXNAT (AREF (vec1, 1)); | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | DEFUN ("composition-sort-rules", Fcomposition_sort_rules, | ||
| 2068 | Scomposition_sort_rules, 1, 1, 0, | ||
| 2069 | doc: /* Sort composition RULES by their LOOKBACK parameter. | ||
| 2070 | |||
| 2071 | If RULES include just one rule, return RULES. | ||
| 2072 | Otherwise, return a new list of rules where all the rules are | ||
| 2073 | arranged in decreasing order of the LOOKBACK parameter of the | ||
| 2074 | rules (the second element of the rule's vector). This is required | ||
| 2075 | when combining composition rules from different sources, because | ||
| 2076 | of the way buffer text is examined for matching one of the rules. */) | ||
| 2077 | (Lisp_Object rules) | ||
| 2078 | { | ||
| 2079 | ptrdiff_t nrules; | ||
| 2080 | USE_SAFE_ALLOCA; | ||
| 2081 | |||
| 2082 | CHECK_LIST (rules); | ||
| 2083 | nrules = list_length (rules); | ||
| 2084 | if (nrules > 1) | ||
| 2085 | { | ||
| 2086 | ptrdiff_t i; | ||
| 2087 | Lisp_Object *sortvec; | ||
| 2088 | |||
| 2089 | SAFE_NALLOCA (sortvec, 1, nrules); | ||
| 2090 | for (i = 0; i < nrules; i++) | ||
| 2091 | { | ||
| 2092 | Lisp_Object elt = XCAR (rules); | ||
| 2093 | if (VECTORP (elt) && ASIZE (elt) == 3 && FIXNATP (AREF (elt, 1))) | ||
| 2094 | sortvec[i] = elt; | ||
| 2095 | else | ||
| 2096 | error ("Invalid composition rule in RULES argument"); | ||
| 2097 | rules = XCDR (rules); | ||
| 2098 | } | ||
| 2099 | qsort (sortvec, nrules, sizeof (Lisp_Object), compare_composition_rules); | ||
| 2100 | rules = Flist (nrules, sortvec); | ||
| 2101 | SAFE_FREE (); | ||
| 2102 | } | ||
| 2103 | |||
| 2104 | return rules; | ||
| 2105 | } | ||
| 2106 | |||
| 2051 | 2107 | ||
| 2052 | void | 2108 | void |
| 2053 | syms_of_composite (void) | 2109 | syms_of_composite (void) |
| @@ -2179,4 +2235,5 @@ This list is auto-generated, you should not need to modify it. */); | |||
| 2179 | defsubr (&Sfind_composition_internal); | 2235 | defsubr (&Sfind_composition_internal); |
| 2180 | defsubr (&Scomposition_get_gstring); | 2236 | defsubr (&Scomposition_get_gstring); |
| 2181 | defsubr (&Sclear_composition_cache); | 2237 | defsubr (&Sclear_composition_cache); |
| 2238 | defsubr (&Scomposition_sort_rules); | ||
| 2182 | } | 2239 | } |
diff --git a/src/dispextern.h b/src/dispextern.h index 037e02ff58f..12ba927261f 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -2287,6 +2287,8 @@ struct composition_it | |||
| 2287 | reverse order, and thus the grapheme clusters must be rendered | 2287 | reverse order, and thus the grapheme clusters must be rendered |
| 2288 | from the last to the first. */ | 2288 | from the last to the first. */ |
| 2289 | bool reversed_p; | 2289 | bool reversed_p; |
| 2290 | /* Parent iterator. */ | ||
| 2291 | struct it *parent_it; | ||
| 2290 | 2292 | ||
| 2291 | /** The following members contain information about the current | 2293 | /** The following members contain information about the current |
| 2292 | grapheme cluster. */ | 2294 | grapheme cluster. */ |
diff --git a/src/editfns.c b/src/editfns.c index 79af27d24da..07f5c0bbef7 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -2660,9 +2660,11 @@ DEFUN ("widen", Fwiden, Swiden, 0, 0, "", | |||
| 2660 | doc: /* Remove restrictions (narrowing) from current buffer. | 2660 | doc: /* Remove restrictions (narrowing) from current buffer. |
| 2661 | This allows the buffer's full text to be seen and edited. | 2661 | This allows the buffer's full text to be seen and edited. |
| 2662 | 2662 | ||
| 2663 | When called from Lisp inside a body form in which `narrow-to-region' | 2663 | Note that, when the current buffer contains one or more lines whose |
| 2664 | was called with an optional argument LOCK non-nil, this function does | 2664 | length is above `long-line-threshold', Emacs may decide to leave, for |
| 2665 | not produce any effect. */) | 2665 | performance reasons, the accessible portion of the buffer unchanged |
| 2666 | after this function is called from low-level hooks, such as | ||
| 2667 | `jit-lock-functions' or `post-command-hook'. */) | ||
| 2666 | (void) | 2668 | (void) |
| 2667 | { | 2669 | { |
| 2668 | if (! NILP (Vrestrictions_locked)) | 2670 | if (! NILP (Vrestrictions_locked)) |
| @@ -2689,22 +2691,11 @@ unwind_locked_zv (Lisp_Object point_max) | |||
| 2689 | SET_BUF_ZV (current_buffer, XFIXNUM (point_max)); | 2691 | SET_BUF_ZV (current_buffer, XFIXNUM (point_max)); |
| 2690 | } | 2692 | } |
| 2691 | 2693 | ||
| 2692 | DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 3, "r", | 2694 | /* Internal function for Fnarrow_to_region, meant to be used with a |
| 2693 | doc: /* Restrict editing in this buffer to the current region. | 2695 | third argument 'true', in which case it should be followed by "specbind |
| 2694 | The rest of the text becomes temporarily invisible and untouchable | 2696 | (Qrestrictions_locked, Qt)". */ |
| 2695 | but is not deleted; if you save the buffer in a file, the invisible | 2697 | Lisp_Object |
| 2696 | text is included in the file. \\[widen] makes all visible again. | 2698 | narrow_to_region_internal (Lisp_Object start, Lisp_Object end, bool lock) |
| 2697 | See also `save-restriction'. | ||
| 2698 | |||
| 2699 | When calling from Lisp, pass two arguments START and END: | ||
| 2700 | positions (integers or markers) bounding the text that should | ||
| 2701 | remain visible. | ||
| 2702 | |||
| 2703 | When called from Lisp with the optional argument LOCK non-nil, | ||
| 2704 | calls to `widen', or to `narrow-to-region' with an optional | ||
| 2705 | argument LOCK nil, do not produce any effect until the end of | ||
| 2706 | the current body form. */) | ||
| 2707 | (Lisp_Object start, Lisp_Object end, Lisp_Object lock) | ||
| 2708 | { | 2699 | { |
| 2709 | EMACS_INT s = fix_position (start), e = fix_position (end); | 2700 | EMACS_INT s = fix_position (start), e = fix_position (end); |
| 2710 | 2701 | ||
| @@ -2713,7 +2704,7 @@ the current body form. */) | |||
| 2713 | EMACS_INT tem = s; s = e; e = tem; | 2704 | EMACS_INT tem = s; s = e; e = tem; |
| 2714 | } | 2705 | } |
| 2715 | 2706 | ||
| 2716 | if (! NILP (lock)) | 2707 | if (lock) |
| 2717 | { | 2708 | { |
| 2718 | if (!(BEGV <= s && s <= e && e <= ZV)) | 2709 | if (!(BEGV <= s && s <= e && e <= ZV)) |
| 2719 | args_out_of_range (start, end); | 2710 | args_out_of_range (start, end); |
| @@ -2727,8 +2718,6 @@ the current body form. */) | |||
| 2727 | 2718 | ||
| 2728 | SET_BUF_BEGV (current_buffer, s); | 2719 | SET_BUF_BEGV (current_buffer, s); |
| 2729 | SET_BUF_ZV (current_buffer, e); | 2720 | SET_BUF_ZV (current_buffer, e); |
| 2730 | |||
| 2731 | specbind (Qrestrictions_locked, Qt); | ||
| 2732 | } | 2721 | } |
| 2733 | else | 2722 | else |
| 2734 | { | 2723 | { |
| @@ -2754,6 +2743,27 @@ the current body form. */) | |||
| 2754 | return Qnil; | 2743 | return Qnil; |
| 2755 | } | 2744 | } |
| 2756 | 2745 | ||
| 2746 | DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r", | ||
| 2747 | doc: /* Restrict editing in this buffer to the current region. | ||
| 2748 | The rest of the text becomes temporarily invisible and untouchable | ||
| 2749 | but is not deleted; if you save the buffer in a file, the invisible | ||
| 2750 | text is included in the file. \\[widen] makes all visible again. | ||
| 2751 | See also `save-restriction'. | ||
| 2752 | |||
| 2753 | When calling from Lisp, pass two arguments START and END: | ||
| 2754 | positions (integers or markers) bounding the text that should | ||
| 2755 | remain visible. | ||
| 2756 | |||
| 2757 | Note that, when the current buffer contains one or more lines whose | ||
| 2758 | length is above `long-line-threshold', Emacs may decide to leave, for | ||
| 2759 | performance reasons, the accessible portion of the buffer unchanged | ||
| 2760 | after this function is called from low-level hooks, such as | ||
| 2761 | `jit-lock-functions' or `post-command-hook'. */) | ||
| 2762 | (Lisp_Object start, Lisp_Object end) | ||
| 2763 | { | ||
| 2764 | return narrow_to_region_internal (start, end, false); | ||
| 2765 | } | ||
| 2766 | |||
| 2757 | Lisp_Object | 2767 | Lisp_Object |
| 2758 | save_restriction_save (void) | 2768 | save_restriction_save (void) |
| 2759 | { | 2769 | { |
diff --git a/src/eval.c b/src/eval.c index 141d2546f08..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); |
| @@ -593,16 +601,19 @@ The return value is BASE-VARIABLE. */) | |||
| 593 | 601 | ||
| 594 | if (SYMBOL_CONSTANT_P (new_alias)) | 602 | if (SYMBOL_CONSTANT_P (new_alias)) |
| 595 | /* Making it an alias effectively changes its value. */ | 603 | /* Making it an alias effectively changes its value. */ |
| 596 | error ("Cannot make a constant an alias"); | 604 | error ("Cannot make a constant an alias: %s", |
| 605 | SDATA (SYMBOL_NAME (new_alias))); | ||
| 597 | 606 | ||
| 598 | sym = XSYMBOL (new_alias); | 607 | sym = XSYMBOL (new_alias); |
| 599 | 608 | ||
| 600 | switch (sym->u.s.redirect) | 609 | switch (sym->u.s.redirect) |
| 601 | { | 610 | { |
| 602 | case SYMBOL_FORWARDED: | 611 | case SYMBOL_FORWARDED: |
| 603 | error ("Cannot make an internal variable an alias"); | 612 | error ("Cannot make a built-in variable an alias: %s", |
| 613 | SDATA (SYMBOL_NAME (new_alias))); | ||
| 604 | case SYMBOL_LOCALIZED: | 614 | case SYMBOL_LOCALIZED: |
| 605 | error ("Don't know how to make a localized variable an alias"); | 615 | error ("Don't know how to make a buffer-local variable an alias: %s", |
| 616 | SDATA (SYMBOL_NAME (new_alias))); | ||
| 606 | case SYMBOL_PLAINVAL: | 617 | case SYMBOL_PLAINVAL: |
| 607 | case SYMBOL_VARALIAS: | 618 | case SYMBOL_VARALIAS: |
| 608 | break; | 619 | break; |
| @@ -633,7 +644,8 @@ The return value is BASE-VARIABLE. */) | |||
| 633 | for (p = specpdl_ptr; p > specpdl; ) | 644 | for (p = specpdl_ptr; p > specpdl; ) |
| 634 | if ((--p)->kind >= SPECPDL_LET | 645 | if ((--p)->kind >= SPECPDL_LET |
| 635 | && (EQ (new_alias, specpdl_symbol (p)))) | 646 | && (EQ (new_alias, specpdl_symbol (p)))) |
| 636 | error ("Don't know how to make a let-bound variable an alias"); | 647 | error ("Don't know how to make a let-bound variable an alias: %s", |
| 648 | SDATA (SYMBOL_NAME (new_alias))); | ||
| 637 | } | 649 | } |
| 638 | 650 | ||
| 639 | if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) | 651 | if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) |
| @@ -1552,12 +1564,16 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1552 | ptrdiff_t nargs, | 1564 | ptrdiff_t nargs, |
| 1553 | Lisp_Object *args)) | 1565 | Lisp_Object *args)) |
| 1554 | { | 1566 | { |
| 1567 | struct handler *old_deep = redisplay_deep_handler; | ||
| 1555 | 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; | ||
| 1556 | if (sys_setjmp (c->jmp)) | 1571 | if (sys_setjmp (c->jmp)) |
| 1557 | { | 1572 | { |
| 1558 | Lisp_Object val = handlerlist->val; | 1573 | Lisp_Object val = handlerlist->val; |
| 1559 | clobbered_eassert (handlerlist == c); | 1574 | clobbered_eassert (handlerlist == c); |
| 1560 | handlerlist = handlerlist->next; | 1575 | handlerlist = handlerlist->next; |
| 1576 | redisplay_deep_handler = old_deep; | ||
| 1561 | return hfun (val, nargs, args); | 1577 | return hfun (val, nargs, args); |
| 1562 | } | 1578 | } |
| 1563 | else | 1579 | else |
| @@ -1565,6 +1581,7 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1565 | Lisp_Object val = bfun (nargs, args); | 1581 | Lisp_Object val = bfun (nargs, args); |
| 1566 | eassert (handlerlist == c); | 1582 | eassert (handlerlist == c); |
| 1567 | handlerlist = c->next; | 1583 | handlerlist = c->next; |
| 1584 | redisplay_deep_handler = old_deep; | ||
| 1568 | return val; | 1585 | return val; |
| 1569 | } | 1586 | } |
| 1570 | } | 1587 | } |
| @@ -1697,6 +1714,11 @@ quit (void) | |||
| 1697 | return signal_or_quit (Qquit, Qnil, true); | 1714 | return signal_or_quit (Qquit, Qnil, true); |
| 1698 | } | 1715 | } |
| 1699 | 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 | |||
| 1700 | /* 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. |
| 1701 | If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be | 1723 | If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be |
| 1702 | Qquit and DATA should be Qnil, and this function may return. | 1724 | Qquit and DATA should be Qnil, and this function may return. |
| @@ -1812,6 +1834,40 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) | |||
| 1812 | unbind_to (count, Qnil); | 1834 | unbind_to (count, Qnil); |
| 1813 | } | 1835 | } |
| 1814 | 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 | |||
| 1815 | if (!NILP (clause)) | 1871 | if (!NILP (clause)) |
| 1816 | { | 1872 | { |
| 1817 | Lisp_Object unwind_data | 1873 | Lisp_Object unwind_data |
| @@ -4274,6 +4330,11 @@ Does not apply if quit is handled by a `condition-case'. */); | |||
| 4274 | DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call, | 4330 | DEFVAR_BOOL ("debug-on-next-call", debug_on_next_call, |
| 4275 | 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'. */); |
| 4276 | 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 | |||
| 4277 | DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue, | 4338 | DEFVAR_BOOL ("debugger-may-continue", debugger_may_continue, |
| 4278 | doc: /* Non-nil means debugger may continue execution. | 4339 | doc: /* Non-nil means debugger may continue execution. |
| 4279 | 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/frame.c b/src/frame.c index a39e1c4944f..25d71e0769f 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -3916,9 +3916,10 @@ static const struct frame_parm_table frame_parms[] = | |||
| 3916 | {"z-group", SYMBOL_INDEX (Qz_group)}, | 3916 | {"z-group", SYMBOL_INDEX (Qz_group)}, |
| 3917 | {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, | 3917 | {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, |
| 3918 | {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, | 3918 | {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, |
| 3919 | {"alpha-background", SYMBOL_INDEX (Qalpha_background)}, | 3919 | {"alpha-background", SYMBOL_INDEX (Qalpha_background)}, |
| 3920 | {"use-frame-synchronization", SYMBOL_INDEX (Quse_frame_synchronization)}, | ||
| 3920 | #ifdef HAVE_X_WINDOWS | 3921 | #ifdef HAVE_X_WINDOWS |
| 3921 | {"shaded", SYMBOL_INDEX (Qshaded)}, | 3922 | {"shaded", SYMBOL_INDEX (Qshaded)}, |
| 3922 | #endif | 3923 | #endif |
| 3923 | #ifdef NS_IMPL_COCOA | 3924 | #ifdef NS_IMPL_COCOA |
| 3924 | {"ns-appearance", SYMBOL_INDEX (Qns_appearance)}, | 3925 | {"ns-appearance", SYMBOL_INDEX (Qns_appearance)}, |
| @@ -6195,6 +6196,7 @@ syms_of_frame (void) | |||
| 6195 | DEFSYM (Qtop_only, "top-only"); | 6196 | DEFSYM (Qtop_only, "top-only"); |
| 6196 | DEFSYM (Qiconify_top_level, "iconify-top-level"); | 6197 | DEFSYM (Qiconify_top_level, "iconify-top-level"); |
| 6197 | DEFSYM (Qmake_invisible, "make-invisible"); | 6198 | DEFSYM (Qmake_invisible, "make-invisible"); |
| 6199 | DEFSYM (Quse_frame_synchronization, "use-frame-synchronization"); | ||
| 6198 | 6200 | ||
| 6199 | { | 6201 | { |
| 6200 | int i; | 6202 | int i; |
diff --git a/src/ftcrfont.c b/src/ftcrfont.c index 6bb41110d5c..e089f9dea85 100644 --- a/src/ftcrfont.c +++ b/src/ftcrfont.c | |||
| @@ -567,7 +567,7 @@ ftcrfont_draw (struct glyph_string *s, | |||
| 567 | unblock_input (); | 567 | unblock_input (); |
| 568 | return 0; | 568 | return 0; |
| 569 | } | 569 | } |
| 570 | BView_cr_dump_clipping (FRAME_HAIKU_VIEW (f), cr); | 570 | BView_cr_dump_clipping (FRAME_HAIKU_DRAWABLE (f), cr); |
| 571 | #endif | 571 | #endif |
| 572 | 572 | ||
| 573 | if (with_background) | 573 | if (with_background) |
| @@ -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/haiku_support.cc b/src/haiku_support.cc index b7590f68a48..983928442a1 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc | |||
| @@ -1512,6 +1512,8 @@ public: | |||
| 1512 | 1512 | ||
| 1513 | BMessage *wait_for_release_message; | 1513 | BMessage *wait_for_release_message; |
| 1514 | int64 grabbed_buttons; | 1514 | int64 grabbed_buttons; |
| 1515 | BScreen screen; | ||
| 1516 | bool use_frame_synchronization; | ||
| 1515 | 1517 | ||
| 1516 | EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", | 1518 | EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs", |
| 1517 | B_FOLLOW_NONE, B_WILL_DRAW), | 1519 | B_FOLLOW_NONE, B_WILL_DRAW), |
| @@ -1524,7 +1526,8 @@ public: | |||
| 1524 | cr_context (NULL), | 1526 | cr_context (NULL), |
| 1525 | #endif | 1527 | #endif |
| 1526 | wait_for_release_message (NULL), | 1528 | wait_for_release_message (NULL), |
| 1527 | grabbed_buttons (0) | 1529 | grabbed_buttons (0), |
| 1530 | use_frame_synchronization (false) | ||
| 1528 | { | 1531 | { |
| 1529 | 1532 | ||
| 1530 | } | 1533 | } |
| @@ -1547,6 +1550,16 @@ public: | |||
| 1547 | } | 1550 | } |
| 1548 | 1551 | ||
| 1549 | void | 1552 | void |
| 1553 | SetFrameSynchronization (bool sync) | ||
| 1554 | { | ||
| 1555 | if (LockLooper ()) | ||
| 1556 | { | ||
| 1557 | use_frame_synchronization = sync; | ||
| 1558 | UnlockLooper (); | ||
| 1559 | } | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | void | ||
| 1550 | MessageReceived (BMessage *msg) | 1563 | MessageReceived (BMessage *msg) |
| 1551 | { | 1564 | { |
| 1552 | uint32 buttons; | 1565 | uint32 buttons; |
| @@ -1722,14 +1735,14 @@ public: | |||
| 1722 | void | 1735 | void |
| 1723 | FlipBuffers (void) | 1736 | FlipBuffers (void) |
| 1724 | { | 1737 | { |
| 1738 | EmacsWindow *w; | ||
| 1725 | if (!LockLooper ()) | 1739 | if (!LockLooper ()) |
| 1726 | gui_abort ("Failed to lock looper during buffer flip"); | 1740 | gui_abort ("Failed to lock looper during buffer flip"); |
| 1727 | if (!offscreen_draw_view) | 1741 | if (!offscreen_draw_view) |
| 1728 | gui_abort ("Failed to lock offscreen view during buffer flip"); | 1742 | gui_abort ("Failed to lock offscreen view during buffer flip"); |
| 1729 | 1743 | ||
| 1730 | offscreen_draw_view->Sync (); | 1744 | offscreen_draw_view->Sync (); |
| 1731 | 1745 | w = (EmacsWindow *) Window (); | |
| 1732 | EmacsWindow *w = (EmacsWindow *) Window (); | ||
| 1733 | w->shown_flag = 0; | 1746 | w->shown_flag = 0; |
| 1734 | 1747 | ||
| 1735 | if (copy_bitmap && | 1748 | if (copy_bitmap && |
| @@ -1750,6 +1763,11 @@ public: | |||
| 1750 | if (copy_bitmap->InitCheck () != B_OK) | 1763 | if (copy_bitmap->InitCheck () != B_OK) |
| 1751 | gui_abort ("Failed to init copy bitmap during buffer flip"); | 1764 | gui_abort ("Failed to init copy bitmap during buffer flip"); |
| 1752 | 1765 | ||
| 1766 | /* Wait for VBLANK. If responding to the invalidation or buffer | ||
| 1767 | flipping takes longer than the blanking period, we lose. */ | ||
| 1768 | if (use_frame_synchronization) | ||
| 1769 | screen.WaitForRetrace (); | ||
| 1770 | |||
| 1753 | Invalidate (&invalid_region); | 1771 | Invalidate (&invalid_region); |
| 1754 | invalid_region.MakeEmpty (); | 1772 | invalid_region.MakeEmpty (); |
| 1755 | UnlockLooper (); | 1773 | UnlockLooper (); |
| @@ -5474,3 +5492,12 @@ be_clear_grab_view (void) | |||
| 5474 | grab_view_locker.Unlock (); | 5492 | grab_view_locker.Unlock (); |
| 5475 | } | 5493 | } |
| 5476 | } | 5494 | } |
| 5495 | |||
| 5496 | void | ||
| 5497 | be_set_use_frame_synchronization (void *view, bool sync) | ||
| 5498 | { | ||
| 5499 | EmacsView *vw; | ||
| 5500 | |||
| 5501 | vw = (EmacsView *) view; | ||
| 5502 | vw->SetFrameSynchronization (sync); | ||
| 5503 | } | ||
diff --git a/src/haiku_support.h b/src/haiku_support.h index 76fe071f2c9..ca1808556a4 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h | |||
| @@ -728,6 +728,7 @@ extern void be_lock_window (void *); | |||
| 728 | extern void be_unlock_window (void *); | 728 | extern void be_unlock_window (void *); |
| 729 | extern bool be_get_explicit_workarea (int *, int *, int *, int *); | 729 | extern bool be_get_explicit_workarea (int *, int *, int *, int *); |
| 730 | extern void be_clear_grab_view (void); | 730 | extern void be_clear_grab_view (void); |
| 731 | extern void be_set_use_frame_synchronization (void *, bool); | ||
| 731 | #ifdef __cplusplus | 732 | #ifdef __cplusplus |
| 732 | } | 733 | } |
| 733 | 734 | ||
diff --git a/src/haikufns.c b/src/haikufns.c index f3667ac2f9d..aaa4e866228 100644 --- a/src/haikufns.c +++ b/src/haikufns.c | |||
| @@ -949,6 +949,10 @@ haiku_create_frame (Lisp_Object parms) | |||
| 949 | || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) | 949 | || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) |
| 950 | kset_default_minibuffer_frame (kb, frame); | 950 | kset_default_minibuffer_frame (kb, frame); |
| 951 | 951 | ||
| 952 | /* Set whether or not frame synchronization is enabled. */ | ||
| 953 | gui_default_parameter (f, parms, Quse_frame_synchronization, Qt, | ||
| 954 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 955 | |||
| 952 | gui_default_parameter (f, parms, Qz_group, Qnil, | 956 | gui_default_parameter (f, parms, Qz_group, Qnil, |
| 953 | NULL, NULL, RES_TYPE_SYMBOL); | 957 | NULL, NULL, RES_TYPE_SYMBOL); |
| 954 | 958 | ||
| @@ -1501,9 +1505,9 @@ haiku_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval | |||
| 1501 | 1505 | ||
| 1502 | if (FRAME_HAIKU_VIEW (f)) | 1506 | if (FRAME_HAIKU_VIEW (f)) |
| 1503 | { | 1507 | { |
| 1504 | BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0); | 1508 | BView_draw_lock (FRAME_HAIKU_DRAWABLE (f), false, 0, 0, 0, 0); |
| 1505 | BView_SetViewColor (FRAME_HAIKU_VIEW (f), background); | 1509 | BView_SetViewColor (FRAME_HAIKU_DRAWABLE (f), background); |
| 1506 | BView_draw_unlock (FRAME_HAIKU_VIEW (f)); | 1510 | BView_draw_unlock (FRAME_HAIKU_DRAWABLE (f)); |
| 1507 | 1511 | ||
| 1508 | FRAME_OUTPUT_DATA (f)->cursor_fg = background; | 1512 | FRAME_OUTPUT_DATA (f)->cursor_fg = background; |
| 1509 | update_face_from_frame_parameter (f, Qbackground_color, arg); | 1513 | update_face_from_frame_parameter (f, Qbackground_color, arg); |
| @@ -2115,6 +2119,13 @@ haiku_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 2115 | update_face_from_frame_parameter (f, Qmouse_color, arg); | 2119 | update_face_from_frame_parameter (f, Qmouse_color, arg); |
| 2116 | } | 2120 | } |
| 2117 | 2121 | ||
| 2122 | static void | ||
| 2123 | haiku_set_use_frame_synchronization (struct frame *f, Lisp_Object arg, | ||
| 2124 | Lisp_Object oldval) | ||
| 2125 | { | ||
| 2126 | be_set_use_frame_synchronization (FRAME_HAIKU_VIEW (f), !NILP (arg)); | ||
| 2127 | } | ||
| 2128 | |||
| 2118 | 2129 | ||
| 2119 | 2130 | ||
| 2120 | DEFUN ("haiku-set-mouse-absolute-pixel-position", | 2131 | DEFUN ("haiku-set-mouse-absolute-pixel-position", |
| @@ -3128,6 +3139,7 @@ frame_parm_handler haiku_frame_parm_handlers[] = | |||
| 3128 | haiku_set_override_redirect, | 3139 | haiku_set_override_redirect, |
| 3129 | gui_set_no_special_glyphs, | 3140 | gui_set_no_special_glyphs, |
| 3130 | gui_set_alpha_background, | 3141 | gui_set_alpha_background, |
| 3142 | haiku_set_use_frame_synchronization, | ||
| 3131 | }; | 3143 | }; |
| 3132 | 3144 | ||
| 3133 | void | 3145 | void |
diff --git a/src/haikuterm.c b/src/haikuterm.c index f2bee1263d3..c2d4e34ba25 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c | |||
| @@ -163,15 +163,15 @@ haiku_clip_to_string (struct glyph_string *s) | |||
| 163 | /* If n[FOO].width is 0, it means to not draw at all, so set the | 163 | /* If n[FOO].width is 0, it means to not draw at all, so set the |
| 164 | clipping to some impossible value. */ | 164 | clipping to some impossible value. */ |
| 165 | if (r[0].width <= 0) | 165 | if (r[0].width <= 0) |
| 166 | BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), | 166 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), |
| 167 | FRAME_PIXEL_WIDTH (s->f), | 167 | FRAME_PIXEL_WIDTH (s->f), |
| 168 | FRAME_PIXEL_HEIGHT (s->f), | 168 | FRAME_PIXEL_HEIGHT (s->f), |
| 169 | 10, 10); | 169 | 10, 10); |
| 170 | else | 170 | else |
| 171 | { | 171 | { |
| 172 | BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[0].x, | 172 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), r[0].x, |
| 173 | r[0].y, r[0].width, r[0].height); | 173 | r[0].y, r[0].width, r[0].height); |
| 174 | BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), r[0].x, | 174 | BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), r[0].x, |
| 175 | r[0].y, r[0].width, r[0].height); | 175 | r[0].y, r[0].width, r[0].height); |
| 176 | } | 176 | } |
| 177 | } | 177 | } |
| @@ -181,15 +181,15 @@ haiku_clip_to_string (struct glyph_string *s) | |||
| 181 | /* If n[FOO].width is 0, it means to not draw at all, so set the | 181 | /* If n[FOO].width is 0, it means to not draw at all, so set the |
| 182 | clipping to some impossible value. */ | 182 | clipping to some impossible value. */ |
| 183 | if (r[1].width <= 0) | 183 | if (r[1].width <= 0) |
| 184 | BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), | 184 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), |
| 185 | FRAME_PIXEL_WIDTH (s->f), | 185 | FRAME_PIXEL_WIDTH (s->f), |
| 186 | FRAME_PIXEL_HEIGHT (s->f), | 186 | FRAME_PIXEL_HEIGHT (s->f), |
| 187 | 10, 10); | 187 | 10, 10); |
| 188 | else | 188 | else |
| 189 | { | 189 | { |
| 190 | BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), r[1].x, r[1].y, | 190 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), r[1].x, r[1].y, |
| 191 | r[1].width, r[1].height); | 191 | r[1].width, r[1].height); |
| 192 | BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), r[1].x, | 192 | BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), r[1].x, |
| 193 | r[1].y, r[1].width, r[1].height); | 193 | r[1].y, r[1].width, r[1].height); |
| 194 | } | 194 | } |
| 195 | } | 195 | } |
| @@ -198,9 +198,9 @@ haiku_clip_to_string (struct glyph_string *s) | |||
| 198 | static void | 198 | static void |
| 199 | haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst) | 199 | haiku_clip_to_string_exactly (struct glyph_string *s, struct glyph_string *dst) |
| 200 | { | 200 | { |
| 201 | BView_ClipToRect (FRAME_HAIKU_VIEW (s->f), s->x, s->y, | 201 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (s->f), s->x, s->y, |
| 202 | s->width, s->height); | 202 | s->width, s->height); |
| 203 | BView_invalidate_region (FRAME_HAIKU_VIEW (s->f), s->x, | 203 | BView_invalidate_region (FRAME_HAIKU_DRAWABLE (s->f), s->x, |
| 204 | s->y, s->width, s->height); | 204 | s->y, s->width, s->height); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| @@ -246,7 +246,7 @@ static void | |||
| 246 | haiku_clear_frame_area (struct frame *f, int x, int y, | 246 | haiku_clear_frame_area (struct frame *f, int x, int y, |
| 247 | int width, int height) | 247 | int width, int height) |
| 248 | { | 248 | { |
| 249 | void *vw = FRAME_HAIKU_VIEW (f); | 249 | void *vw = FRAME_HAIKU_DRAWABLE (f); |
| 250 | block_input (); | 250 | block_input (); |
| 251 | BView_draw_lock (vw, true, x, y, width, height); | 251 | BView_draw_lock (vw, true, x, y, width, height); |
| 252 | BView_StartClip (vw); | 252 | BView_StartClip (vw); |
| @@ -261,7 +261,7 @@ haiku_clear_frame_area (struct frame *f, int x, int y, | |||
| 261 | static void | 261 | static void |
| 262 | haiku_clear_frame (struct frame *f) | 262 | haiku_clear_frame (struct frame *f) |
| 263 | { | 263 | { |
| 264 | void *view = FRAME_HAIKU_VIEW (f); | 264 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 265 | 265 | ||
| 266 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | 266 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); |
| 267 | 267 | ||
| @@ -596,7 +596,7 @@ haiku_draw_box_rect (struct glyph_string *s, int left_x, int top_y, | |||
| 596 | int right_x, int bottom_y, int hwidth, int vwidth, | 596 | int right_x, int bottom_y, int hwidth, int vwidth, |
| 597 | bool left_p, bool right_p, struct haiku_rect *clip_rect) | 597 | bool left_p, bool right_p, struct haiku_rect *clip_rect) |
| 598 | { | 598 | { |
| 599 | void *view = FRAME_HAIKU_VIEW (s->f); | 599 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 600 | struct face *face = s->face; | 600 | struct face *face = s->face; |
| 601 | 601 | ||
| 602 | BView_SetHighColor (view, face->box_color); | 602 | BView_SetHighColor (view, face->box_color); |
| @@ -660,7 +660,7 @@ haiku_draw_relief_rect (struct glyph_string *s, int left_x, int top_y, | |||
| 660 | uint32_t color_white, color_black; | 660 | uint32_t color_white, color_black; |
| 661 | void *view; | 661 | void *view; |
| 662 | 662 | ||
| 663 | view = FRAME_HAIKU_VIEW (s->f); | 663 | view = FRAME_HAIKU_DRAWABLE (s->f); |
| 664 | haiku_calculate_relief_colors (s, &color_white, &color_black); | 664 | haiku_calculate_relief_colors (s, &color_white, &color_black); |
| 665 | 665 | ||
| 666 | BView_SetHighColor (view, raised_p ? color_white : color_black); | 666 | BView_SetHighColor (view, raised_p ? color_white : color_black); |
| @@ -769,7 +769,7 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x) | |||
| 769 | dy = wave_height - 1; | 769 | dy = wave_height - 1; |
| 770 | y = s->ybase - wave_height + 3; | 770 | y = s->ybase - wave_height + 3; |
| 771 | xmax = x + width; | 771 | xmax = x + width; |
| 772 | view = FRAME_HAIKU_VIEW (s->f); | 772 | view = FRAME_HAIKU_DRAWABLE (s->f); |
| 773 | 773 | ||
| 774 | BView_StartClip (view); | 774 | BView_StartClip (view); |
| 775 | haiku_clip_to_string (s); | 775 | haiku_clip_to_string (s); |
| @@ -811,7 +811,7 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 811 | if (s->hl == DRAW_CURSOR) | 811 | if (s->hl == DRAW_CURSOR) |
| 812 | haiku_merge_cursor_foreground (s, &cursor_color, NULL); | 812 | haiku_merge_cursor_foreground (s, &cursor_color, NULL); |
| 813 | 813 | ||
| 814 | void *view = FRAME_HAIKU_VIEW (s->f); | 814 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 815 | 815 | ||
| 816 | if (face->underline) | 816 | if (face->underline) |
| 817 | { | 817 | { |
| @@ -1013,7 +1013,7 @@ static void | |||
| 1013 | haiku_draw_plain_background (struct glyph_string *s, struct face *face, | 1013 | haiku_draw_plain_background (struct glyph_string *s, struct face *face, |
| 1014 | int x, int y, int width, int height) | 1014 | int x, int y, int width, int height) |
| 1015 | { | 1015 | { |
| 1016 | void *view = FRAME_HAIKU_VIEW (s->f); | 1016 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1017 | unsigned long cursor_color; | 1017 | unsigned long cursor_color; |
| 1018 | 1018 | ||
| 1019 | if (s->hl == DRAW_CURSOR) | 1019 | if (s->hl == DRAW_CURSOR) |
| @@ -1075,7 +1075,7 @@ haiku_draw_stipple_background (struct glyph_string *s, struct face *face, | |||
| 1075 | unsigned long foreground, background; | 1075 | unsigned long foreground, background; |
| 1076 | void *view; | 1076 | void *view; |
| 1077 | 1077 | ||
| 1078 | view = FRAME_HAIKU_VIEW (s->f); | 1078 | view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1079 | rec = haiku_get_bitmap_rec (s->f, s->face->stipple); | 1079 | rec = haiku_get_bitmap_rec (s->f, s->face->stipple); |
| 1080 | 1080 | ||
| 1081 | if (explicit_colors_p) | 1081 | if (explicit_colors_p) |
| @@ -1173,7 +1173,7 @@ haiku_draw_glyph_string_foreground (struct glyph_string *s) | |||
| 1173 | else | 1173 | else |
| 1174 | x = s->x; | 1174 | x = s->x; |
| 1175 | 1175 | ||
| 1176 | void *view = FRAME_HAIKU_VIEW (s->f); | 1176 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1177 | 1177 | ||
| 1178 | if (s->font_not_found_p) | 1178 | if (s->font_not_found_p) |
| 1179 | { | 1179 | { |
| @@ -1289,9 +1289,9 @@ haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | |||
| 1289 | else | 1289 | else |
| 1290 | color = s->face->foreground; | 1290 | color = s->face->foreground; |
| 1291 | 1291 | ||
| 1292 | BView_SetHighColor (FRAME_HAIKU_VIEW (s->f), color); | 1292 | BView_SetHighColor (FRAME_HAIKU_DRAWABLE (s->f), color); |
| 1293 | BView_SetPenSize (FRAME_HAIKU_VIEW (s->f), 1); | 1293 | BView_SetPenSize (FRAME_HAIKU_DRAWABLE (s->f), 1); |
| 1294 | BView_StrokeRectangle (FRAME_HAIKU_VIEW (s->f), | 1294 | BView_StrokeRectangle (FRAME_HAIKU_DRAWABLE (s->f), |
| 1295 | x, s->ybase - glyph->ascent, | 1295 | x, s->ybase - glyph->ascent, |
| 1296 | glyph->pixel_width, | 1296 | glyph->pixel_width, |
| 1297 | glyph->ascent + glyph->descent); | 1297 | glyph->ascent + glyph->descent); |
| @@ -1335,7 +1335,7 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s) | |||
| 1335 | if (s->row->reversed_p) | 1335 | if (s->row->reversed_p) |
| 1336 | x -= width; | 1336 | x -= width; |
| 1337 | 1337 | ||
| 1338 | void *view = FRAME_HAIKU_VIEW (s->f); | 1338 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1339 | unsigned long cursor_color; | 1339 | unsigned long cursor_color; |
| 1340 | 1340 | ||
| 1341 | haiku_merge_cursor_foreground (s, NULL, &cursor_color); | 1341 | haiku_merge_cursor_foreground (s, NULL, &cursor_color); |
| @@ -1401,14 +1401,14 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s) | |||
| 1401 | static void | 1401 | static void |
| 1402 | haiku_start_clip (struct glyph_string *s) | 1402 | haiku_start_clip (struct glyph_string *s) |
| 1403 | { | 1403 | { |
| 1404 | void *view = FRAME_HAIKU_VIEW (s->f); | 1404 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1405 | BView_StartClip (view); | 1405 | BView_StartClip (view); |
| 1406 | } | 1406 | } |
| 1407 | 1407 | ||
| 1408 | static void | 1408 | static void |
| 1409 | haiku_end_clip (struct glyph_string *s) | 1409 | haiku_end_clip (struct glyph_string *s) |
| 1410 | { | 1410 | { |
| 1411 | void *view = FRAME_HAIKU_VIEW (s->f); | 1411 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1412 | BView_EndClip (view); | 1412 | BView_EndClip (view); |
| 1413 | } | 1413 | } |
| 1414 | 1414 | ||
| @@ -1428,7 +1428,7 @@ haiku_clip_to_row (struct window *w, struct glyph_row *row, | |||
| 1428 | width = window_width; | 1428 | width = window_width; |
| 1429 | height = row->visible_height; | 1429 | height = row->visible_height; |
| 1430 | 1430 | ||
| 1431 | BView_ClipToRect (FRAME_HAIKU_VIEW (f), x, y, width, height); | 1431 | BView_ClipToRect (FRAME_HAIKU_DRAWABLE (f), x, y, width, height); |
| 1432 | } | 1432 | } |
| 1433 | 1433 | ||
| 1434 | static void | 1434 | static void |
| @@ -1448,7 +1448,7 @@ haiku_draw_composite_glyph_string_foreground (struct glyph_string *s) | |||
| 1448 | { | 1448 | { |
| 1449 | int i, j, x; | 1449 | int i, j, x; |
| 1450 | struct font *font = s->font; | 1450 | struct font *font = s->font; |
| 1451 | void *view = FRAME_HAIKU_VIEW (s->f); | 1451 | void *view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1452 | struct face *face = s->face; | 1452 | struct face *face = s->face; |
| 1453 | 1453 | ||
| 1454 | /* If first glyph of S has a left box line, start drawing the text | 1454 | /* If first glyph of S has a left box line, start drawing the text |
| @@ -1670,7 +1670,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s) | |||
| 1670 | if (s->slice.y == 0) | 1670 | if (s->slice.y == 0) |
| 1671 | y += box_line_vwidth; | 1671 | y += box_line_vwidth; |
| 1672 | 1672 | ||
| 1673 | view = FRAME_HAIKU_VIEW (s->f); | 1673 | view = FRAME_HAIKU_DRAWABLE (s->f); |
| 1674 | bitmap = s->img->pixmap; | 1674 | bitmap = s->img->pixmap; |
| 1675 | 1675 | ||
| 1676 | s->stippled_p = face->stipple != 0; | 1676 | s->stippled_p = face->stipple != 0; |
| @@ -1803,7 +1803,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s) | |||
| 1803 | static void | 1803 | static void |
| 1804 | haiku_draw_glyph_string (struct glyph_string *s) | 1804 | haiku_draw_glyph_string (struct glyph_string *s) |
| 1805 | { | 1805 | { |
| 1806 | void *view = FRAME_HAIKU_VIEW (s->f);; | 1806 | void *view = FRAME_HAIKU_DRAWABLE (s->f);; |
| 1807 | struct face *face = s->face; | 1807 | struct face *face = s->face; |
| 1808 | 1808 | ||
| 1809 | block_input (); | 1809 | block_input (); |
| @@ -2001,7 +2001,7 @@ haiku_after_update_window_line (struct window *w, | |||
| 2001 | block_input (); | 2001 | block_input (); |
| 2002 | if (face) | 2002 | if (face) |
| 2003 | { | 2003 | { |
| 2004 | void *view = FRAME_HAIKU_VIEW (f); | 2004 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 2005 | BView_draw_lock (view, false, 0, 0, 0, 0); | 2005 | BView_draw_lock (view, false, 0, 0, 0, 0); |
| 2006 | BView_StartClip (view); | 2006 | BView_StartClip (view); |
| 2007 | BView_SetHighColor (view, (face->background_defaulted_p | 2007 | BView_SetHighColor (view, (face->background_defaulted_p |
| @@ -2010,7 +2010,7 @@ haiku_after_update_window_line (struct window *w, | |||
| 2010 | BView_FillRectangle (view, 0, y, width, height); | 2010 | BView_FillRectangle (view, 0, y, width, height); |
| 2011 | BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width, | 2011 | BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width, |
| 2012 | y, width, height); | 2012 | y, width, height); |
| 2013 | BView_invalidate_region (FRAME_HAIKU_VIEW (f), | 2013 | BView_invalidate_region (FRAME_HAIKU_DRAWABLE (f), |
| 2014 | 0, y, width, height); | 2014 | 0, y, width, height); |
| 2015 | BView_invalidate_region (view, FRAME_PIXEL_WIDTH (f) - width, | 2015 | BView_invalidate_region (view, FRAME_PIXEL_WIDTH (f) - width, |
| 2016 | y, width, height); | 2016 | y, width, height); |
| @@ -2075,7 +2075,7 @@ haiku_draw_hollow_cursor (struct window *w, struct glyph_row *row) | |||
| 2075 | void *view; | 2075 | void *view; |
| 2076 | 2076 | ||
| 2077 | f = XFRAME (WINDOW_FRAME (w)); | 2077 | f = XFRAME (WINDOW_FRAME (w)); |
| 2078 | view = FRAME_HAIKU_VIEW (f); | 2078 | view = FRAME_HAIKU_DRAWABLE (f); |
| 2079 | 2079 | ||
| 2080 | /* Get the glyph the cursor is on. If we can't tell because | 2080 | /* Get the glyph the cursor is on. If we can't tell because |
| 2081 | the current matrix is invalid or such, give up. */ | 2081 | the current matrix is invalid or such, give up. */ |
| @@ -2148,7 +2148,7 @@ haiku_draw_bar_cursor (struct window *w, struct glyph_row *row, | |||
| 2148 | } | 2148 | } |
| 2149 | else | 2149 | else |
| 2150 | { | 2150 | { |
| 2151 | view = FRAME_HAIKU_VIEW (f); | 2151 | view = FRAME_HAIKU_DRAWABLE (f); |
| 2152 | face = FACE_FROM_ID (f, cursor_glyph->face_id); | 2152 | face = FACE_FROM_ID (f, cursor_glyph->face_id); |
| 2153 | 2153 | ||
| 2154 | /* If the glyph's background equals the color we normally draw | 2154 | /* If the glyph's background equals the color we normally draw |
| @@ -2334,7 +2334,7 @@ haiku_draw_vertical_window_border (struct window *w, | |||
| 2334 | struct face *face; | 2334 | struct face *face; |
| 2335 | 2335 | ||
| 2336 | face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); | 2336 | face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); |
| 2337 | void *view = FRAME_HAIKU_VIEW (f); | 2337 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 2338 | BView_draw_lock (view, true, x, y_0, 1, y_1); | 2338 | BView_draw_lock (view, true, x, y_0, 1, y_1); |
| 2339 | BView_StartClip (view); | 2339 | BView_StartClip (view); |
| 2340 | if (face) | 2340 | if (face) |
| @@ -2384,7 +2384,7 @@ haiku_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) | |||
| 2384 | unsigned long color_last = (face_last | 2384 | unsigned long color_last = (face_last |
| 2385 | ? face_last->foreground | 2385 | ? face_last->foreground |
| 2386 | : FRAME_FOREGROUND_PIXEL (f)); | 2386 | : FRAME_FOREGROUND_PIXEL (f)); |
| 2387 | void *view = FRAME_HAIKU_VIEW (f); | 2387 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 2388 | 2388 | ||
| 2389 | BView_draw_lock (view, true, x0, y0, x1 - x0 + 1, y1 - y0 + 1); | 2389 | BView_draw_lock (view, true, x0, y0, x1 - x0 + 1, y1 - y0 + 1); |
| 2390 | BView_StartClip (view); | 2390 | BView_StartClip (view); |
| @@ -2554,7 +2554,7 @@ haiku_scroll_bar_create (struct window *w, int left, int top, | |||
| 2554 | void *view; | 2554 | void *view; |
| 2555 | 2555 | ||
| 2556 | f = XFRAME (WINDOW_FRAME (w)); | 2556 | f = XFRAME (WINDOW_FRAME (w)); |
| 2557 | view = FRAME_HAIKU_VIEW (f); | 2557 | view = FRAME_HAIKU_DRAWABLE (f); |
| 2558 | 2558 | ||
| 2559 | block_input (); | 2559 | block_input (); |
| 2560 | bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER); | 2560 | bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER); |
| @@ -2604,7 +2604,7 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p | |||
| 2604 | width = window_width; | 2604 | width = window_width; |
| 2605 | top = WINDOW_SCROLL_BAR_AREA_Y (w); | 2605 | top = WINDOW_SCROLL_BAR_AREA_Y (w); |
| 2606 | height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); | 2606 | height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); |
| 2607 | view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w)); | 2607 | view = FRAME_HAIKU_DRAWABLE (WINDOW_XFRAME (w)); |
| 2608 | 2608 | ||
| 2609 | block_input (); | 2609 | block_input (); |
| 2610 | 2610 | ||
| @@ -2663,7 +2663,7 @@ haiku_set_vertical_scroll_bar (struct window *w, int portion, int whole, int pos | |||
| 2663 | left = WINDOW_SCROLL_BAR_AREA_X (w); | 2663 | left = WINDOW_SCROLL_BAR_AREA_X (w); |
| 2664 | width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); | 2664 | width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); |
| 2665 | 2665 | ||
| 2666 | view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w)); | 2666 | view = FRAME_HAIKU_DRAWABLE (WINDOW_XFRAME (w)); |
| 2667 | 2667 | ||
| 2668 | block_input (); | 2668 | block_input (); |
| 2669 | if (NILP (w->vertical_scroll_bar)) | 2669 | if (NILP (w->vertical_scroll_bar)) |
| @@ -2712,7 +2712,7 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | |||
| 2712 | uint32 col; | 2712 | uint32 col; |
| 2713 | 2713 | ||
| 2714 | f = XFRAME (WINDOW_FRAME (w)); | 2714 | f = XFRAME (WINDOW_FRAME (w)); |
| 2715 | view = FRAME_HAIKU_VIEW (f); | 2715 | view = FRAME_HAIKU_DRAWABLE (f); |
| 2716 | face = p->face; | 2716 | face = p->face; |
| 2717 | 2717 | ||
| 2718 | block_input (); | 2718 | block_input (); |
| @@ -2828,7 +2828,7 @@ static void | |||
| 2828 | haiku_scroll_run (struct window *w, struct run *run) | 2828 | haiku_scroll_run (struct window *w, struct run *run) |
| 2829 | { | 2829 | { |
| 2830 | struct frame *f = XFRAME (w->frame); | 2830 | struct frame *f = XFRAME (w->frame); |
| 2831 | void *view = FRAME_HAIKU_VIEW (f); | 2831 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 2832 | int x, y, width, height, from_y, to_y, bottom_y; | 2832 | int x, y, width, height, from_y, to_y, bottom_y; |
| 2833 | window_box (w, ANY_AREA, &x, &y, &width, &height); | 2833 | window_box (w, ANY_AREA, &x, &y, &width, &height); |
| 2834 | 2834 | ||
| @@ -3211,9 +3211,9 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) | |||
| 3211 | continue; | 3211 | continue; |
| 3212 | } | 3212 | } |
| 3213 | 3213 | ||
| 3214 | BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0); | 3214 | BView_draw_lock (FRAME_HAIKU_DRAWABLE (f), false, 0, 0, 0, 0); |
| 3215 | BView_resize_to (FRAME_HAIKU_VIEW (f), width, height); | 3215 | BView_resize_to (FRAME_HAIKU_DRAWABLE (f), width, height); |
| 3216 | BView_draw_unlock (FRAME_HAIKU_VIEW (f)); | 3216 | BView_draw_unlock (FRAME_HAIKU_DRAWABLE (f)); |
| 3217 | 3217 | ||
| 3218 | if (width != FRAME_PIXEL_WIDTH (f) | 3218 | if (width != FRAME_PIXEL_WIDTH (f) |
| 3219 | || height != FRAME_PIXEL_HEIGHT (f) | 3219 | || height != FRAME_PIXEL_HEIGHT (f) |
| @@ -4126,7 +4126,7 @@ haiku_flash (struct frame *f) | |||
| 4126 | int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f); | 4126 | int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f); |
| 4127 | int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f); | 4127 | int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f); |
| 4128 | int width = flash_right - flash_left; | 4128 | int width = flash_right - flash_left; |
| 4129 | void *view = FRAME_HAIKU_VIEW (f); | 4129 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 4130 | object_wait_info info; | 4130 | object_wait_info info; |
| 4131 | bigtime_t wakeup; | 4131 | bigtime_t wakeup; |
| 4132 | 4132 | ||
| @@ -4454,7 +4454,7 @@ haiku_clear_under_internal_border (struct frame *f) | |||
| 4454 | ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) | 4454 | ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) |
| 4455 | : INTERNAL_BORDER_FACE_ID)); | 4455 | : INTERNAL_BORDER_FACE_ID)); |
| 4456 | struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); | 4456 | struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); |
| 4457 | void *view = FRAME_HAIKU_VIEW (f); | 4457 | void *view = FRAME_HAIKU_DRAWABLE (f); |
| 4458 | 4458 | ||
| 4459 | block_input (); | 4459 | block_input (); |
| 4460 | BView_draw_lock (view, true, 0, 0, FRAME_PIXEL_WIDTH (f), | 4460 | BView_draw_lock (view, true, 0, 0, FRAME_PIXEL_WIDTH (f), |
| @@ -4496,7 +4496,7 @@ haiku_scroll_bar_remove (struct scroll_bar *bar) | |||
| 4496 | struct frame *f; | 4496 | struct frame *f; |
| 4497 | 4497 | ||
| 4498 | f = WINDOW_XFRAME (XWINDOW (bar->window)); | 4498 | f = WINDOW_XFRAME (XWINDOW (bar->window)); |
| 4499 | view = FRAME_HAIKU_VIEW (f); | 4499 | view = FRAME_HAIKU_DRAWABLE (f); |
| 4500 | 4500 | ||
| 4501 | block_input (); | 4501 | block_input (); |
| 4502 | BView_forget_scroll_bar (view, bar->left, bar->top, | 4502 | BView_forget_scroll_bar (view, bar->left, bar->top, |
diff --git a/src/haikuterm.h b/src/haikuterm.h index 02a364f6712..b603c0a482f 100644 --- a/src/haikuterm.h +++ b/src/haikuterm.h | |||
| @@ -275,7 +275,8 @@ struct scroll_bar | |||
| 275 | #define MAKE_FRAME_DIRTY(f) (FRAME_DIRTY_P (f) = 1) | 275 | #define MAKE_FRAME_DIRTY(f) (FRAME_DIRTY_P (f) = 1) |
| 276 | #define FRAME_OUTPUT_DATA(f) ((f)->output_data.haiku) | 276 | #define FRAME_OUTPUT_DATA(f) ((f)->output_data.haiku) |
| 277 | #define FRAME_HAIKU_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window) | 277 | #define FRAME_HAIKU_WINDOW(f) (FRAME_OUTPUT_DATA (f)->window) |
| 278 | #define FRAME_HAIKU_VIEW(f) ((MAKE_FRAME_DIRTY (f)), FRAME_OUTPUT_DATA (f)->view) | 278 | #define FRAME_HAIKU_VIEW(f) (FRAME_OUTPUT_DATA (f)->view) |
| 279 | #define FRAME_HAIKU_DRAWABLE(f) ((MAKE_FRAME_DIRTY (f)), FRAME_HAIKU_VIEW (f)) | ||
| 279 | #define FRAME_HAIKU_MENU_BAR(f) (FRAME_OUTPUT_DATA (f)->menubar) | 280 | #define FRAME_HAIKU_MENU_BAR(f) (FRAME_OUTPUT_DATA (f)->menubar) |
| 280 | #define FRAME_DISPLAY_INFO(f) (FRAME_OUTPUT_DATA (f)->display_info) | 281 | #define FRAME_DISPLAY_INFO(f) (FRAME_OUTPUT_DATA (f)->display_info) |
| 281 | #define FRAME_FONT(f) (FRAME_OUTPUT_DATA (f)->font) | 282 | #define FRAME_FONT(f) (FRAME_OUTPUT_DATA (f)->font) |
| @@ -287,7 +288,7 @@ struct scroll_bar | |||
| 287 | #ifdef USE_BE_CAIRO | 288 | #ifdef USE_BE_CAIRO |
| 288 | #define FRAME_CR_CONTEXT(f) \ | 289 | #define FRAME_CR_CONTEXT(f) \ |
| 289 | (FRAME_HAIKU_VIEW (f) \ | 290 | (FRAME_HAIKU_VIEW (f) \ |
| 290 | ? EmacsView_cairo_context (FRAME_HAIKU_VIEW (f)) \ | 291 | ? EmacsView_cairo_context (FRAME_HAIKU_DRAWABLE (f)) \ |
| 291 | : NULL) | 292 | : NULL) |
| 292 | #endif | 293 | #endif |
| 293 | 294 | ||
diff --git a/src/indent.c b/src/indent.c index fd2e7636656..d2dfaee254e 100644 --- a/src/indent.c +++ b/src/indent.c | |||
| @@ -2345,7 +2345,15 @@ whether or not it is currently displayed in some window. */) | |||
| 2345 | last line that it occupies. */ | 2345 | last line that it occupies. */ |
| 2346 | if (it_start < ZV) | 2346 | if (it_start < ZV) |
| 2347 | { | 2347 | { |
| 2348 | while (IT_CHARPOS (it) <= it_start) | 2348 | if ((it.bidi_it.scan_dir > 0) |
| 2349 | ? IT_CHARPOS (it) < it_start | ||
| 2350 | : IT_CHARPOS (it) > it_start) | ||
| 2351 | { | ||
| 2352 | it.vpos = 0; | ||
| 2353 | it.current_y = 0; | ||
| 2354 | move_it_by_lines (&it, 1); | ||
| 2355 | } | ||
| 2356 | while (IT_CHARPOS (it) == it_start) | ||
| 2349 | { | 2357 | { |
| 2350 | it.vpos = 0; | 2358 | it.vpos = 0; |
| 2351 | it.current_y = 0; | 2359 | it.current_y = 0; |
diff --git a/src/keyboard.c b/src/keyboard.c index 2863058d633..719226caedc 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -1295,7 +1295,8 @@ command_loop_1 (void) | |||
| 1295 | /* Note that the value cell will never directly contain nil | 1295 | /* Note that the value cell will never directly contain nil |
| 1296 | if the symbol is a local variable. */ | 1296 | if the symbol is a local variable. */ |
| 1297 | if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks)) | 1297 | if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks)) |
| 1298 | safe_run_hooks (Qpost_command_hook); | 1298 | safe_run_hooks_maybe_narrowed (Qpost_command_hook, |
| 1299 | XWINDOW (selected_window)); | ||
| 1299 | 1300 | ||
| 1300 | /* If displaying a message, resize the echo area window to fit | 1301 | /* If displaying a message, resize the echo area window to fit |
| 1301 | that message's size exactly. */ | 1302 | that message's size exactly. */ |
| @@ -1330,6 +1331,7 @@ command_loop_1 (void) | |||
| 1330 | display_malloc_warning (); | 1331 | display_malloc_warning (); |
| 1331 | 1332 | ||
| 1332 | Vdeactivate_mark = Qnil; | 1333 | Vdeactivate_mark = Qnil; |
| 1334 | backtrace_yet = false; | ||
| 1333 | 1335 | ||
| 1334 | /* Don't ignore mouse movements for more than a single command | 1336 | /* Don't ignore mouse movements for more than a single command |
| 1335 | 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 |
| @@ -1461,7 +1463,9 @@ command_loop_1 (void) | |||
| 1461 | } | 1463 | } |
| 1462 | Vthis_command = cmd; | 1464 | Vthis_command = cmd; |
| 1463 | Vreal_this_command = cmd; | 1465 | Vreal_this_command = cmd; |
| 1464 | safe_run_hooks (Qpre_command_hook); | 1466 | |
| 1467 | safe_run_hooks_maybe_narrowed (Qpre_command_hook, | ||
| 1468 | XWINDOW (selected_window)); | ||
| 1465 | 1469 | ||
| 1466 | already_adjusted = 0; | 1470 | already_adjusted = 0; |
| 1467 | 1471 | ||
| @@ -1513,7 +1517,8 @@ command_loop_1 (void) | |||
| 1513 | } | 1517 | } |
| 1514 | kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg); | 1518 | kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg); |
| 1515 | 1519 | ||
| 1516 | safe_run_hooks (Qpost_command_hook); | 1520 | safe_run_hooks_maybe_narrowed (Qpost_command_hook, |
| 1521 | XWINDOW (selected_window)); | ||
| 1517 | 1522 | ||
| 1518 | /* If displaying a message, resize the echo area window to fit | 1523 | /* If displaying a message, resize the echo area window to fit |
| 1519 | that message's size exactly. Do this only if the echo area | 1524 | that message's size exactly. Do this only if the echo area |
| @@ -1837,7 +1842,7 @@ safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args) | |||
| 1837 | static Lisp_Object | 1842 | static Lisp_Object |
| 1838 | 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) |
| 1839 | { | 1844 | { |
| 1840 | eassert (nargs == 2); | 1845 | eassert (nargs >= 2 && nargs <= 4); |
| 1841 | AUTO_STRING (format, "Error in %s (%S): %S"); | 1846 | AUTO_STRING (format, "Error in %s (%S): %S"); |
| 1842 | Lisp_Object hook = args[0]; | 1847 | Lisp_Object hook = args[0]; |
| 1843 | Lisp_Object fun = args[1]; | 1848 | Lisp_Object fun = args[1]; |
| @@ -1895,6 +1900,33 @@ safe_run_hooks (Lisp_Object hook) | |||
| 1895 | unbind_to (count, Qnil); | 1900 | unbind_to (count, Qnil); |
| 1896 | } | 1901 | } |
| 1897 | 1902 | ||
| 1903 | void | ||
| 1904 | safe_run_hooks_maybe_narrowed (Lisp_Object hook, struct window *w) | ||
| 1905 | { | ||
| 1906 | specpdl_ref count = SPECPDL_INDEX (); | ||
| 1907 | |||
| 1908 | specbind (Qinhibit_quit, Qt); | ||
| 1909 | |||
| 1910 | if (current_buffer->long_line_optimizations_p) | ||
| 1911 | narrow_to_region_internal (make_fixnum (get_narrowed_begv (w, PT)), | ||
| 1912 | make_fixnum (get_narrowed_zv (w, PT)), | ||
| 1913 | true); | ||
| 1914 | |||
| 1915 | run_hook_with_args (2, ((Lisp_Object []) {hook, hook}), safe_run_hook_funcall); | ||
| 1916 | unbind_to (count, Qnil); | ||
| 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 | |||
| 1898 | 1930 | ||
| 1899 | /* Nonzero means polling for input is temporarily suppressed. */ | 1931 | /* Nonzero means polling for input is temporarily suppressed. */ |
| 1900 | 1932 | ||
| @@ -4622,6 +4654,11 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) | |||
| 4622 | /* If timer is ripe, run it if it hasn't been run. */ | 4654 | /* If timer is ripe, run it if it hasn't been run. */ |
| 4623 | if (ripe) | 4655 | if (ripe) |
| 4624 | { | 4656 | { |
| 4657 | /* If we got here, presumably `decode_timer` has checked | ||
| 4658 | that this timer has not yet been triggered. */ | ||
| 4659 | eassert (NILP (AREF (chosen_timer, 0))); | ||
| 4660 | /* In a production build, where assertions compile to | ||
| 4661 | nothing, we still want to play it safe here. */ | ||
| 4625 | if (NILP (AREF (chosen_timer, 0))) | 4662 | if (NILP (AREF (chosen_timer, 0))) |
| 4626 | { | 4663 | { |
| 4627 | specpdl_ref count = SPECPDL_INDEX (); | 4664 | specpdl_ref count = SPECPDL_INDEX (); |
| @@ -4640,8 +4677,8 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) | |||
| 4640 | 4677 | ||
| 4641 | /* Since we have handled the event, | 4678 | /* Since we have handled the event, |
| 4642 | we don't need to tell the caller to wake up and do it. */ | 4679 | we don't need to tell the caller to wake up and do it. */ |
| 4643 | /* But the caller must still wait for the next timer, so | 4680 | /* But the caller must still wait for the next timer, so |
| 4644 | return 0 to indicate that. */ | 4681 | return 0 to indicate that. */ |
| 4645 | } | 4682 | } |
| 4646 | 4683 | ||
| 4647 | nexttime = make_timespec (0, 0); | 4684 | nexttime = make_timespec (0, 0); |
| @@ -12622,23 +12659,39 @@ Buffer modification stores t in this variable. */); | |||
| 12622 | 12659 | ||
| 12623 | DEFVAR_LISP ("pre-command-hook", Vpre_command_hook, | 12660 | DEFVAR_LISP ("pre-command-hook", Vpre_command_hook, |
| 12624 | doc: /* Normal hook run before each command is executed. | 12661 | doc: /* Normal hook run before each command is executed. |
| 12625 | If an unhandled error happens in running this hook, | 12662 | |
| 12626 | the function in which the error occurred is unconditionally removed, since | 12663 | If an unhandled error happens in running this hook, the function in |
| 12627 | otherwise the error might happen repeatedly and make Emacs nonfunctional. | 12664 | which the error occurred is unconditionally removed, since otherwise |
| 12665 | the error might happen repeatedly and make Emacs nonfunctional. | ||
| 12666 | |||
| 12667 | Note that, when the current buffer contains one or more lines whose | ||
| 12668 | length is above `long-line-threshold', these hook functions are called | ||
| 12669 | with the buffer narrowed to a small portion around point, and the | ||
| 12670 | narrowing is locked (see `narrow-to-region'), so that these hook | ||
| 12671 | functions cannot use `widen' to gain access to other portions of | ||
| 12672 | buffer text. | ||
| 12628 | 12673 | ||
| 12629 | See also `post-command-hook'. */); | 12674 | See also `post-command-hook'. */); |
| 12630 | Vpre_command_hook = Qnil; | 12675 | Vpre_command_hook = Qnil; |
| 12631 | 12676 | ||
| 12632 | DEFVAR_LISP ("post-command-hook", Vpost_command_hook, | 12677 | DEFVAR_LISP ("post-command-hook", Vpost_command_hook, |
| 12633 | doc: /* Normal hook run after each command is executed. | 12678 | doc: /* Normal hook run after each command is executed. |
| 12634 | If an unhandled error happens in running this hook, | 12679 | |
| 12635 | the function in which the error occurred is unconditionally removed, since | 12680 | If an unhandled error happens in running this hook, the function in |
| 12636 | otherwise the error might happen repeatedly and make Emacs nonfunctional. | 12681 | which the error occurred is unconditionally removed, since otherwise |
| 12682 | the error might happen repeatedly and make Emacs nonfunctional. | ||
| 12637 | 12683 | ||
| 12638 | It is a bad idea to use this hook for expensive processing. If | 12684 | It is a bad idea to use this hook for expensive processing. If |
| 12639 | unavoidable, wrap your code in `(while-no-input (redisplay) CODE)' to | 12685 | unavoidable, wrap your code in `(while-no-input (redisplay) CODE)' to |
| 12640 | avoid making Emacs unresponsive while the user types. | 12686 | avoid making Emacs unresponsive while the user types. |
| 12641 | 12687 | ||
| 12688 | Note that, when the current buffer contains one or more lines whose | ||
| 12689 | length is above `long-line-threshold', these hook functions are called | ||
| 12690 | with the buffer narrowed to a small portion around point, and the | ||
| 12691 | narrowing is locked (see `narrow-to-region'), so that these hook | ||
| 12692 | functions cannot use `widen' to gain access to other portions of | ||
| 12693 | buffer text. | ||
| 12694 | |||
| 12642 | See also `pre-command-hook'. */); | 12695 | See also `pre-command-hook'. */); |
| 12643 | Vpost_command_hook = Qnil; | 12696 | Vpost_command_hook = Qnil; |
| 12644 | 12697 | ||
| @@ -12914,7 +12967,10 @@ This variable only has an effect when Transient Mark mode is enabled. | |||
| 12914 | 12967 | ||
| 12915 | If the value is `only', only temporarily active regions (usually made | 12968 | If the value is `only', only temporarily active regions (usually made |
| 12916 | by mouse-dragging or shift-selection) set the window system's primary | 12969 | by mouse-dragging or shift-selection) set the window system's primary |
| 12917 | selection. */); | 12970 | selection. |
| 12971 | |||
| 12972 | If this variable causes the region to be set as the primary selection, | ||
| 12973 | `post-select-region-hook' is then run afterwards. */); | ||
| 12918 | Vselect_active_regions = Qt; | 12974 | Vselect_active_regions = Qt; |
| 12919 | 12975 | ||
| 12920 | DEFVAR_LISP ("saved-region-selection", | 12976 | DEFVAR_LISP ("saved-region-selection", |
diff --git a/src/lisp.h b/src/lisp.h index 8fcc9b6e75a..2f73ba4c617 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3793,10 +3793,10 @@ make_symbol_constant (Lisp_Object sym) | |||
| 3793 | 3793 | ||
| 3794 | /* Buffer-local variable access functions. */ | 3794 | /* Buffer-local variable access functions. */ |
| 3795 | 3795 | ||
| 3796 | INLINE int | 3796 | INLINE bool |
| 3797 | blv_found (struct Lisp_Buffer_Local_Value *blv) | 3797 | blv_found (struct Lisp_Buffer_Local_Value *blv) |
| 3798 | { | 3798 | { |
| 3799 | eassert (blv->found == !EQ (blv->defcell, blv->valcell)); | 3799 | eassert (blv->found == !BASE_EQ (blv->defcell, blv->valcell)); |
| 3800 | return blv->found; | 3800 | return blv->found; |
| 3801 | } | 3801 | } |
| 3802 | 3802 | ||
| @@ -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: |
| @@ -4679,6 +4680,7 @@ extern void save_restriction_restore (Lisp_Object); | |||
| 4679 | extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); | 4680 | extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); |
| 4680 | extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, | 4681 | extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| 4681 | ptrdiff_t, bool); | 4682 | ptrdiff_t, bool); |
| 4683 | extern Lisp_Object narrow_to_region_internal (Lisp_Object, Lisp_Object, bool); | ||
| 4682 | extern void init_editfns (void); | 4684 | extern void init_editfns (void); |
| 4683 | extern void syms_of_editfns (void); | 4685 | extern void syms_of_editfns (void); |
| 4684 | 4686 | ||
| @@ -4829,6 +4831,8 @@ extern bool detect_input_pending (void); | |||
| 4829 | extern bool detect_input_pending_ignore_squeezables (void); | 4831 | extern bool detect_input_pending_ignore_squeezables (void); |
| 4830 | extern bool detect_input_pending_run_timers (bool); | 4832 | extern bool detect_input_pending_run_timers (bool); |
| 4831 | extern void safe_run_hooks (Lisp_Object); | 4833 | extern void safe_run_hooks (Lisp_Object); |
| 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); | ||
| 4832 | extern void cmd_error_internal (Lisp_Object, const char *); | 4836 | extern void cmd_error_internal (Lisp_Object, const char *); |
| 4833 | extern Lisp_Object command_loop_2 (Lisp_Object); | 4837 | extern Lisp_Object command_loop_2 (Lisp_Object); |
| 4834 | extern Lisp_Object read_menu_command (void); | 4838 | extern Lisp_Object read_menu_command (void); |
| @@ -4941,7 +4945,8 @@ extern void setup_process_coding_systems (Lisp_Object); | |||
| 4941 | #endif | 4945 | #endif |
| 4942 | 4946 | ||
| 4943 | extern int emacs_spawn (pid_t *, int, int, int, char **, char **, | 4947 | extern int emacs_spawn (pid_t *, int, int, int, char **, char **, |
| 4944 | const char *, const char *, const sigset_t *); | 4948 | const char *, const char *, bool, bool, |
| 4949 | const sigset_t *); | ||
| 4945 | extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; | 4950 | extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL; |
| 4946 | extern void init_callproc_1 (void); | 4951 | extern void init_callproc_1 (void); |
| 4947 | extern void init_callproc (void); | 4952 | extern void init_callproc (void); |
diff --git a/src/lread.c b/src/lread.c index 0720774db2b..ccccd79cd7c 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -131,25 +131,15 @@ static ptrdiff_t read_from_string_limit; | |||
| 131 | /* Position in object from which characters are being read by `readchar'. */ | 131 | /* Position in object from which characters are being read by `readchar'. */ |
| 132 | static EMACS_INT readchar_offset; | 132 | static EMACS_INT readchar_offset; |
| 133 | 133 | ||
| 134 | /* This contains the last string skipped with #@. */ | 134 | struct saved_string { |
| 135 | static char *saved_doc_string; | 135 | char *string; /* string in allocated buffer */ |
| 136 | /* Length of buffer allocated in saved_doc_string. */ | 136 | ptrdiff_t size; /* allocated size of buffer */ |
| 137 | static ptrdiff_t saved_doc_string_size; | 137 | ptrdiff_t length; /* length of string in buffer */ |
| 138 | /* Length of actual data in saved_doc_string. */ | 138 | file_offset position; /* position in file the string came from */ |
| 139 | static ptrdiff_t saved_doc_string_length; | 139 | }; |
| 140 | /* This is the file position that string came from. */ | 140 | |
| 141 | static file_offset saved_doc_string_position; | 141 | /* The last two strings skipped with #@ (most recent first). */ |
| 142 | 142 | static struct saved_string saved_strings[2]; | |
| 143 | /* This contains the previous string skipped with #@. | ||
| 144 | We copy it from saved_doc_string when a new string | ||
| 145 | is put in saved_doc_string. */ | ||
| 146 | static char *prev_saved_doc_string; | ||
| 147 | /* Length of buffer allocated in prev_saved_doc_string. */ | ||
| 148 | static ptrdiff_t prev_saved_doc_string_size; | ||
| 149 | /* Length of actual data in prev_saved_doc_string. */ | ||
| 150 | static ptrdiff_t prev_saved_doc_string_length; | ||
| 151 | /* This is the file position that string came from. */ | ||
| 152 | static file_offset prev_saved_doc_string_position; | ||
| 153 | 143 | ||
| 154 | /* A list of file names for files being loaded in Fload. Used to | 144 | /* A list of file names for files being loaded in Fload. Used to |
| 155 | check for recursive loads. */ | 145 | check for recursive loads. */ |
| @@ -1605,13 +1595,12 @@ Return t if the file exists and loads successfully. */) | |||
| 1605 | if (!NILP (Ffboundp (Qdo_after_load_evaluation))) | 1595 | if (!NILP (Ffboundp (Qdo_after_load_evaluation))) |
| 1606 | call1 (Qdo_after_load_evaluation, hist_file_name) ; | 1596 | call1 (Qdo_after_load_evaluation, hist_file_name) ; |
| 1607 | 1597 | ||
| 1608 | xfree (saved_doc_string); | 1598 | for (int i = 0; i < ARRAYELTS (saved_strings); i++) |
| 1609 | saved_doc_string = 0; | 1599 | { |
| 1610 | saved_doc_string_size = 0; | 1600 | xfree (saved_strings[i].string); |
| 1611 | 1601 | saved_strings[i].string = NULL; | |
| 1612 | xfree (prev_saved_doc_string); | 1602 | saved_strings[i].size = 0; |
| 1613 | prev_saved_doc_string = 0; | 1603 | } |
| 1614 | prev_saved_doc_string_size = 0; | ||
| 1615 | 1604 | ||
| 1616 | if (!noninteractive && (NILP (nomessage) || force_load_messages)) | 1605 | if (!noninteractive && (NILP (nomessage) || force_load_messages)) |
| 1617 | { | 1606 | { |
| @@ -2261,7 +2250,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2261 | /* Set point and ZV around stuff to be read. */ | 2250 | /* Set point and ZV around stuff to be read. */ |
| 2262 | Fgoto_char (start); | 2251 | Fgoto_char (start); |
| 2263 | if (!NILP (end)) | 2252 | if (!NILP (end)) |
| 2264 | Fnarrow_to_region (make_fixnum (BEGV), end, Qnil); | 2253 | Fnarrow_to_region (make_fixnum (BEGV), end); |
| 2265 | 2254 | ||
| 2266 | /* Just for cleanliness, convert END to a marker | 2255 | /* Just for cleanliness, convert END to a marker |
| 2267 | if it is an integer. */ | 2256 | if it is an integer. */ |
| @@ -3056,7 +3045,6 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], | |||
| 3056 | /* True if we saw an escape sequence specifying | 3045 | /* True if we saw an escape sequence specifying |
| 3057 | a single-byte character. */ | 3046 | a single-byte character. */ |
| 3058 | bool force_singlebyte = false; | 3047 | bool force_singlebyte = false; |
| 3059 | bool cancel = false; | ||
| 3060 | ptrdiff_t nchars = 0; | 3048 | ptrdiff_t nchars = 0; |
| 3061 | 3049 | ||
| 3062 | int ch; | 3050 | int ch; |
| @@ -3085,8 +3073,6 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], | |||
| 3085 | case ' ': | 3073 | case ' ': |
| 3086 | case '\n': | 3074 | case '\n': |
| 3087 | /* `\SPC' and `\LF' generate no characters at all. */ | 3075 | /* `\SPC' and `\LF' generate no characters at all. */ |
| 3088 | if (p == read_buffer) | ||
| 3089 | cancel = true; | ||
| 3090 | continue; | 3076 | continue; |
| 3091 | default: | 3077 | default: |
| 3092 | UNREAD (ch); | 3078 | UNREAD (ch); |
| @@ -3152,15 +3138,6 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], | |||
| 3152 | if (ch < 0) | 3138 | if (ch < 0) |
| 3153 | end_of_file_error (); | 3139 | end_of_file_error (); |
| 3154 | 3140 | ||
| 3155 | /* If purifying, and string starts with \ newline, | ||
| 3156 | return zero instead. This is for doc strings | ||
| 3157 | that we are really going to find in etc/DOC.nn.nn. */ | ||
| 3158 | if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) | ||
| 3159 | { | ||
| 3160 | unbind_to (count, Qnil); | ||
| 3161 | return make_fixnum (0); | ||
| 3162 | } | ||
| 3163 | |||
| 3164 | if (!force_multibyte && force_singlebyte) | 3141 | if (!force_multibyte && force_singlebyte) |
| 3165 | { | 3142 | { |
| 3166 | /* READ_BUFFER contains raw 8-bit bytes and no multibyte | 3143 | /* READ_BUFFER contains raw 8-bit bytes and no multibyte |
| @@ -3457,57 +3434,95 @@ skip_lazy_string (Lisp_Object readcharfun) | |||
| 3457 | record the last string that we skipped, | 3434 | record the last string that we skipped, |
| 3458 | and record where in the file it comes from. */ | 3435 | and record where in the file it comes from. */ |
| 3459 | 3436 | ||
| 3460 | /* But first exchange saved_doc_string | 3437 | /* First exchange the two saved_strings. */ |
| 3461 | with prev_saved_doc_string, so we save two strings. */ | 3438 | verify (ARRAYELTS (saved_strings) == 2); |
| 3462 | { | 3439 | struct saved_string t = saved_strings[0]; |
| 3463 | char *temp = saved_doc_string; | 3440 | saved_strings[0] = saved_strings[1]; |
| 3464 | ptrdiff_t temp_size = saved_doc_string_size; | 3441 | saved_strings[1] = t; |
| 3465 | file_offset temp_pos = saved_doc_string_position; | ||
| 3466 | ptrdiff_t temp_len = saved_doc_string_length; | ||
| 3467 | |||
| 3468 | saved_doc_string = prev_saved_doc_string; | ||
| 3469 | saved_doc_string_size = prev_saved_doc_string_size; | ||
| 3470 | saved_doc_string_position = prev_saved_doc_string_position; | ||
| 3471 | saved_doc_string_length = prev_saved_doc_string_length; | ||
| 3472 | |||
| 3473 | prev_saved_doc_string = temp; | ||
| 3474 | prev_saved_doc_string_size = temp_size; | ||
| 3475 | prev_saved_doc_string_position = temp_pos; | ||
| 3476 | prev_saved_doc_string_length = temp_len; | ||
| 3477 | } | ||
| 3478 | 3442 | ||
| 3479 | enum { extra = 100 }; | 3443 | enum { extra = 100 }; |
| 3480 | if (saved_doc_string_size == 0) | 3444 | struct saved_string *ss = &saved_strings[0]; |
| 3445 | if (ss->size == 0) | ||
| 3481 | { | 3446 | { |
| 3482 | saved_doc_string = xmalloc (nskip + extra); | 3447 | ss->size = nskip + extra; |
| 3483 | saved_doc_string_size = nskip + extra; | 3448 | ss->string = xmalloc (ss->size); |
| 3484 | } | 3449 | } |
| 3485 | if (nskip > saved_doc_string_size) | 3450 | else if (nskip > ss->size) |
| 3486 | { | 3451 | { |
| 3487 | saved_doc_string = xrealloc (saved_doc_string, nskip + extra); | 3452 | ss->size = nskip + extra; |
| 3488 | saved_doc_string_size = nskip + extra; | 3453 | ss->string = xrealloc (ss->string, ss->size); |
| 3489 | } | 3454 | } |
| 3490 | 3455 | ||
| 3491 | FILE *instream = infile->stream; | 3456 | FILE *instream = infile->stream; |
| 3492 | saved_doc_string_position = (file_tell (instream) - infile->lookahead); | 3457 | ss->position = (file_tell (instream) - infile->lookahead); |
| 3493 | 3458 | ||
| 3494 | /* Copy that many bytes into saved_doc_string. */ | 3459 | /* Copy that many bytes into the saved string. */ |
| 3495 | ptrdiff_t i = 0; | 3460 | ptrdiff_t i = 0; |
| 3496 | int c = 0; | 3461 | int c = 0; |
| 3497 | for (int n = min (nskip, infile->lookahead); n > 0; n--) | 3462 | for (int n = min (nskip, infile->lookahead); n > 0; n--) |
| 3498 | saved_doc_string[i++] = c = infile->buf[--infile->lookahead]; | 3463 | ss->string[i++] = c = infile->buf[--infile->lookahead]; |
| 3499 | block_input (); | 3464 | block_input (); |
| 3500 | for (; i < nskip && c >= 0; i++) | 3465 | for (; i < nskip && c >= 0; i++) |
| 3501 | saved_doc_string[i] = c = getc (instream); | 3466 | ss->string[i] = c = getc (instream); |
| 3502 | unblock_input (); | 3467 | unblock_input (); |
| 3503 | 3468 | ||
| 3504 | saved_doc_string_length = i; | 3469 | ss->length = i; |
| 3505 | } | 3470 | } |
| 3506 | else | 3471 | else |
| 3507 | /* Skip that many bytes. */ | 3472 | /* Skip that many bytes. */ |
| 3508 | skip_dyn_bytes (readcharfun, nskip); | 3473 | skip_dyn_bytes (readcharfun, nskip); |
| 3509 | } | 3474 | } |
| 3510 | 3475 | ||
| 3476 | /* Given a lazy-loaded string designator VAL, return the actual string. | ||
| 3477 | VAL is (FILENAME . POS). */ | ||
| 3478 | static Lisp_Object | ||
| 3479 | get_lazy_string (Lisp_Object val) | ||
| 3480 | { | ||
| 3481 | /* Get a doc string from the file we are loading. | ||
| 3482 | If it's in a saved string, get it from there. | ||
| 3483 | |||
| 3484 | Here, we don't know if the string is a bytecode string or a doc | ||
| 3485 | string. As a bytecode string must be unibyte, we always return a | ||
| 3486 | unibyte string. If it is actually a doc string, caller must make | ||
| 3487 | it multibyte. */ | ||
| 3488 | |||
| 3489 | /* We used to emit negative positions for 'user variables' (whose doc | ||
| 3490 | strings started with an asterisk); take the absolute value for | ||
| 3491 | compatibility. */ | ||
| 3492 | EMACS_INT pos = eabs (XFIXNUM (XCDR (val))); | ||
| 3493 | struct saved_string *ss = &saved_strings[0]; | ||
| 3494 | struct saved_string *ssend = ss + ARRAYELTS (saved_strings); | ||
| 3495 | while (ss < ssend | ||
| 3496 | && !(pos >= ss->position && pos < ss->position + ss->length)) | ||
| 3497 | ss++; | ||
| 3498 | if (ss >= ssend) | ||
| 3499 | return get_doc_string (val, 1, 0); | ||
| 3500 | |||
| 3501 | ptrdiff_t start = pos - ss->position; | ||
| 3502 | char *str = ss->string; | ||
| 3503 | ptrdiff_t from = start; | ||
| 3504 | ptrdiff_t to = start; | ||
| 3505 | |||
| 3506 | /* Process quoting with ^A, and find the end of the string, | ||
| 3507 | which is marked with ^_ (037). */ | ||
| 3508 | while (str[from] != 037) | ||
| 3509 | { | ||
| 3510 | int c = str[from++]; | ||
| 3511 | if (c == 1) | ||
| 3512 | { | ||
| 3513 | c = str[from++]; | ||
| 3514 | str[to++] = (c == 1 ? c | ||
| 3515 | : c == '0' ? 0 | ||
| 3516 | : c == '_' ? 037 | ||
| 3517 | : c); | ||
| 3518 | } | ||
| 3519 | else | ||
| 3520 | str[to++] = c; | ||
| 3521 | } | ||
| 3522 | |||
| 3523 | return make_unibyte_string (str + start, to - start); | ||
| 3524 | } | ||
| 3525 | |||
| 3511 | 3526 | ||
| 3512 | /* Length of prefix only consisting of symbol constituent characters. */ | 3527 | /* Length of prefix only consisting of symbol constituent characters. */ |
| 3513 | static ptrdiff_t | 3528 | static ptrdiff_t |
| @@ -4249,6 +4264,15 @@ read0 (Lisp_Object readcharfun, bool locate_syms) | |||
| 4249 | XSETCDR (e->u.list.tail, obj); | 4264 | XSETCDR (e->u.list.tail, obj); |
| 4250 | read_stack_pop (); | 4265 | read_stack_pop (); |
| 4251 | obj = e->u.list.head; | 4266 | obj = e->u.list.head; |
| 4267 | |||
| 4268 | /* Hack: immediately convert (#$ . FIXNUM) to the corresponding | ||
| 4269 | string if load-force-doc-strings is set. */ | ||
| 4270 | if (load_force_doc_strings | ||
| 4271 | && BASE_EQ (XCAR (obj), Vload_file_name) | ||
| 4272 | && !NILP (XCAR (obj)) | ||
| 4273 | && FIXNUMP (XCDR (obj))) | ||
| 4274 | obj = get_lazy_string (obj); | ||
| 4275 | |||
| 4252 | break; | 4276 | break; |
| 4253 | } | 4277 | } |
| 4254 | 4278 | ||
diff --git a/src/marker.c b/src/marker.c index 3c8e628762e..9727586f424 100644 --- a/src/marker.c +++ b/src/marker.c | |||
| @@ -214,11 +214,12 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos) | |||
| 214 | We have one known above and one known below. | 214 | We have one known above and one known below. |
| 215 | Scan, counting characters, from whichever one is closer. */ | 215 | Scan, counting characters, from whichever one is closer. */ |
| 216 | 216 | ||
| 217 | eassert (best_below <= charpos && charpos <= best_above); | ||
| 217 | if (charpos - best_below < best_above - charpos) | 218 | if (charpos - best_below < best_above - charpos) |
| 218 | { | 219 | { |
| 219 | bool record = charpos - best_below > 5000; | 220 | bool record = charpos - best_below > 5000; |
| 220 | 221 | ||
| 221 | while (best_below != charpos) | 222 | while (best_below < charpos) |
| 222 | { | 223 | { |
| 223 | best_below++; | 224 | best_below++; |
| 224 | best_below_byte += buf_next_char_len (b, best_below_byte); | 225 | best_below_byte += buf_next_char_len (b, best_below_byte); |
| @@ -243,7 +244,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos) | |||
| 243 | { | 244 | { |
| 244 | bool record = best_above - charpos > 5000; | 245 | bool record = best_above - charpos > 5000; |
| 245 | 246 | ||
| 246 | while (best_above != charpos) | 247 | while (best_above > charpos) |
| 247 | { | 248 | { |
| 248 | best_above--; | 249 | best_above--; |
| 249 | best_above_byte -= buf_prev_char_len (b, best_above_byte); | 250 | best_above_byte -= buf_prev_char_len (b, best_above_byte); |
diff --git a/src/nsfns.m b/src/nsfns.m index 433df059610..1d3dcd31243 100644 --- a/src/nsfns.m +++ b/src/nsfns.m | |||
| @@ -1057,6 +1057,7 @@ frame_parm_handler ns_frame_parm_handlers[] = | |||
| 1057 | 0, /* x_set_override_redirect */ | 1057 | 0, /* x_set_override_redirect */ |
| 1058 | gui_set_no_special_glyphs, | 1058 | gui_set_no_special_glyphs, |
| 1059 | gui_set_alpha_background, | 1059 | gui_set_alpha_background, |
| 1060 | NULL, | ||
| 1060 | #ifdef NS_IMPL_COCOA | 1061 | #ifdef NS_IMPL_COCOA |
| 1061 | ns_set_appearance, | 1062 | ns_set_appearance, |
| 1062 | ns_set_transparent_titlebar, | 1063 | ns_set_transparent_titlebar, |
diff --git a/src/pgtkfns.c b/src/pgtkfns.c index d998c3d938c..beaf28f69d9 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c | |||
| @@ -991,6 +991,7 @@ frame_parm_handler pgtk_frame_parm_handlers[] = | |||
| 991 | pgtk_set_override_redirect, | 991 | pgtk_set_override_redirect, |
| 992 | gui_set_no_special_glyphs, | 992 | gui_set_no_special_glyphs, |
| 993 | pgtk_set_alpha_background, | 993 | pgtk_set_alpha_background, |
| 994 | NULL, | ||
| 994 | }; | 995 | }; |
| 995 | 996 | ||
| 996 | 997 | ||
diff --git a/src/print.c b/src/print.c index 7303e847aa2..1c96ec14b86 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -63,16 +63,17 @@ static Lisp_Object being_printed[PRINT_CIRCLE]; | |||
| 63 | /* Last char printed to stdout by printchar. */ | 63 | /* Last char printed to stdout by printchar. */ |
| 64 | static unsigned int printchar_stdout_last; | 64 | static unsigned int printchar_stdout_last; |
| 65 | 65 | ||
| 66 | struct print_buffer | ||
| 67 | { | ||
| 68 | char *buffer; /* Allocated buffer. */ | ||
| 69 | ptrdiff_t size; /* Size of allocated buffer. */ | ||
| 70 | ptrdiff_t pos; /* Chars stored in buffer. */ | ||
| 71 | ptrdiff_t pos_byte; /* Bytes stored in buffer. */ | ||
| 72 | }; | ||
| 73 | |||
| 66 | /* When printing into a buffer, first we put the text in this | 74 | /* When printing into a buffer, first we put the text in this |
| 67 | block, then insert it all at once. */ | 75 | block, then insert it all at once. */ |
| 68 | static char *print_buffer; | 76 | static struct print_buffer print_buffer; |
| 69 | |||
| 70 | /* Size allocated in print_buffer. */ | ||
| 71 | static ptrdiff_t print_buffer_size; | ||
| 72 | /* Chars stored in print_buffer. */ | ||
| 73 | static ptrdiff_t print_buffer_pos; | ||
| 74 | /* Bytes stored in print_buffer. */ | ||
| 75 | static ptrdiff_t print_buffer_pos_byte; | ||
| 76 | 77 | ||
| 77 | /* Vprint_number_table is a table, that keeps objects that are going to | 78 | /* Vprint_number_table is a table, that keeps objects that are going to |
| 78 | be printed, to allow use of #n= and #n# to express sharing. | 79 | be printed, to allow use of #n= and #n# to express sharing. |
| @@ -91,121 +92,139 @@ bool print_output_debug_flag EXTERNALLY_VISIBLE = 1; | |||
| 91 | 92 | ||
| 92 | /* Low level output routines for characters and strings. */ | 93 | /* Low level output routines for characters and strings. */ |
| 93 | 94 | ||
| 94 | /* Lisp functions to do output using a stream | ||
| 95 | must have the stream in a variable called printcharfun | ||
| 96 | and must start with PRINTPREPARE, end with PRINTFINISH. | ||
| 97 | Use printchar to output one character, | ||
| 98 | or call strout to output a block of characters. */ | ||
| 99 | |||
| 100 | #define PRINTPREPARE \ | ||
| 101 | ptrdiff_t old_point = -1, start_point = -1; \ | ||
| 102 | ptrdiff_t old_point_byte = -1, start_point_byte = -1; \ | ||
| 103 | specpdl_ref specpdl_count = SPECPDL_INDEX (); \ | ||
| 104 | bool multibyte \ | ||
| 105 | = !NILP (BVAR (current_buffer, enable_multibyte_characters)); \ | ||
| 106 | Lisp_Object original = printcharfun; \ | ||
| 107 | record_unwind_current_buffer (); \ | ||
| 108 | specbind(Qprint__unreadable_callback_buffer, Fcurrent_buffer ()); \ | ||
| 109 | if (NILP (printcharfun)) printcharfun = Qt; \ | ||
| 110 | if (BUFFERP (printcharfun)) \ | ||
| 111 | { \ | ||
| 112 | if (XBUFFER (printcharfun) != current_buffer) \ | ||
| 113 | Fset_buffer (printcharfun); \ | ||
| 114 | printcharfun = Qnil; \ | ||
| 115 | } \ | ||
| 116 | if (MARKERP (printcharfun)) \ | ||
| 117 | { \ | ||
| 118 | ptrdiff_t marker_pos; \ | ||
| 119 | if (! XMARKER (printcharfun)->buffer) \ | ||
| 120 | error ("Marker does not point anywhere"); \ | ||
| 121 | if (XMARKER (printcharfun)->buffer != current_buffer) \ | ||
| 122 | set_buffer_internal (XMARKER (printcharfun)->buffer); \ | ||
| 123 | marker_pos = marker_position (printcharfun); \ | ||
| 124 | if (marker_pos < BEGV || marker_pos > ZV) \ | ||
| 125 | signal_error ("Marker is outside the accessible " \ | ||
| 126 | "part of the buffer", printcharfun); \ | ||
| 127 | old_point = PT; \ | ||
| 128 | old_point_byte = PT_BYTE; \ | ||
| 129 | SET_PT_BOTH (marker_pos, \ | ||
| 130 | marker_byte_position (printcharfun)); \ | ||
| 131 | start_point = PT; \ | ||
| 132 | start_point_byte = PT_BYTE; \ | ||
| 133 | printcharfun = Qnil; \ | ||
| 134 | } \ | ||
| 135 | if (NILP (printcharfun)) \ | ||
| 136 | { \ | ||
| 137 | Lisp_Object string; \ | ||
| 138 | if (NILP (BVAR (current_buffer, enable_multibyte_characters)) \ | ||
| 139 | && ! print_escape_multibyte) \ | ||
| 140 | specbind (Qprint_escape_multibyte, Qt); \ | ||
| 141 | if (! NILP (BVAR (current_buffer, enable_multibyte_characters)) \ | ||
| 142 | && ! print_escape_nonascii) \ | ||
| 143 | specbind (Qprint_escape_nonascii, Qt); \ | ||
| 144 | if (print_buffer != 0) \ | ||
| 145 | { \ | ||
| 146 | string = make_string_from_bytes (print_buffer, \ | ||
| 147 | print_buffer_pos, \ | ||
| 148 | print_buffer_pos_byte); \ | ||
| 149 | record_unwind_protect (print_unwind, string); \ | ||
| 150 | } \ | ||
| 151 | else \ | ||
| 152 | { \ | ||
| 153 | int new_size = 1000; \ | ||
| 154 | print_buffer = xmalloc (new_size); \ | ||
| 155 | print_buffer_size = new_size; \ | ||
| 156 | record_unwind_protect_void (print_free_buffer); \ | ||
| 157 | } \ | ||
| 158 | print_buffer_pos = 0; \ | ||
| 159 | print_buffer_pos_byte = 0; \ | ||
| 160 | } \ | ||
| 161 | if (EQ (printcharfun, Qt) && ! noninteractive) \ | ||
| 162 | setup_echo_area_for_printing (multibyte); | ||
| 163 | |||
| 164 | #define PRINTFINISH \ | ||
| 165 | if (NILP (printcharfun)) \ | ||
| 166 | { \ | ||
| 167 | if (print_buffer_pos != print_buffer_pos_byte \ | ||
| 168 | && NILP (BVAR (current_buffer, enable_multibyte_characters)))\ | ||
| 169 | { \ | ||
| 170 | USE_SAFE_ALLOCA; \ | ||
| 171 | unsigned char *temp = SAFE_ALLOCA (print_buffer_pos + 1); \ | ||
| 172 | copy_text ((unsigned char *) print_buffer, temp, \ | ||
| 173 | print_buffer_pos_byte, 1, 0); \ | ||
| 174 | insert_1_both ((char *) temp, print_buffer_pos, \ | ||
| 175 | print_buffer_pos, 0, 1, 0); \ | ||
| 176 | SAFE_FREE (); \ | ||
| 177 | } \ | ||
| 178 | else \ | ||
| 179 | insert_1_both (print_buffer, print_buffer_pos, \ | ||
| 180 | print_buffer_pos_byte, 0, 1, 0); \ | ||
| 181 | signal_after_change (PT - print_buffer_pos, 0, print_buffer_pos);\ | ||
| 182 | } \ | ||
| 183 | if (MARKERP (original)) \ | ||
| 184 | set_marker_both (original, Qnil, PT, PT_BYTE); \ | ||
| 185 | if (old_point >= 0) \ | ||
| 186 | SET_PT_BOTH (old_point + (old_point >= start_point \ | ||
| 187 | ? PT - start_point : 0), \ | ||
| 188 | old_point_byte + (old_point_byte >= start_point_byte \ | ||
| 189 | ? PT_BYTE - start_point_byte : 0)); \ | ||
| 190 | unbind_to (specpdl_count, Qnil); \ | ||
| 191 | |||
| 192 | /* This is used to free the print buffer; we don't simply record xfree | 95 | /* This is used to free the print buffer; we don't simply record xfree |
| 193 | since print_buffer can be reallocated during the printing. */ | 96 | since print_buffer can be reallocated during the printing. */ |
| 194 | |||
| 195 | static void | 97 | static void |
| 196 | print_free_buffer (void) | 98 | print_free_buffer (void) |
| 197 | { | 99 | { |
| 198 | xfree (print_buffer); | 100 | xfree (print_buffer.buffer); |
| 199 | print_buffer = NULL; | 101 | print_buffer.buffer = NULL; |
| 200 | } | 102 | } |
| 201 | 103 | ||
| 202 | /* This is used to restore the saved contents of print_buffer | 104 | /* This is used to restore the saved contents of print_buffer |
| 203 | when there is a recursive call to print. */ | 105 | when there is a recursive call to print. */ |
| 204 | |||
| 205 | static void | 106 | static void |
| 206 | print_unwind (Lisp_Object saved_text) | 107 | print_unwind (Lisp_Object saved_text) |
| 207 | { | 108 | { |
| 208 | memcpy (print_buffer, SDATA (saved_text), SCHARS (saved_text)); | 109 | memcpy (print_buffer.buffer, SDATA (saved_text), SCHARS (saved_text)); |
| 110 | } | ||
| 111 | |||
| 112 | /* Lisp functions to do output using a stream must start with a call to | ||
| 113 | print_prepare, and end with calling print_finish. | ||
| 114 | Use printchar to output one character, or call strout to output a | ||
| 115 | block of characters. */ | ||
| 116 | |||
| 117 | /* State carried between print_prepare and print_finish. */ | ||
| 118 | struct print_context | ||
| 119 | { | ||
| 120 | Lisp_Object printcharfun; | ||
| 121 | Lisp_Object old_printcharfun; | ||
| 122 | ptrdiff_t old_point, start_point; | ||
| 123 | ptrdiff_t old_point_byte, start_point_byte; | ||
| 124 | specpdl_ref specpdl_count; | ||
| 125 | }; | ||
| 126 | |||
| 127 | static inline struct print_context | ||
| 128 | print_prepare (Lisp_Object printcharfun) | ||
| 129 | { | ||
| 130 | struct print_context pc = { | ||
| 131 | .old_printcharfun = printcharfun, | ||
| 132 | .old_point = -1, | ||
| 133 | .start_point = -1, | ||
| 134 | .old_point_byte = -1, | ||
| 135 | .start_point_byte = -1, | ||
| 136 | .specpdl_count = SPECPDL_INDEX (), | ||
| 137 | }; | ||
| 138 | bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters)); | ||
| 139 | record_unwind_current_buffer (); | ||
| 140 | specbind(Qprint__unreadable_callback_buffer, Fcurrent_buffer ()); | ||
| 141 | if (NILP (printcharfun)) | ||
| 142 | printcharfun = Qt; | ||
| 143 | if (BUFFERP (printcharfun)) | ||
| 144 | { | ||
| 145 | if (XBUFFER (printcharfun) != current_buffer) | ||
| 146 | Fset_buffer (printcharfun); | ||
| 147 | printcharfun = Qnil; | ||
| 148 | } | ||
| 149 | if (MARKERP (printcharfun)) | ||
| 150 | { | ||
| 151 | if (! XMARKER (printcharfun)->buffer) | ||
| 152 | error ("Marker does not point anywhere"); | ||
| 153 | if (XMARKER (printcharfun)->buffer != current_buffer) | ||
| 154 | set_buffer_internal (XMARKER (printcharfun)->buffer); | ||
| 155 | ptrdiff_t marker_pos = marker_position (printcharfun); | ||
| 156 | if (marker_pos < BEGV || marker_pos > ZV) | ||
| 157 | signal_error ("Marker is outside the accessible part of the buffer", | ||
| 158 | printcharfun); | ||
| 159 | pc.old_point = PT; | ||
| 160 | pc.old_point_byte = PT_BYTE; | ||
| 161 | SET_PT_BOTH (marker_pos, marker_byte_position (printcharfun)); | ||
| 162 | pc.start_point = PT; | ||
| 163 | pc.start_point_byte = PT_BYTE; | ||
| 164 | printcharfun = Qnil; | ||
| 165 | } | ||
| 166 | if (NILP (printcharfun)) | ||
| 167 | { | ||
| 168 | if (NILP (BVAR (current_buffer, enable_multibyte_characters)) | ||
| 169 | && ! print_escape_multibyte) | ||
| 170 | specbind (Qprint_escape_multibyte, Qt); | ||
| 171 | if (! NILP (BVAR (current_buffer, enable_multibyte_characters)) | ||
| 172 | && ! print_escape_nonascii) | ||
| 173 | specbind (Qprint_escape_nonascii, Qt); | ||
| 174 | if (print_buffer.buffer != NULL) | ||
| 175 | { | ||
| 176 | Lisp_Object string = make_string_from_bytes (print_buffer.buffer, | ||
| 177 | print_buffer.pos, | ||
| 178 | print_buffer.pos_byte); | ||
| 179 | record_unwind_protect (print_unwind, string); | ||
| 180 | } | ||
| 181 | else | ||
| 182 | { | ||
| 183 | int new_size = 1000; | ||
| 184 | print_buffer.buffer = xmalloc (new_size); | ||
| 185 | print_buffer.size = new_size; | ||
| 186 | record_unwind_protect_void (print_free_buffer); | ||
| 187 | } | ||
| 188 | print_buffer.pos = 0; | ||
| 189 | print_buffer.pos_byte = 0; | ||
| 190 | } | ||
| 191 | if (EQ (printcharfun, Qt) && ! noninteractive) | ||
| 192 | setup_echo_area_for_printing (multibyte); | ||
| 193 | pc.printcharfun = printcharfun; | ||
| 194 | return pc; | ||
| 195 | } | ||
| 196 | |||
| 197 | static inline void | ||
| 198 | print_finish (struct print_context *pc) | ||
| 199 | { | ||
| 200 | if (NILP (pc->printcharfun)) | ||
| 201 | { | ||
| 202 | if (print_buffer.pos != print_buffer.pos_byte | ||
| 203 | && NILP (BVAR (current_buffer, enable_multibyte_characters))) | ||
| 204 | { | ||
| 205 | USE_SAFE_ALLOCA; | ||
| 206 | unsigned char *temp = SAFE_ALLOCA (print_buffer.pos + 1); | ||
| 207 | copy_text ((unsigned char *) print_buffer.buffer, temp, | ||
| 208 | print_buffer.pos_byte, 1, 0); | ||
| 209 | insert_1_both ((char *) temp, print_buffer.pos, | ||
| 210 | print_buffer.pos, 0, 1, 0); | ||
| 211 | SAFE_FREE (); | ||
| 212 | } | ||
| 213 | else | ||
| 214 | insert_1_both (print_buffer.buffer, print_buffer.pos, | ||
| 215 | print_buffer.pos_byte, 0, 1, 0); | ||
| 216 | signal_after_change (PT - print_buffer.pos, 0, print_buffer.pos); | ||
| 217 | } | ||
| 218 | if (MARKERP (pc->old_printcharfun)) | ||
| 219 | set_marker_both (pc->old_printcharfun, Qnil, PT, PT_BYTE); | ||
| 220 | if (pc->old_point >= 0) | ||
| 221 | SET_PT_BOTH (pc->old_point | ||
| 222 | + (pc->old_point >= pc->start_point | ||
| 223 | ? PT - pc->start_point : 0), | ||
| 224 | pc->old_point_byte | ||
| 225 | + (pc->old_point_byte >= pc->start_point_byte | ||
| 226 | ? PT_BYTE - pc->start_point_byte : 0)); | ||
| 227 | unbind_to (pc->specpdl_count, Qnil); | ||
| 209 | } | 228 | } |
| 210 | 229 | ||
| 211 | /* Print character CH to the stdio stream STREAM. */ | 230 | /* Print character CH to the stdio stream STREAM. */ |
| @@ -293,13 +312,14 @@ printchar (unsigned int ch, Lisp_Object fun) | |||
| 293 | 312 | ||
| 294 | if (NILP (fun)) | 313 | if (NILP (fun)) |
| 295 | { | 314 | { |
| 296 | ptrdiff_t incr = len - (print_buffer_size - print_buffer_pos_byte); | 315 | ptrdiff_t incr = len - (print_buffer.size - print_buffer.pos_byte); |
| 297 | if (incr > 0) | 316 | if (incr > 0) |
| 298 | print_buffer = xpalloc (print_buffer, &print_buffer_size, | 317 | print_buffer.buffer = xpalloc (print_buffer.buffer, |
| 299 | incr, -1, 1); | 318 | &print_buffer.size, |
| 300 | memcpy (print_buffer + print_buffer_pos_byte, str, len); | 319 | incr, -1, 1); |
| 301 | print_buffer_pos += 1; | 320 | memcpy (print_buffer.buffer + print_buffer.pos_byte, str, len); |
| 302 | print_buffer_pos_byte += len; | 321 | print_buffer.pos += 1; |
| 322 | print_buffer.pos_byte += len; | ||
| 303 | } | 323 | } |
| 304 | else if (noninteractive) | 324 | else if (noninteractive) |
| 305 | { | 325 | { |
| @@ -358,12 +378,13 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t size_byte, | |||
| 358 | { | 378 | { |
| 359 | if (NILP (printcharfun)) | 379 | if (NILP (printcharfun)) |
| 360 | { | 380 | { |
| 361 | ptrdiff_t incr = size_byte - (print_buffer_size - print_buffer_pos_byte); | 381 | ptrdiff_t incr = size_byte - (print_buffer.size - print_buffer.pos_byte); |
| 362 | if (incr > 0) | 382 | if (incr > 0) |
| 363 | print_buffer = xpalloc (print_buffer, &print_buffer_size, incr, -1, 1); | 383 | print_buffer.buffer = xpalloc (print_buffer.buffer, |
| 364 | memcpy (print_buffer + print_buffer_pos_byte, ptr, size_byte); | 384 | &print_buffer.size, incr, -1, 1); |
| 365 | print_buffer_pos += size; | 385 | memcpy (print_buffer.buffer + print_buffer.pos_byte, ptr, size_byte); |
| 366 | print_buffer_pos_byte += size_byte; | 386 | print_buffer.pos += size; |
| 387 | print_buffer.pos_byte += size_byte; | ||
| 367 | } | 388 | } |
| 368 | else if (noninteractive && EQ (printcharfun, Qt)) | 389 | else if (noninteractive && EQ (printcharfun, Qt)) |
| 369 | { | 390 | { |
| @@ -527,14 +548,14 @@ PRINTCHARFUN defaults to the value of `standard-output' (which see). */) | |||
| 527 | if (NILP (printcharfun)) | 548 | if (NILP (printcharfun)) |
| 528 | printcharfun = Vstandard_output; | 549 | printcharfun = Vstandard_output; |
| 529 | CHECK_FIXNUM (character); | 550 | CHECK_FIXNUM (character); |
| 530 | PRINTPREPARE; | 551 | struct print_context pc = print_prepare (printcharfun); |
| 531 | printchar (XFIXNUM (character), printcharfun); | 552 | printchar (XFIXNUM (character), pc.printcharfun); |
| 532 | PRINTFINISH; | 553 | print_finish (&pc); |
| 533 | return character; | 554 | return character; |
| 534 | } | 555 | } |
| 535 | 556 | ||
| 536 | /* Print the contents of a unibyte C string STRING using PRINTCHARFUN. | 557 | /* Print the contents of a unibyte C string STRING using PRINTCHARFUN. |
| 537 | The caller should arrange to put this inside PRINTPREPARE and PRINTFINISH. | 558 | The caller should arrange to put this inside print_prepare and print_finish. |
| 538 | Do not use this on the contents of a Lisp string. */ | 559 | Do not use this on the contents of a Lisp string. */ |
| 539 | 560 | ||
| 540 | static void | 561 | static void |
| @@ -550,9 +571,9 @@ print_c_string (char const *string, Lisp_Object printcharfun) | |||
| 550 | static void | 571 | static void |
| 551 | write_string (const char *data, Lisp_Object printcharfun) | 572 | write_string (const char *data, Lisp_Object printcharfun) |
| 552 | { | 573 | { |
| 553 | PRINTPREPARE; | 574 | struct print_context pc = print_prepare (printcharfun); |
| 554 | print_c_string (data, printcharfun); | 575 | print_c_string (data, pc.printcharfun); |
| 555 | PRINTFINISH; | 576 | print_finish (&pc); |
| 556 | } | 577 | } |
| 557 | 578 | ||
| 558 | 579 | ||
| @@ -605,21 +626,21 @@ If PRINTCHARFUN is omitted or nil, the value of `standard-output' is used. */) | |||
| 605 | 626 | ||
| 606 | if (NILP (printcharfun)) | 627 | if (NILP (printcharfun)) |
| 607 | printcharfun = Vstandard_output; | 628 | printcharfun = Vstandard_output; |
| 608 | PRINTPREPARE; | 629 | struct print_context pc = print_prepare (printcharfun); |
| 609 | 630 | ||
| 610 | if (NILP (ensure)) | 631 | if (NILP (ensure)) |
| 611 | val = Qt; | 632 | val = Qt; |
| 612 | /* Difficult to check if at line beginning so abort. */ | 633 | /* Difficult to check if at line beginning so abort. */ |
| 613 | else if (FUNCTIONP (printcharfun)) | 634 | else if (FUNCTIONP (pc.printcharfun)) |
| 614 | signal_error ("Unsupported function argument", printcharfun); | 635 | signal_error ("Unsupported function argument", pc.printcharfun); |
| 615 | else if (noninteractive && !NILP (printcharfun)) | 636 | else if (noninteractive && !NILP (pc.printcharfun)) |
| 616 | val = printchar_stdout_last == 10 ? Qnil : Qt; | 637 | val = printchar_stdout_last == 10 ? Qnil : Qt; |
| 617 | else | 638 | else |
| 618 | val = NILP (Fbolp ()) ? Qt : Qnil; | 639 | val = NILP (Fbolp ()) ? Qt : Qnil; |
| 619 | 640 | ||
| 620 | if (!NILP (val)) | 641 | if (!NILP (val)) |
| 621 | printchar ('\n', printcharfun); | 642 | printchar ('\n', pc.printcharfun); |
| 622 | PRINTFINISH; | 643 | print_finish (&pc); |
| 623 | return val; | 644 | return val; |
| 624 | } | 645 | } |
| 625 | 646 | ||
| @@ -750,9 +771,9 @@ means "use default values for all the print-related settings". */) | |||
| 750 | if (!NILP (overrides)) | 771 | if (!NILP (overrides)) |
| 751 | print_bind_overrides (overrides); | 772 | print_bind_overrides (overrides); |
| 752 | 773 | ||
| 753 | PRINTPREPARE; | 774 | struct print_context pc = print_prepare (printcharfun); |
| 754 | print (object, printcharfun, 1); | 775 | print (object, pc.printcharfun, 1); |
| 755 | PRINTFINISH; | 776 | print_finish (&pc); |
| 756 | 777 | ||
| 757 | return unbind_to (count, object); | 778 | return unbind_to (count, object); |
| 758 | } | 779 | } |
| @@ -787,11 +808,10 @@ A printed representation of an object is text which describes that object. */) | |||
| 787 | No need for specbind, since errors deactivate the mark. */ | 808 | No need for specbind, since errors deactivate the mark. */ |
| 788 | Lisp_Object save_deactivate_mark = Vdeactivate_mark; | 809 | Lisp_Object save_deactivate_mark = Vdeactivate_mark; |
| 789 | 810 | ||
| 790 | Lisp_Object printcharfun = Vprin1_to_string_buffer; | 811 | struct print_context pc = print_prepare (Vprin1_to_string_buffer); |
| 791 | PRINTPREPARE; | 812 | print (object, pc.printcharfun, NILP (noescape)); |
| 792 | print (object, printcharfun, NILP (noescape)); | 813 | /* Make Vprin1_to_string_buffer be the default buffer after print_finish */ |
| 793 | /* Make Vprin1_to_string_buffer be the default buffer after PRINTFINISH */ | 814 | print_finish (&pc); |
| 794 | PRINTFINISH; | ||
| 795 | 815 | ||
| 796 | struct buffer *previous = current_buffer; | 816 | struct buffer *previous = current_buffer; |
| 797 | set_buffer_internal (XBUFFER (Vprin1_to_string_buffer)); | 817 | set_buffer_internal (XBUFFER (Vprin1_to_string_buffer)); |
| @@ -836,15 +856,15 @@ is used instead. */) | |||
| 836 | { | 856 | { |
| 837 | if (NILP (printcharfun)) | 857 | if (NILP (printcharfun)) |
| 838 | printcharfun = Vstandard_output; | 858 | printcharfun = Vstandard_output; |
| 839 | PRINTPREPARE; | 859 | struct print_context pc = print_prepare (printcharfun); |
| 840 | if (STRINGP (object) | 860 | if (STRINGP (object) |
| 841 | && !string_intervals (object) | 861 | && !string_intervals (object) |
| 842 | && NILP (Vprint_continuous_numbering)) | 862 | && NILP (Vprint_continuous_numbering)) |
| 843 | /* fast path for plain strings */ | 863 | /* fast path for plain strings */ |
| 844 | print_string (object, printcharfun); | 864 | print_string (object, pc.printcharfun); |
| 845 | else | 865 | else |
| 846 | print (object, printcharfun, 0); | 866 | print (object, pc.printcharfun, 0); |
| 847 | PRINTFINISH; | 867 | print_finish (&pc); |
| 848 | return object; | 868 | return object; |
| 849 | } | 869 | } |
| 850 | 870 | ||
| @@ -875,11 +895,11 @@ is used instead. */) | |||
| 875 | { | 895 | { |
| 876 | if (NILP (printcharfun)) | 896 | if (NILP (printcharfun)) |
| 877 | printcharfun = Vstandard_output; | 897 | printcharfun = Vstandard_output; |
| 878 | PRINTPREPARE; | 898 | struct print_context pc = print_prepare (printcharfun); |
| 879 | printchar ('\n', printcharfun); | 899 | printchar ('\n', pc.printcharfun); |
| 880 | print (object, printcharfun, 1); | 900 | print (object, pc.printcharfun, 1); |
| 881 | printchar ('\n', printcharfun); | 901 | printchar ('\n', pc.printcharfun); |
| 882 | PRINTFINISH; | 902 | print_finish (&pc); |
| 883 | return object; | 903 | return object; |
| 884 | } | 904 | } |
| 885 | 905 | ||
diff --git a/src/process.c b/src/process.c index a15efa39bd1..23479c06194 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -1243,14 +1243,31 @@ or t (process is stopped). */) | |||
| 1243 | return XPROCESS (process)->command; | 1243 | return XPROCESS (process)->command; |
| 1244 | } | 1244 | } |
| 1245 | 1245 | ||
| 1246 | DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0, | 1246 | DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 2, 0, |
| 1247 | doc: /* Return the name of the terminal PROCESS uses, or nil if none. | 1247 | doc: /* Return the name of the terminal PROCESS uses, or nil if none. |
| 1248 | This is the terminal that the process itself reads and writes on, | 1248 | This is the terminal that the process itself reads and writes on, |
| 1249 | not the name of the pty that Emacs uses to talk with that terminal. */) | 1249 | not the name of the pty that Emacs uses to talk with that terminal. |
| 1250 | (register Lisp_Object process) | 1250 | |
| 1251 | If STREAM is nil, return the terminal name if any of PROCESS's | ||
| 1252 | standard streams use a terminal for communication. If STREAM is one | ||
| 1253 | of `stdin', `stdout', or `stderr', return the name of the terminal | ||
| 1254 | PROCESS uses for that stream specifically, or nil if that stream | ||
| 1255 | communicates via a pipe. */) | ||
| 1256 | (register Lisp_Object process, Lisp_Object stream) | ||
| 1251 | { | 1257 | { |
| 1252 | CHECK_PROCESS (process); | 1258 | CHECK_PROCESS (process); |
| 1253 | return XPROCESS (process)->tty_name; | 1259 | register struct Lisp_Process *p = XPROCESS (process); |
| 1260 | |||
| 1261 | if (NILP (stream)) | ||
| 1262 | return p->tty_name; | ||
| 1263 | else if (EQ (stream, Qstdin)) | ||
| 1264 | return p->pty_in ? p->tty_name : Qnil; | ||
| 1265 | else if (EQ (stream, Qstdout)) | ||
| 1266 | return p->pty_out ? p->tty_name : Qnil; | ||
| 1267 | else if (EQ (stream, Qstderr)) | ||
| 1268 | return p->pty_out && NILP (p->stderrproc) ? p->tty_name : Qnil; | ||
| 1269 | else | ||
| 1270 | signal_error ("Unknown stream", stream); | ||
| 1254 | } | 1271 | } |
| 1255 | 1272 | ||
| 1256 | static void | 1273 | static void |
| @@ -1316,6 +1333,19 @@ set_process_filter_masks (struct Lisp_Process *p) | |||
| 1316 | add_process_read_fd (p->infd); | 1333 | add_process_read_fd (p->infd); |
| 1317 | } | 1334 | } |
| 1318 | 1335 | ||
| 1336 | static bool | ||
| 1337 | is_pty_from_symbol (Lisp_Object symbol) | ||
| 1338 | { | ||
| 1339 | if (EQ (symbol, Qpty)) | ||
| 1340 | return true; | ||
| 1341 | else if (EQ (symbol, Qpipe)) | ||
| 1342 | return false; | ||
| 1343 | else if (NILP (symbol)) | ||
| 1344 | return !NILP (Vprocess_connection_type); | ||
| 1345 | else | ||
| 1346 | report_file_error ("Unknown connection type", symbol); | ||
| 1347 | } | ||
| 1348 | |||
| 1319 | DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, | 1349 | DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, |
| 1320 | 2, 2, 0, | 1350 | 2, 2, 0, |
| 1321 | doc: /* Give PROCESS the filter function FILTER; nil means default. | 1351 | doc: /* Give PROCESS the filter function FILTER; nil means default. |
| @@ -1741,15 +1771,18 @@ signals to stop and continue a process. | |||
| 1741 | :connection-type TYPE -- TYPE is control type of device used to | 1771 | :connection-type TYPE -- TYPE is control type of device used to |
| 1742 | communicate with subprocesses. Values are `pipe' to use a pipe, `pty' | 1772 | communicate with subprocesses. Values are `pipe' to use a pipe, `pty' |
| 1743 | to use a pty, or nil to use the default specified through | 1773 | to use a pty, or nil to use the default specified through |
| 1744 | `process-connection-type'. | 1774 | `process-connection-type'. If TYPE is a cons (INPUT . OUTPUT), then |
| 1775 | INPUT will be used for standard input and OUTPUT for standard output | ||
| 1776 | (and standard error if `:stderr' is nil). | ||
| 1745 | 1777 | ||
| 1746 | :filter FILTER -- Install FILTER as the process filter. | 1778 | :filter FILTER -- Install FILTER as the process filter. |
| 1747 | 1779 | ||
| 1748 | :sentinel SENTINEL -- Install SENTINEL as the process sentinel. | 1780 | :sentinel SENTINEL -- Install SENTINEL as the process sentinel. |
| 1749 | 1781 | ||
| 1750 | :stderr STDERR -- STDERR is either a buffer or a pipe process attached | 1782 | :stderr STDERR -- STDERR is either a buffer or a pipe process attached |
| 1751 | to the standard error of subprocess. Specifying this implies | 1783 | to the standard error of subprocess. When specifying this, the |
| 1752 | `:connection-type' is set to `pipe'. If STDERR is nil, standard error | 1784 | subprocess's standard error will always communicate via a pipe, no |
| 1785 | matter the value of `:connection-type'. If STDERR is nil, standard error | ||
| 1753 | is mixed with standard output and sent to BUFFER or FILTER. (Note | 1786 | is mixed with standard output and sent to BUFFER or FILTER. (Note |
| 1754 | that specifying :stderr will create a new, separate (but associated) | 1787 | that specifying :stderr will create a new, separate (but associated) |
| 1755 | process, with its own filter and sentinel. See | 1788 | process, with its own filter and sentinel. See |
| @@ -1845,22 +1878,20 @@ usage: (make-process &rest ARGS) */) | |||
| 1845 | CHECK_TYPE (NILP (tem), Qnull, tem); | 1878 | CHECK_TYPE (NILP (tem), Qnull, tem); |
| 1846 | 1879 | ||
| 1847 | tem = plist_get (contact, QCconnection_type); | 1880 | tem = plist_get (contact, QCconnection_type); |
| 1848 | if (EQ (tem, Qpty)) | 1881 | if (CONSP (tem)) |
| 1849 | XPROCESS (proc)->pty_flag = true; | 1882 | { |
| 1850 | else if (EQ (tem, Qpipe)) | 1883 | XPROCESS (proc)->pty_in = is_pty_from_symbol (XCAR (tem)); |
| 1851 | XPROCESS (proc)->pty_flag = false; | 1884 | XPROCESS (proc)->pty_out = is_pty_from_symbol (XCDR (tem)); |
| 1852 | else if (NILP (tem)) | 1885 | } |
| 1853 | XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type); | ||
| 1854 | else | 1886 | else |
| 1855 | report_file_error ("Unknown connection type", tem); | ||
| 1856 | |||
| 1857 | if (!NILP (stderrproc)) | ||
| 1858 | { | 1887 | { |
| 1859 | pset_stderrproc (XPROCESS (proc), stderrproc); | 1888 | XPROCESS (proc)->pty_in = XPROCESS (proc)->pty_out = |
| 1860 | 1889 | is_pty_from_symbol (tem); | |
| 1861 | XPROCESS (proc)->pty_flag = false; | ||
| 1862 | } | 1890 | } |
| 1863 | 1891 | ||
| 1892 | if (!NILP (stderrproc)) | ||
| 1893 | pset_stderrproc (XPROCESS (proc), stderrproc); | ||
| 1894 | |||
| 1864 | #ifdef HAVE_GNUTLS | 1895 | #ifdef HAVE_GNUTLS |
| 1865 | /* AKA GNUTLS_INITSTAGE(proc). */ | 1896 | /* AKA GNUTLS_INITSTAGE(proc). */ |
| 1866 | verify (GNUTLS_STAGE_EMPTY == 0); | 1897 | verify (GNUTLS_STAGE_EMPTY == 0); |
| @@ -2099,66 +2130,80 @@ static void | |||
| 2099 | create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | 2130 | create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) |
| 2100 | { | 2131 | { |
| 2101 | struct Lisp_Process *p = XPROCESS (process); | 2132 | struct Lisp_Process *p = XPROCESS (process); |
| 2102 | int inchannel, outchannel; | 2133 | int inchannel = -1, outchannel = -1; |
| 2103 | pid_t pid = -1; | 2134 | pid_t pid = -1; |
| 2104 | int vfork_errno; | 2135 | int vfork_errno; |
| 2105 | int forkin, forkout, forkerr = -1; | 2136 | int forkin, forkout, forkerr = -1; |
| 2106 | bool pty_flag = 0; | 2137 | bool pty_in = false, pty_out = false; |
| 2107 | char pty_name[PTY_NAME_SIZE]; | 2138 | char pty_name[PTY_NAME_SIZE]; |
| 2108 | Lisp_Object lisp_pty_name = Qnil; | 2139 | Lisp_Object lisp_pty_name = Qnil; |
| 2140 | int ptychannel = -1, pty_tty = -1; | ||
| 2109 | sigset_t oldset; | 2141 | sigset_t oldset; |
| 2110 | 2142 | ||
| 2111 | /* Ensure that the SIGCHLD handler can notify | 2143 | /* Ensure that the SIGCHLD handler can notify |
| 2112 | `wait_reading_process_output'. */ | 2144 | `wait_reading_process_output'. */ |
| 2113 | child_signal_init (); | 2145 | child_signal_init (); |
| 2114 | 2146 | ||
| 2115 | inchannel = outchannel = -1; | 2147 | if (p->pty_in || p->pty_out) |
| 2116 | 2148 | ptychannel = allocate_pty (pty_name); | |
| 2117 | if (p->pty_flag) | ||
| 2118 | outchannel = inchannel = allocate_pty (pty_name); | ||
| 2119 | 2149 | ||
| 2120 | if (inchannel >= 0) | 2150 | if (ptychannel >= 0) |
| 2121 | { | 2151 | { |
| 2122 | p->open_fd[READ_FROM_SUBPROCESS] = inchannel; | ||
| 2123 | #if ! defined (USG) || defined (USG_SUBTTY_WORKS) | 2152 | #if ! defined (USG) || defined (USG_SUBTTY_WORKS) |
| 2124 | /* On most USG systems it does not work to open the pty's tty here, | 2153 | /* On most USG systems it does not work to open the pty's tty here, |
| 2125 | then close it and reopen it in the child. */ | 2154 | then close it and reopen it in the child. */ |
| 2126 | /* Don't let this terminal become our controlling terminal | 2155 | /* Don't let this terminal become our controlling terminal |
| 2127 | (in case we don't have one). */ | 2156 | (in case we don't have one). */ |
| 2128 | forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); | 2157 | pty_tty = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); |
| 2129 | if (forkin < 0) | 2158 | if (pty_tty < 0) |
| 2130 | report_file_error ("Opening pty", Qnil); | 2159 | report_file_error ("Opening pty", Qnil); |
| 2131 | p->open_fd[SUBPROCESS_STDIN] = forkin; | ||
| 2132 | #else | ||
| 2133 | forkin = forkout = -1; | ||
| 2134 | #endif /* not USG, or USG_SUBTTY_WORKS */ | 2160 | #endif /* not USG, or USG_SUBTTY_WORKS */ |
| 2135 | pty_flag = 1; | 2161 | pty_in = p->pty_in; |
| 2162 | pty_out = p->pty_out; | ||
| 2136 | lisp_pty_name = build_string (pty_name); | 2163 | lisp_pty_name = build_string (pty_name); |
| 2137 | } | 2164 | } |
| 2165 | |||
| 2166 | /* Set up stdin for the child process. */ | ||
| 2167 | if (ptychannel >= 0 && p->pty_in) | ||
| 2168 | { | ||
| 2169 | p->open_fd[SUBPROCESS_STDIN] = forkin = pty_tty; | ||
| 2170 | outchannel = ptychannel; | ||
| 2171 | } | ||
| 2138 | else | 2172 | else |
| 2139 | { | 2173 | { |
| 2140 | if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0 | 2174 | if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0) |
| 2141 | || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0) | ||
| 2142 | report_file_error ("Creating pipe", Qnil); | 2175 | report_file_error ("Creating pipe", Qnil); |
| 2143 | forkin = p->open_fd[SUBPROCESS_STDIN]; | 2176 | forkin = p->open_fd[SUBPROCESS_STDIN]; |
| 2144 | outchannel = p->open_fd[WRITE_TO_SUBPROCESS]; | 2177 | outchannel = p->open_fd[WRITE_TO_SUBPROCESS]; |
| 2178 | } | ||
| 2179 | |||
| 2180 | /* Set up stdout for the child process. */ | ||
| 2181 | if (ptychannel >= 0 && p->pty_out) | ||
| 2182 | { | ||
| 2183 | forkout = pty_tty; | ||
| 2184 | p->open_fd[READ_FROM_SUBPROCESS] = inchannel = ptychannel; | ||
| 2185 | } | ||
| 2186 | else | ||
| 2187 | { | ||
| 2188 | if (emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0) | ||
| 2189 | report_file_error ("Creating pipe", Qnil); | ||
| 2145 | inchannel = p->open_fd[READ_FROM_SUBPROCESS]; | 2190 | inchannel = p->open_fd[READ_FROM_SUBPROCESS]; |
| 2146 | forkout = p->open_fd[SUBPROCESS_STDOUT]; | 2191 | forkout = p->open_fd[SUBPROCESS_STDOUT]; |
| 2147 | 2192 | ||
| 2148 | #if defined(GNU_LINUX) && defined(F_SETPIPE_SZ) | 2193 | #if defined(GNU_LINUX) && defined(F_SETPIPE_SZ) |
| 2149 | fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max); | 2194 | fcntl (inchannel, F_SETPIPE_SZ, read_process_output_max); |
| 2150 | #endif | 2195 | #endif |
| 2196 | } | ||
| 2151 | 2197 | ||
| 2152 | if (!NILP (p->stderrproc)) | 2198 | if (!NILP (p->stderrproc)) |
| 2153 | { | 2199 | { |
| 2154 | struct Lisp_Process *pp = XPROCESS (p->stderrproc); | 2200 | struct Lisp_Process *pp = XPROCESS (p->stderrproc); |
| 2155 | 2201 | ||
| 2156 | forkerr = pp->open_fd[SUBPROCESS_STDOUT]; | 2202 | forkerr = pp->open_fd[SUBPROCESS_STDOUT]; |
| 2157 | 2203 | ||
| 2158 | /* Close unnecessary file descriptors. */ | 2204 | /* Close unnecessary file descriptors. */ |
| 2159 | close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]); | 2205 | close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]); |
| 2160 | close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]); | 2206 | close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]); |
| 2161 | } | ||
| 2162 | } | 2207 | } |
| 2163 | 2208 | ||
| 2164 | if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel) | 2209 | if (FD_SETSIZE <= inchannel || FD_SETSIZE <= outchannel) |
| @@ -2183,7 +2228,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 2183 | we just reopen the device (see emacs_get_tty_pgrp) as this is | 2228 | we just reopen the device (see emacs_get_tty_pgrp) as this is |
| 2184 | more portable (see USG_SUBTTY_WORKS above). */ | 2229 | more portable (see USG_SUBTTY_WORKS above). */ |
| 2185 | 2230 | ||
| 2186 | p->pty_flag = pty_flag; | 2231 | p->pty_in = pty_in; |
| 2232 | p->pty_out = pty_out; | ||
| 2187 | pset_status (p, Qrun); | 2233 | pset_status (p, Qrun); |
| 2188 | 2234 | ||
| 2189 | if (!EQ (p->command, Qt) | 2235 | if (!EQ (p->command, Qt) |
| @@ -2199,13 +2245,15 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 2199 | block_input (); | 2245 | block_input (); |
| 2200 | block_child_signal (&oldset); | 2246 | block_child_signal (&oldset); |
| 2201 | 2247 | ||
| 2202 | pty_flag = p->pty_flag; | 2248 | pty_in = p->pty_in; |
| 2203 | eassert (pty_flag == ! NILP (lisp_pty_name)); | 2249 | pty_out = p->pty_out; |
| 2250 | eassert ((pty_in || pty_out) == ! NILP (lisp_pty_name)); | ||
| 2204 | 2251 | ||
| 2205 | vfork_errno | 2252 | vfork_errno |
| 2206 | = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env, | 2253 | = emacs_spawn (&pid, forkin, forkout, forkerr, new_argv, env, |
| 2207 | SSDATA (current_dir), | 2254 | SSDATA (current_dir), |
| 2208 | pty_flag ? SSDATA (lisp_pty_name) : NULL, &oldset); | 2255 | pty_in || pty_out ? SSDATA (lisp_pty_name) : NULL, |
| 2256 | pty_in, pty_out, &oldset); | ||
| 2209 | 2257 | ||
| 2210 | eassert ((vfork_errno == 0) == (0 < pid)); | 2258 | eassert ((vfork_errno == 0) == (0 < pid)); |
| 2211 | 2259 | ||
| @@ -2263,7 +2311,7 @@ create_pty (Lisp_Object process) | |||
| 2263 | { | 2311 | { |
| 2264 | struct Lisp_Process *p = XPROCESS (process); | 2312 | struct Lisp_Process *p = XPROCESS (process); |
| 2265 | char pty_name[PTY_NAME_SIZE]; | 2313 | char pty_name[PTY_NAME_SIZE]; |
| 2266 | int pty_fd = !p->pty_flag ? -1 : allocate_pty (pty_name); | 2314 | int pty_fd = !(p->pty_in || p->pty_out) ? -1 : allocate_pty (pty_name); |
| 2267 | 2315 | ||
| 2268 | if (pty_fd >= 0) | 2316 | if (pty_fd >= 0) |
| 2269 | { | 2317 | { |
| @@ -2301,7 +2349,7 @@ create_pty (Lisp_Object process) | |||
| 2301 | we just reopen the device (see emacs_get_tty_pgrp) as this is | 2349 | we just reopen the device (see emacs_get_tty_pgrp) as this is |
| 2302 | more portable (see USG_SUBTTY_WORKS above). */ | 2350 | more portable (see USG_SUBTTY_WORKS above). */ |
| 2303 | 2351 | ||
| 2304 | p->pty_flag = 1; | 2352 | p->pty_in = p->pty_out = true; |
| 2305 | pset_status (p, Qrun); | 2353 | pset_status (p, Qrun); |
| 2306 | setup_process_coding_systems (process); | 2354 | setup_process_coding_systems (process); |
| 2307 | 2355 | ||
| @@ -2412,7 +2460,7 @@ usage: (make-pipe-process &rest ARGS) */) | |||
| 2412 | p->kill_without_query = 1; | 2460 | p->kill_without_query = 1; |
| 2413 | if (tem = plist_get (contact, QCstop), !NILP (tem)) | 2461 | if (tem = plist_get (contact, QCstop), !NILP (tem)) |
| 2414 | pset_command (p, Qt); | 2462 | pset_command (p, Qt); |
| 2415 | eassert (! p->pty_flag); | 2463 | eassert (! p->pty_in && ! p->pty_out); |
| 2416 | 2464 | ||
| 2417 | if (!EQ (p->command, Qt) | 2465 | if (!EQ (p->command, Qt) |
| 2418 | && !EQ (p->filter, Qt)) | 2466 | && !EQ (p->filter, Qt)) |
| @@ -3147,7 +3195,7 @@ usage: (make-serial-process &rest ARGS) */) | |||
| 3147 | p->kill_without_query = 1; | 3195 | p->kill_without_query = 1; |
| 3148 | if (tem = plist_get (contact, QCstop), !NILP (tem)) | 3196 | if (tem = plist_get (contact, QCstop), !NILP (tem)) |
| 3149 | pset_command (p, Qt); | 3197 | pset_command (p, Qt); |
| 3150 | eassert (! p->pty_flag); | 3198 | eassert (! p->pty_in && ! p->pty_out); |
| 3151 | 3199 | ||
| 3152 | if (!EQ (p->command, Qt) | 3200 | if (!EQ (p->command, Qt) |
| 3153 | && !EQ (p->filter, Qt)) | 3201 | && !EQ (p->filter, Qt)) |
| @@ -6339,7 +6387,7 @@ Otherwise it discards the output. */) | |||
| 6339 | 6387 | ||
| 6340 | /* If the restriction isn't what it should be, set it. */ | 6388 | /* If the restriction isn't what it should be, set it. */ |
| 6341 | if (old_begv != BEGV || old_zv != ZV) | 6389 | if (old_begv != BEGV || old_zv != ZV) |
| 6342 | Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv), Qnil); | 6390 | Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv)); |
| 6343 | 6391 | ||
| 6344 | bset_read_only (current_buffer, old_read_only); | 6392 | bset_read_only (current_buffer, old_read_only); |
| 6345 | SET_PT_BOTH (opoint, opoint_byte); | 6393 | SET_PT_BOTH (opoint, opoint_byte); |
| @@ -6808,7 +6856,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group, | |||
| 6808 | error ("Process %s is not active", | 6856 | error ("Process %s is not active", |
| 6809 | SDATA (p->name)); | 6857 | SDATA (p->name)); |
| 6810 | 6858 | ||
| 6811 | if (!p->pty_flag) | 6859 | if (! p->pty_in) |
| 6812 | current_group = Qnil; | 6860 | current_group = Qnil; |
| 6813 | 6861 | ||
| 6814 | /* If we are using pgrps, get a pgrp number and make it negative. */ | 6862 | /* If we are using pgrps, get a pgrp number and make it negative. */ |
| @@ -7177,7 +7225,7 @@ process has been transmitted to the serial port. */) | |||
| 7177 | send_process (proc, "", 0, Qnil); | 7225 | send_process (proc, "", 0, Qnil); |
| 7178 | } | 7226 | } |
| 7179 | 7227 | ||
| 7180 | if (XPROCESS (proc)->pty_flag) | 7228 | if (XPROCESS (proc)->pty_in) |
| 7181 | send_process (proc, "\004", 1, Qnil); | 7229 | send_process (proc, "\004", 1, Qnil); |
| 7182 | else if (EQ (XPROCESS (proc)->type, Qserial)) | 7230 | else if (EQ (XPROCESS (proc)->type, Qserial)) |
| 7183 | { | 7231 | { |
diff --git a/src/process.h b/src/process.h index 392b661ce69..92baf0c4cb9 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -156,8 +156,9 @@ struct Lisp_Process | |||
| 156 | /* True means kill silently if Emacs is exited. | 156 | /* True means kill silently if Emacs is exited. |
| 157 | This is the inverse of the `query-on-exit' flag. */ | 157 | This is the inverse of the `query-on-exit' flag. */ |
| 158 | bool_bf kill_without_query : 1; | 158 | bool_bf kill_without_query : 1; |
| 159 | /* True if communicating through a pty. */ | 159 | /* True if communicating through a pty for input or output. */ |
| 160 | bool_bf pty_flag : 1; | 160 | bool_bf pty_in : 1; |
| 161 | bool_bf pty_out : 1; | ||
| 161 | /* Flag to set coding-system of the process buffer from the | 162 | /* Flag to set coding-system of the process buffer from the |
| 162 | coding_system used to decode process output. */ | 163 | coding_system used to decode process output. */ |
| 163 | bool_bf inherit_coding_system_flag : 1; | 164 | bool_bf inherit_coding_system_flag : 1; |
diff --git a/src/puresize.h b/src/puresize.h index 5516747ac2b..4b746924bb1 100644 --- a/src/puresize.h +++ b/src/puresize.h | |||
| @@ -47,7 +47,7 @@ INLINE_HEADER_BEGIN | |||
| 47 | #endif | 47 | #endif |
| 48 | 48 | ||
| 49 | #ifndef BASE_PURESIZE | 49 | #ifndef BASE_PURESIZE |
| 50 | #define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA) | 50 | #define BASE_PURESIZE (2750000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA) |
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | /* Increase BASE_PURESIZE by a ratio depending on the machine's word size. */ | 53 | /* Increase BASE_PURESIZE by a ratio depending on the machine's word size. */ |
diff --git a/src/sysdep.c b/src/sysdep.c index c1545622dfc..efd9638b07a 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -3169,7 +3169,8 @@ list_system_processes (void) | |||
| 3169 | 3169 | ||
| 3170 | #endif /* !defined (WINDOWSNT) */ | 3170 | #endif /* !defined (WINDOWSNT) */ |
| 3171 | 3171 | ||
| 3172 | #if defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__ | 3172 | #if (HAVE_GETRUSAGE \ |
| 3173 | || defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__) | ||
| 3173 | 3174 | ||
| 3174 | static Lisp_Object | 3175 | static Lisp_Object |
| 3175 | make_lisp_s_us (time_t s, long us) | 3176 | make_lisp_s_us (time_t s, long us) |
| @@ -4276,7 +4277,7 @@ does the same thing as `current-time'. */) | |||
| 4276 | usecs -= 1000000; | 4277 | usecs -= 1000000; |
| 4277 | secs++; | 4278 | secs++; |
| 4278 | } | 4279 | } |
| 4279 | return make_lisp_time (make_timespec (secs, usecs * 1000)); | 4280 | return make_lisp_s_us (secs, usecs); |
| 4280 | #else /* ! HAVE_GETRUSAGE */ | 4281 | #else /* ! HAVE_GETRUSAGE */ |
| 4281 | #ifdef WINDOWSNT | 4282 | #ifdef WINDOWSNT |
| 4282 | return w32_get_internal_run_time (); | 4283 | return w32_get_internal_run_time (); |
diff --git a/src/timefns.c b/src/timefns.c index 9df50eaecc3..1112f174763 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -387,9 +387,9 @@ enum { flt_radix_power_size = DBL_MANT_DIG - DBL_MIN_EXP + 1 }; | |||
| 387 | equals FLT_RADIX**P. */ | 387 | equals FLT_RADIX**P. */ |
| 388 | static Lisp_Object flt_radix_power; | 388 | static Lisp_Object flt_radix_power; |
| 389 | 389 | ||
| 390 | /* Convert T into an Emacs time *RESULT, truncating toward minus infinity. | 390 | /* Convert the finite number T into an Emacs time *RESULT, truncating |
| 391 | Return zero if successful, an error number otherwise. */ | 391 | toward minus infinity. Signal an error if unsuccessful. */ |
| 392 | static int | 392 | static void |
| 393 | decode_float_time (double t, struct lisp_time *result) | 393 | decode_float_time (double t, struct lisp_time *result) |
| 394 | { | 394 | { |
| 395 | Lisp_Object ticks, hz; | 395 | Lisp_Object ticks, hz; |
| @@ -401,6 +401,7 @@ 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 | eassume (scale < flt_radix_power_size); | ||
| 404 | 405 | ||
| 405 | if (scale < 0) | 406 | if (scale < 0) |
| 406 | { | 407 | { |
| @@ -412,8 +413,6 @@ decode_float_time (double t, struct lisp_time *result) | |||
| 412 | which is typically better than signaling overflow. */ | 413 | which is typically better than signaling overflow. */ |
| 413 | scale = 0; | 414 | scale = 0; |
| 414 | } | 415 | } |
| 415 | else if (flt_radix_power_size <= scale) | ||
| 416 | return isnan (t) ? EDOM : EOVERFLOW; | ||
| 417 | 416 | ||
| 418 | /* Compute TICKS, HZ such that TICKS / HZ exactly equals T, where HZ is | 417 | /* Compute TICKS, HZ such that TICKS / HZ exactly equals T, where HZ is |
| 419 | T's frequency or 1, whichever is greater. Here, “frequency” means | 418 | T's frequency or 1, whichever is greater. Here, “frequency” means |
| @@ -431,7 +430,6 @@ decode_float_time (double t, struct lisp_time *result) | |||
| 431 | } | 430 | } |
| 432 | result->ticks = ticks; | 431 | result->ticks = ticks; |
| 433 | result->hz = hz; | 432 | result->hz = hz; |
| 434 | return 0; | ||
| 435 | } | 433 | } |
| 436 | 434 | ||
| 437 | /* Make a 4-element timestamp (HI LO US PS) from TICKS and HZ. | 435 | /* Make a 4-element timestamp (HI LO US PS) from TICKS and HZ. |
| @@ -705,7 +703,7 @@ enum timeform | |||
| 705 | TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ | 703 | TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ |
| 706 | }; | 704 | }; |
| 707 | 705 | ||
| 708 | /* From the valid form FORM and the time components HIGH, LOW, USEC | 706 | /* From the non-float form FORM and the time components HIGH, LOW, USEC |
| 709 | and PSEC, generate the corresponding time value. If LOW is | 707 | and PSEC, generate the corresponding time value. If LOW is |
| 710 | floating point, the other components should be zero and FORM should | 708 | floating point, the other components should be zero and FORM should |
| 711 | not be TIMEFORM_TICKS_HZ. | 709 | not be TIMEFORM_TICKS_HZ. |
| @@ -734,16 +732,7 @@ decode_time_components (enum timeform form, | |||
| 734 | return EINVAL; | 732 | return EINVAL; |
| 735 | 733 | ||
| 736 | case TIMEFORM_FLOAT: | 734 | case TIMEFORM_FLOAT: |
| 737 | { | 735 | eassume (false); |
| 738 | double t = XFLOAT_DATA (low); | ||
| 739 | if (result) | ||
| 740 | return decode_float_time (t, result); | ||
| 741 | else | ||
| 742 | { | ||
| 743 | *dresult = t; | ||
| 744 | return 0; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | 736 | ||
| 748 | case TIMEFORM_NIL: | 737 | case TIMEFORM_NIL: |
| 749 | return decode_ticks_hz (timespec_ticks (current_timespec ()), | 738 | return decode_ticks_hz (timespec_ticks (current_timespec ()), |
| @@ -830,7 +819,16 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, | |||
| 830 | if (NILP (specified_time)) | 819 | if (NILP (specified_time)) |
| 831 | form = TIMEFORM_NIL; | 820 | form = TIMEFORM_NIL; |
| 832 | else if (FLOATP (specified_time)) | 821 | else if (FLOATP (specified_time)) |
| 833 | form = TIMEFORM_FLOAT; | 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 | } | ||
| 834 | else if (CONSP (specified_time)) | 832 | else if (CONSP (specified_time)) |
| 835 | { | 833 | { |
| 836 | high = XCAR (specified_time); | 834 | high = XCAR (specified_time); |
| @@ -878,7 +876,7 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only, | |||
| 878 | return form; | 876 | return form; |
| 879 | } | 877 | } |
| 880 | 878 | ||
| 881 | /* Convert a Lisp timestamp SPECIFIED_TIME to double. | 879 | /* Convert a non-float Lisp timestamp SPECIFIED_TIME to double. |
| 882 | Signal an error if unsuccessful. */ | 880 | Signal an error if unsuccessful. */ |
| 883 | double | 881 | double |
| 884 | float_time (Lisp_Object specified_time) | 882 | float_time (Lisp_Object specified_time) |
| @@ -1074,27 +1072,9 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1074 | static Lisp_Object | 1072 | static Lisp_Object |
| 1075 | time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | 1073 | time_arith (Lisp_Object a, Lisp_Object b, bool subtract) |
| 1076 | { | 1074 | { |
| 1077 | if (FLOATP (a) && !isfinite (XFLOAT_DATA (a))) | ||
| 1078 | { | ||
| 1079 | double da = XFLOAT_DATA (a); | ||
| 1080 | double db = float_time (b); | ||
| 1081 | return make_float (subtract ? da - db : da + db); | ||
| 1082 | } | ||
| 1083 | enum timeform aform, bform; | 1075 | enum timeform aform, bform; |
| 1084 | struct lisp_time ta = lisp_time_struct (a, &aform); | 1076 | struct lisp_time ta = lisp_time_struct (a, &aform); |
| 1085 | 1077 | struct lisp_time tb = lisp_time_struct (b, &bform); | |
| 1086 | if (FLOATP (b) && !isfinite (XFLOAT_DATA (b))) | ||
| 1087 | return subtract ? make_float (-XFLOAT_DATA (b)) : b; | ||
| 1088 | |||
| 1089 | /* Subtract nil from nil correctly, and handle other eq values | ||
| 1090 | quicker while we're at it. Compare here rather than earlier, to | ||
| 1091 | handle NaNs and check formats. */ | ||
| 1092 | struct lisp_time tb; | ||
| 1093 | if (BASE_EQ (a, b)) | ||
| 1094 | bform = aform, tb = ta; | ||
| 1095 | else | ||
| 1096 | tb = lisp_time_struct (b, &bform); | ||
| 1097 | |||
| 1098 | Lisp_Object ticks, hz; | 1078 | Lisp_Object ticks, hz; |
| 1099 | 1079 | ||
| 1100 | if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)) | 1080 | if (FASTER_TIMEFNS && BASE_EQ (ta.hz, tb.hz)) |
| @@ -1201,30 +1181,32 @@ See `format-time-string' for the various forms of a time value. | |||
| 1201 | For example, nil stands for the current time. */) | 1181 | For example, nil stands for the current time. */) |
| 1202 | (Lisp_Object a, Lisp_Object b) | 1182 | (Lisp_Object a, Lisp_Object b) |
| 1203 | { | 1183 | { |
| 1184 | /* Subtract nil from nil correctly, and handle other eq values | ||
| 1185 | quicker while we're at it. This means (time-subtract X X) does | ||
| 1186 | not signal an error if X is not a valid time value, but that's OK. */ | ||
| 1187 | if (BASE_EQ (a, b)) | ||
| 1188 | return timespec_to_lisp ((struct timespec) {0}); | ||
| 1189 | |||
| 1204 | return time_arith (a, b, true); | 1190 | return time_arith (a, b, true); |
| 1205 | } | 1191 | } |
| 1206 | 1192 | ||
| 1207 | /* Return negative, 0, positive if a < b, a == b, a > b respectively. | 1193 | /* Return negative, 0, positive if A < B, A == B, A > B respectively. |
| 1208 | Return positive if either a or b is a NaN; this is good enough | 1194 | A and B should be Lisp time values. */ |
| 1209 | for the current callers. */ | 1195 | static EMACS_INT |
| 1210 | static int | ||
| 1211 | time_cmp (Lisp_Object a, Lisp_Object b) | 1196 | time_cmp (Lisp_Object a, Lisp_Object b) |
| 1212 | { | 1197 | { |
| 1213 | if ((FLOATP (a) && !isfinite (XFLOAT_DATA (a))) | ||
| 1214 | || (FLOATP (b) && !isfinite (XFLOAT_DATA (b)))) | ||
| 1215 | { | ||
| 1216 | double da = FLOATP (a) ? XFLOAT_DATA (a) : 0; | ||
| 1217 | double db = FLOATP (b) ? XFLOAT_DATA (b) : 0; | ||
| 1218 | return da < db ? -1 : da != db; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | /* Compare nil to nil correctly, and handle other eq values quicker | 1198 | /* Compare nil to nil correctly, and handle other eq values quicker |
| 1222 | while we're at it. Compare here rather than earlier, to handle | 1199 | while we're at it. This means (time-equal-p X X) does not signal |
| 1223 | NaNs. This means (time-equal-p X X) does not signal an error if | 1200 | an error if X is not a valid time value, but that's OK. */ |
| 1224 | X is not a valid time value, but that's OK. */ | ||
| 1225 | if (BASE_EQ (a, b)) | 1201 | if (BASE_EQ (a, b)) |
| 1226 | return 0; | 1202 | return 0; |
| 1227 | 1203 | ||
| 1204 | /* 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. */ | ||
| 1206 | if (FASTER_TIMEFNS && CONSP (a) && CONSP (b) && BASE_EQ (XCDR (a), XCDR (b)) | ||
| 1207 | && FIXNUMP (XCAR (a)) && FIXNUMP (XCAR (b))) | ||
| 1208 | return XFIXNUM (XCAR (a)) - XFIXNUM (XCAR (b)); | ||
| 1209 | |||
| 1228 | /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing | 1210 | /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing |
| 1229 | ATICKS * BHZ to BTICKS * AHZ. */ | 1211 | ATICKS * BHZ to BTICKS * AHZ. */ |
| 1230 | struct lisp_time ta = lisp_time_struct (a, 0); | 1212 | struct lisp_time ta = lisp_time_struct (a, 0); |
| @@ -1258,7 +1240,9 @@ DEFUN ("time-equal-p", Ftime_equal_p, Stime_equal_p, 2, 2, 0, | |||
| 1258 | See `format-time-string' for the various forms of a time value. */) | 1240 | See `format-time-string' for the various forms of a time value. */) |
| 1259 | (Lisp_Object a, Lisp_Object b) | 1241 | (Lisp_Object a, Lisp_Object b) |
| 1260 | { | 1242 | { |
| 1261 | return time_cmp (a, b) == 0 ? Qt : Qnil; | 1243 | /* A nil arg compares unequal to a non-nil arg. This also saves the |
| 1244 | expense of current_timespec if either arg is nil. */ | ||
| 1245 | return NILP (a) == NILP (b) && time_cmp (a, b) == 0 ? Qt : Qnil; | ||
| 1262 | } | 1246 | } |
| 1263 | 1247 | ||
| 1264 | 1248 | ||
| @@ -1269,11 +1253,12 @@ instead of the current time. See `format-time-string' for the various | |||
| 1269 | forms of a time value. | 1253 | forms of a time value. |
| 1270 | 1254 | ||
| 1271 | WARNING: Since the result is floating point, it may not be exact. | 1255 | WARNING: Since the result is floating point, it may not be exact. |
| 1272 | If precise time stamps are required, use either `encode-time', | 1256 | If precise time stamps are required, use either `time-convert', |
| 1273 | or (if you need time as a string) `format-time-string'. */) | 1257 | or (if you need time as a string) `format-time-string'. */) |
| 1274 | (Lisp_Object specified_time) | 1258 | (Lisp_Object specified_time) |
| 1275 | { | 1259 | { |
| 1276 | return make_float (float_time (specified_time)); | 1260 | return (FLOATP (specified_time) ? specified_time |
| 1261 | : make_float (float_time (specified_time))); | ||
| 1277 | } | 1262 | } |
| 1278 | 1263 | ||
| 1279 | /* Write information into buffer S of size MAXSIZE, according to the | 1264 | /* Write information into buffer S of size MAXSIZE, according to the |
diff --git a/src/w32fns.c b/src/w32fns.c index 5e42a1df6ff..28d13a68d45 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -10508,6 +10508,7 @@ frame_parm_handler w32_frame_parm_handlers[] = | |||
| 10508 | 0, /* x_set_override_redirect */ | 10508 | 0, /* x_set_override_redirect */ |
| 10509 | gui_set_no_special_glyphs, | 10509 | gui_set_no_special_glyphs, |
| 10510 | gui_set_alpha_background, | 10510 | gui_set_alpha_background, |
| 10511 | 0, /* x_set_use_frame_synchronization */ | ||
| 10511 | }; | 10512 | }; |
| 10512 | 10513 | ||
| 10513 | void | 10514 | void |
diff --git a/src/xdisp.c b/src/xdisp.c index 88a489e290f..5268c359ecd 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -3229,6 +3229,7 @@ init_iterator (struct it *it, struct window *w, | |||
| 3229 | it->f = XFRAME (w->frame); | 3229 | it->f = XFRAME (w->frame); |
| 3230 | 3230 | ||
| 3231 | it->cmp_it.id = -1; | 3231 | it->cmp_it.id = -1; |
| 3232 | it->cmp_it.parent_it = it; | ||
| 3232 | 3233 | ||
| 3233 | if (max_redisplay_ticks > 0) | 3234 | if (max_redisplay_ticks > 0) |
| 3234 | update_redisplay_ticks (0, w); | 3235 | update_redisplay_ticks (0, w); |
| @@ -3413,12 +3414,6 @@ init_iterator (struct it *it, struct window *w, | |||
| 3413 | } | 3414 | } |
| 3414 | } | 3415 | } |
| 3415 | 3416 | ||
| 3416 | if (current_buffer->long_line_optimizations_p) | ||
| 3417 | { | ||
| 3418 | it->narrowed_begv = get_narrowed_begv (w, window_point (w)); | ||
| 3419 | it->narrowed_zv = get_narrowed_zv (w, window_point (w)); | ||
| 3420 | } | ||
| 3421 | |||
| 3422 | /* If a buffer position was specified, set the iterator there, | 3417 | /* If a buffer position was specified, set the iterator there, |
| 3423 | getting overlays and face properties from that position. */ | 3418 | getting overlays and face properties from that position. */ |
| 3424 | if (charpos >= BUF_BEG (current_buffer)) | 3419 | if (charpos >= BUF_BEG (current_buffer)) |
| @@ -3478,6 +3473,10 @@ init_iterator (struct it *it, struct window *w, | |||
| 3478 | &it->bidi_it); | 3473 | &it->bidi_it); |
| 3479 | } | 3474 | } |
| 3480 | 3475 | ||
| 3476 | /* This is set only when long_line_optimizations_p is non-zero | ||
| 3477 | for the current buffer. */ | ||
| 3478 | it->narrowed_begv = 0; | ||
| 3479 | |||
| 3481 | /* Compute faces etc. */ | 3480 | /* Compute faces etc. */ |
| 3482 | reseat (it, it->current.pos, true); | 3481 | reseat (it, it->current.pos, true); |
| 3483 | } | 3482 | } |
| @@ -3510,9 +3509,7 @@ ptrdiff_t | |||
| 3510 | get_narrowed_begv (struct window *w, ptrdiff_t pos) | 3509 | get_narrowed_begv (struct window *w, ptrdiff_t pos) |
| 3511 | { | 3510 | { |
| 3512 | int len = get_narrowed_len (w); | 3511 | int len = get_narrowed_len (w); |
| 3513 | ptrdiff_t begv; | 3512 | return max ((pos / len - 1) * len, BEGV); |
| 3514 | begv = max ((pos / len - 1) * len, BEGV); | ||
| 3515 | return begv == BEGV ? 0 : begv; | ||
| 3516 | } | 3513 | } |
| 3517 | 3514 | ||
| 3518 | ptrdiff_t | 3515 | ptrdiff_t |
| @@ -4397,16 +4394,16 @@ handle_fontified_prop (struct it *it) | |||
| 4397 | 4394 | ||
| 4398 | if (current_buffer->long_line_optimizations_p) | 4395 | if (current_buffer->long_line_optimizations_p) |
| 4399 | { | 4396 | { |
| 4400 | ptrdiff_t begv = it->narrowed_begv ? it->narrowed_begv : BEGV; | 4397 | ptrdiff_t begv = it->narrowed_begv; |
| 4401 | ptrdiff_t zv = it->narrowed_zv; | 4398 | ptrdiff_t zv = it->narrowed_zv; |
| 4402 | ptrdiff_t charpos = IT_CHARPOS (*it); | 4399 | ptrdiff_t charpos = IT_CHARPOS (*it); |
| 4403 | if (charpos < begv || charpos > zv) | 4400 | if (charpos < begv || charpos > zv) |
| 4404 | { | 4401 | { |
| 4405 | begv = get_narrowed_begv (it->w, charpos); | 4402 | begv = get_narrowed_begv (it->w, charpos); |
| 4406 | if (!begv) begv = BEGV; | ||
| 4407 | zv = get_narrowed_zv (it->w, charpos); | 4403 | zv = get_narrowed_zv (it->w, charpos); |
| 4408 | } | 4404 | } |
| 4409 | Fnarrow_to_region (make_fixnum (begv), make_fixnum (zv), Qt); | 4405 | narrow_to_region_internal (make_fixnum (begv), make_fixnum (zv), true); |
| 4406 | specbind (Qrestrictions_locked, Qt); | ||
| 4410 | } | 4407 | } |
| 4411 | 4408 | ||
| 4412 | /* Don't allow Lisp that runs from 'fontification-functions' | 4409 | /* Don't allow Lisp that runs from 'fontification-functions' |
| @@ -7416,7 +7413,7 @@ back_to_previous_visible_line_start (struct it *it) | |||
| 7416 | it->continuation_lines_width = 0; | 7413 | it->continuation_lines_width = 0; |
| 7417 | 7414 | ||
| 7418 | eassert (IT_CHARPOS (*it) >= BEGV); | 7415 | eassert (IT_CHARPOS (*it) >= BEGV); |
| 7419 | eassert (it->narrowed_begv > BEGV | 7416 | eassert (it->narrowed_begv > 0 /* long-line optimizations: all bets off */ |
| 7420 | || IT_CHARPOS (*it) == BEGV | 7417 | || IT_CHARPOS (*it) == BEGV |
| 7421 | || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); | 7418 | || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); |
| 7422 | CHECK_IT (it); | 7419 | CHECK_IT (it); |
| @@ -7532,6 +7529,21 @@ reseat (struct it *it, struct text_pos pos, bool force_p) | |||
| 7532 | 7529 | ||
| 7533 | reseat_1 (it, pos, false); | 7530 | reseat_1 (it, pos, false); |
| 7534 | 7531 | ||
| 7532 | if (current_buffer->long_line_optimizations_p) | ||
| 7533 | { | ||
| 7534 | if (!it->narrowed_begv) | ||
| 7535 | { | ||
| 7536 | it->narrowed_begv = get_narrowed_begv (it->w, window_point (it->w)); | ||
| 7537 | it->narrowed_zv = get_narrowed_zv (it->w, window_point (it->w)); | ||
| 7538 | } | ||
| 7539 | else if ((pos.charpos < it->narrowed_begv || pos.charpos > it->narrowed_zv) | ||
| 7540 | && (!redisplaying_p || it->line_wrap == TRUNCATE)) | ||
| 7541 | { | ||
| 7542 | it->narrowed_begv = get_narrowed_begv (it->w, pos.charpos); | ||
| 7543 | it->narrowed_zv = get_narrowed_zv (it->w, pos.charpos); | ||
| 7544 | } | ||
| 7545 | } | ||
| 7546 | |||
| 7535 | /* Determine where to check text properties. Avoid doing it | 7547 | /* Determine where to check text properties. Avoid doing it |
| 7536 | where possible because text property lookup is very expensive. */ | 7548 | where possible because text property lookup is very expensive. */ |
| 7537 | if (force_p | 7549 | if (force_p |
| @@ -8837,7 +8849,7 @@ get_visually_first_element (struct it *it) | |||
| 8837 | 8849 | ||
| 8838 | SET_WITH_NARROWED_BEGV (it, bob, | 8850 | SET_WITH_NARROWED_BEGV (it, bob, |
| 8839 | string_p ? 0 : | 8851 | string_p ? 0 : |
| 8840 | IT_BYTEPOS (*it) < BEGV ? obegv : BEGV, | 8852 | IT_CHARPOS (*it) < BEGV ? obegv : BEGV, |
| 8841 | it->narrowed_begv); | 8853 | it->narrowed_begv); |
| 8842 | 8854 | ||
| 8843 | if (STRINGP (it->string)) | 8855 | if (STRINGP (it->string)) |
| @@ -10699,6 +10711,11 @@ move_it_vertically_backward (struct it *it, int dy) | |||
| 10699 | while (nlines-- && IT_CHARPOS (*it) > pos_limit) | 10711 | while (nlines-- && IT_CHARPOS (*it) > pos_limit) |
| 10700 | back_to_previous_visible_line_start (it); | 10712 | back_to_previous_visible_line_start (it); |
| 10701 | 10713 | ||
| 10714 | /* Move one line more back, for the (rare) situation where we have | ||
| 10715 | bidi-reordered continued lines, and we start from the top-most | ||
| 10716 | screen line, which is the last in logical order. */ | ||
| 10717 | if (it->bidi_p && dy == 0) | ||
| 10718 | back_to_previous_visible_line_start (it); | ||
| 10702 | /* Reseat the iterator here. When moving backward, we don't want | 10719 | /* Reseat the iterator here. When moving backward, we don't want |
| 10703 | reseat to skip forward over invisible text, set up the iterator | 10720 | reseat to skip forward over invisible text, set up the iterator |
| 10704 | to deliver from overlay strings at the new position etc. So, | 10721 | to deliver from overlay strings at the new position etc. So, |
| @@ -10772,7 +10789,7 @@ move_it_vertically_backward (struct it *it, int dy) | |||
| 10772 | dec_both (&cp, &bp); | 10789 | dec_both (&cp, &bp); |
| 10773 | SET_WITH_NARROWED_BEGV (it, cp, | 10790 | SET_WITH_NARROWED_BEGV (it, cp, |
| 10774 | find_newline_no_quit (cp, bp, -1, NULL), | 10791 | find_newline_no_quit (cp, bp, -1, NULL), |
| 10775 | it->narrowed_begv); | 10792 | get_closer_narrowed_begv (it->w, IT_CHARPOS (*it))); |
| 10776 | move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS); | 10793 | move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS); |
| 10777 | } | 10794 | } |
| 10778 | bidi_unshelve_cache (it3data, true); | 10795 | bidi_unshelve_cache (it3data, true); |
| @@ -10950,6 +10967,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) | |||
| 10950 | position. This may actually move vertically backwards, | 10967 | position. This may actually move vertically backwards, |
| 10951 | in case of overlays, so adjust dvpos accordingly. */ | 10968 | in case of overlays, so adjust dvpos accordingly. */ |
| 10952 | dvpos += it->vpos; | 10969 | dvpos += it->vpos; |
| 10970 | start_charpos = IT_CHARPOS (*it); | ||
| 10953 | move_it_vertically_backward (it, 0); | 10971 | move_it_vertically_backward (it, 0); |
| 10954 | dvpos -= it->vpos; | 10972 | dvpos -= it->vpos; |
| 10955 | 10973 | ||
| @@ -11003,7 +11021,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) | |||
| 11003 | SAVE_IT (it2, *it, it2data); | 11021 | SAVE_IT (it2, *it, it2data); |
| 11004 | move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS); | 11022 | move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS); |
| 11005 | /* Move back again if we got too far ahead. */ | 11023 | /* Move back again if we got too far ahead. */ |
| 11006 | if (IT_CHARPOS (*it) >= start_charpos) | 11024 | if (it->vpos - it2.vpos > delta) |
| 11007 | RESTORE_IT (it, &it2, it2data); | 11025 | RESTORE_IT (it, &it2, it2data); |
| 11008 | else | 11026 | else |
| 11009 | bidi_unshelve_cache (it2data, true); | 11027 | bidi_unshelve_cache (it2data, true); |
| @@ -18115,8 +18133,8 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp) | |||
| 18115 | { | 18133 | { |
| 18116 | specpdl_ref count = SPECPDL_INDEX (); | 18134 | specpdl_ref count = SPECPDL_INDEX (); |
| 18117 | specbind (Qinhibit_quit, Qt); | 18135 | specbind (Qinhibit_quit, Qt); |
| 18118 | run_hook_with_args_2 (Qwindow_scroll_functions, window, | 18136 | safe_run_hooks_2 |
| 18119 | make_fixnum (CHARPOS (startp))); | 18137 | (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp))); |
| 18120 | unbind_to (count, Qnil); | 18138 | unbind_to (count, Qnil); |
| 18121 | SET_TEXT_POS_FROM_MARKER (startp, w->start); | 18139 | SET_TEXT_POS_FROM_MARKER (startp, w->start); |
| 18122 | /* In case the hook functions switch buffers. */ | 18140 | /* In case the hook functions switch buffers. */ |
| @@ -18825,6 +18843,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, | |||
| 18825 | { | 18843 | { |
| 18826 | /* Cursor has to be moved backward. Note that PT >= | 18844 | /* Cursor has to be moved backward. Note that PT >= |
| 18827 | CHARPOS (startp) because of the outer if-statement. */ | 18845 | CHARPOS (startp) because of the outer if-statement. */ |
| 18846 | struct glyph_row *row0 = row; | ||
| 18847 | |||
| 18828 | while (!row->mode_line_p | 18848 | while (!row->mode_line_p |
| 18829 | && (MATRIX_ROW_START_CHARPOS (row) > PT | 18849 | && (MATRIX_ROW_START_CHARPOS (row) > PT |
| 18830 | || (MATRIX_ROW_START_CHARPOS (row) == PT | 18850 | || (MATRIX_ROW_START_CHARPOS (row) == PT |
| @@ -18839,6 +18859,23 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, | |||
| 18839 | --row; | 18859 | --row; |
| 18840 | } | 18860 | } |
| 18841 | 18861 | ||
| 18862 | /* With bidi-reordered rows we can have buffer positions | ||
| 18863 | _decrease_ when going down by rows. If we haven't | ||
| 18864 | found our row in the loop above, give it another try | ||
| 18865 | now going in the other direction from the original row. */ | ||
| 18866 | if (!(MATRIX_ROW_START_CHARPOS (row) <= PT | ||
| 18867 | && PT <= MATRIX_ROW_END_CHARPOS (row)) | ||
| 18868 | && row0->continued_p) | ||
| 18869 | { | ||
| 18870 | row = row0; | ||
| 18871 | while (MATRIX_ROW_START_CHARPOS (row) > PT | ||
| 18872 | && MATRIX_ROW_BOTTOM_Y (row) < last_y) | ||
| 18873 | { | ||
| 18874 | eassert (row->enabled_p); | ||
| 18875 | ++row; | ||
| 18876 | } | ||
| 18877 | } | ||
| 18878 | |||
| 18842 | /* Consider the following case: Window starts at BEGV, | 18879 | /* Consider the following case: Window starts at BEGV, |
| 18843 | there is invisible, intangible text at BEGV, so that | 18880 | there is invisible, intangible text at BEGV, so that |
| 18844 | display starts at some point START > BEGV. It can | 18881 | display starts at some point START > BEGV. It can |
| @@ -18862,9 +18899,16 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, | |||
| 18862 | && !cursor_row_p (row)) | 18899 | && !cursor_row_p (row)) |
| 18863 | ++row; | 18900 | ++row; |
| 18864 | 18901 | ||
| 18865 | /* If within the scroll margin, scroll. */ | 18902 | /* If within the scroll margin, either the top one or |
| 18866 | if (row->y < top_scroll_margin | 18903 | the bottom one, scroll. */ |
| 18867 | && CHARPOS (startp) != BEGV) | 18904 | if ((row->y < top_scroll_margin |
| 18905 | && CHARPOS (startp) != BEGV) | ||
| 18906 | || MATRIX_ROW_BOTTOM_Y (row) > last_y | ||
| 18907 | || PT > MATRIX_ROW_END_CHARPOS (row) | ||
| 18908 | || (MATRIX_ROW_BOTTOM_Y (row) == last_y | ||
| 18909 | && PT == MATRIX_ROW_END_CHARPOS (row) | ||
| 18910 | && !row->ends_at_zv_p | ||
| 18911 | && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))) | ||
| 18868 | scroll_p = true; | 18912 | scroll_p = true; |
| 18869 | } | 18913 | } |
| 18870 | else | 18914 | else |
| @@ -19448,7 +19492,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) | |||
| 19448 | { | 19492 | { |
| 19449 | ptrdiff_t cur, next, found, max = 0, threshold; | 19493 | ptrdiff_t cur, next, found, max = 0, threshold; |
| 19450 | threshold = XFIXNUM (Vlong_line_threshold); | 19494 | threshold = XFIXNUM (Vlong_line_threshold); |
| 19451 | for (cur = 1; cur < Z; cur = next) | 19495 | for (cur = BEG; cur < Z; cur = next) |
| 19452 | { | 19496 | { |
| 19453 | next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1, | 19497 | next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1, |
| 19454 | &found, NULL, true); | 19498 | &found, NULL, true); |
diff --git a/src/xfns.c b/src/xfns.c index 1ae615fad44..2845ecca6a9 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -609,24 +609,24 @@ x_relative_mouse_position (struct frame *f, int *x, int *y) | |||
| 609 | 609 | ||
| 610 | block_input (); | 610 | block_input (); |
| 611 | 611 | ||
| 612 | XQueryPointer (FRAME_X_DISPLAY (f), | 612 | x_query_pointer (FRAME_X_DISPLAY (f), |
| 613 | FRAME_DISPLAY_INFO (f)->root_window, | 613 | FRAME_DISPLAY_INFO (f)->root_window, |
| 614 | 614 | ||
| 615 | /* The root window which contains the pointer. */ | 615 | /* The root window which contains the pointer. */ |
| 616 | &root, | 616 | &root, |
| 617 | 617 | ||
| 618 | /* Window pointer is on, not used */ | 618 | /* Window pointer is on, not used */ |
| 619 | &dummy_window, | 619 | &dummy_window, |
| 620 | 620 | ||
| 621 | /* The position on that root window. */ | 621 | /* The position on that root window. */ |
| 622 | x, y, | 622 | x, y, |
| 623 | 623 | ||
| 624 | /* x/y in dummy_window coordinates, not used. */ | 624 | /* x/y in dummy_window coordinates, not used. */ |
| 625 | &dummy, &dummy, | 625 | &dummy, &dummy, |
| 626 | 626 | ||
| 627 | /* Modifier keys and pointer buttons, about which | 627 | /* Modifier keys and pointer buttons, about which |
| 628 | we don't care. */ | 628 | we don't care. */ |
| 629 | (unsigned int *) &dummy); | 629 | (unsigned int *) &dummy); |
| 630 | 630 | ||
| 631 | XTranslateCoordinates (FRAME_X_DISPLAY (f), | 631 | XTranslateCoordinates (FRAME_X_DISPLAY (f), |
| 632 | 632 | ||
| @@ -1202,20 +1202,6 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 1202 | xg_set_background_color (f, bg); | 1202 | xg_set_background_color (f, bg); |
| 1203 | #endif | 1203 | #endif |
| 1204 | 1204 | ||
| 1205 | #ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with | ||
| 1206 | toolkit scroll bars. */ | ||
| 1207 | { | ||
| 1208 | Lisp_Object bar; | ||
| 1209 | for (bar = FRAME_SCROLL_BARS (f); | ||
| 1210 | !NILP (bar); | ||
| 1211 | bar = XSCROLL_BAR (bar)->next) | ||
| 1212 | { | ||
| 1213 | Window window = XSCROLL_BAR (bar)->x_window; | ||
| 1214 | XSetWindowBackground (dpy, window, bg); | ||
| 1215 | } | ||
| 1216 | } | ||
| 1217 | #endif /* USE_TOOLKIT_SCROLL_BARS */ | ||
| 1218 | |||
| 1219 | unblock_input (); | 1205 | unblock_input (); |
| 1220 | update_face_from_frame_parameter (f, Qbackground_color, arg); | 1206 | update_face_from_frame_parameter (f, Qbackground_color, arg); |
| 1221 | 1207 | ||
| @@ -2431,6 +2417,28 @@ x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | |||
| 2431 | } | 2417 | } |
| 2432 | } | 2418 | } |
| 2433 | 2419 | ||
| 2420 | static void | ||
| 2421 | x_set_use_frame_synchronization (struct frame *f, Lisp_Object arg, | ||
| 2422 | Lisp_Object oldval) | ||
| 2423 | { | ||
| 2424 | #if !defined USE_GTK && defined HAVE_XSYNC | ||
| 2425 | struct x_display_info *dpyinfo; | ||
| 2426 | |||
| 2427 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 2428 | |||
| 2429 | if (!NILP (arg) && FRAME_X_EXTENDED_COUNTER (f)) | ||
| 2430 | FRAME_X_OUTPUT (f)->use_vsync_p | ||
| 2431 | = x_wm_supports (f, dpyinfo->Xatom_net_wm_frame_drawn); | ||
| 2432 | else | ||
| 2433 | FRAME_X_OUTPUT (f)->use_vsync_p = false; | ||
| 2434 | |||
| 2435 | store_frame_param (f, Quse_frame_synchronization, | ||
| 2436 | FRAME_X_OUTPUT (f)->use_vsync_p ? Qt : Qnil); | ||
| 2437 | #else | ||
| 2438 | store_frame_param (f, Quse_frame_synchronization, Qnil); | ||
| 2439 | #endif | ||
| 2440 | } | ||
| 2441 | |||
| 2434 | 2442 | ||
| 2435 | /* Record in frame F the specified or default value according to ALIST | 2443 | /* Record in frame F the specified or default value according to ALIST |
| 2436 | of the parameter named PROP (a Lisp symbol). If no value is | 2444 | of the parameter named PROP (a Lisp symbol). If no value is |
| @@ -5149,18 +5157,20 @@ This function is an internal primitive--use `make-frame' instead. */) | |||
| 5149 | (unsigned char *) &counters, | 5157 | (unsigned char *) &counters, |
| 5150 | ((STRINGP (value) | 5158 | ((STRINGP (value) |
| 5151 | && !strcmp (SSDATA (value), "extended")) ? 2 : 1)); | 5159 | && !strcmp (SSDATA (value), "extended")) ? 2 : 1)); |
| 5152 | #endif | ||
| 5153 | 5160 | ||
| 5154 | #ifndef USE_GTK | 5161 | #if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK |
| 5155 | if (FRAME_X_EXTENDED_COUNTER (f)) | 5162 | x_sync_init_fences (f); |
| 5156 | FRAME_X_OUTPUT (f)->use_vsync_p | 5163 | #endif |
| 5157 | = x_wm_supports (f, dpyinfo->Xatom_net_wm_frame_drawn); | ||
| 5158 | #endif | 5164 | #endif |
| 5159 | } | 5165 | } |
| 5160 | #endif | 5166 | #endif |
| 5161 | 5167 | ||
| 5162 | unblock_input (); | 5168 | unblock_input (); |
| 5163 | 5169 | ||
| 5170 | /* Set whether or not frame synchronization is enabled. */ | ||
| 5171 | gui_default_parameter (f, parms, Quse_frame_synchronization, Qt, | ||
| 5172 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 5173 | |||
| 5164 | /* Works iff frame has been already mapped. */ | 5174 | /* Works iff frame has been already mapped. */ |
| 5165 | gui_default_parameter (f, parms, Qskip_taskbar, Qnil, | 5175 | gui_default_parameter (f, parms, Qskip_taskbar, Qnil, |
| 5166 | NULL, NULL, RES_TYPE_BOOLEAN); | 5176 | NULL, NULL, RES_TYPE_BOOLEAN); |
| @@ -6813,10 +6823,10 @@ selected frame's display. */) | |||
| 6813 | return Qnil; | 6823 | return Qnil; |
| 6814 | 6824 | ||
| 6815 | block_input (); | 6825 | block_input (); |
| 6816 | XQueryPointer (FRAME_X_DISPLAY (f), | 6826 | x_query_pointer (FRAME_X_DISPLAY (f), |
| 6817 | FRAME_DISPLAY_INFO (f)->root_window, | 6827 | FRAME_DISPLAY_INFO (f)->root_window, |
| 6818 | &root, &dummy_window, &x, &y, &dummy, &dummy, | 6828 | &root, &dummy_window, &x, &y, &dummy, &dummy, |
| 6819 | (unsigned int *) &dummy); | 6829 | (unsigned int *) &dummy); |
| 6820 | unblock_input (); | 6830 | unblock_input (); |
| 6821 | 6831 | ||
| 6822 | return Fcons (make_fixnum (x), make_fixnum (y)); | 6832 | return Fcons (make_fixnum (x), make_fixnum (y)); |
| @@ -8372,8 +8382,8 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, | |||
| 8372 | Lisp_Object frame, attributes, monitor, geometry; | 8382 | Lisp_Object frame, attributes, monitor, geometry; |
| 8373 | 8383 | ||
| 8374 | block_input (); | 8384 | block_input (); |
| 8375 | XQueryPointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window, | 8385 | x_query_pointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window, |
| 8376 | &root, &child, root_x, root_y, &win_x, &win_y, &pmask); | 8386 | &root, &child, root_x, root_y, &win_x, &win_y, &pmask); |
| 8377 | unblock_input (); | 8387 | unblock_input (); |
| 8378 | 8388 | ||
| 8379 | XSETFRAME (frame, f); | 8389 | XSETFRAME (frame, f); |
| @@ -9775,6 +9785,7 @@ frame_parm_handler x_frame_parm_handlers[] = | |||
| 9775 | x_set_override_redirect, | 9785 | x_set_override_redirect, |
| 9776 | gui_set_no_special_glyphs, | 9786 | gui_set_no_special_glyphs, |
| 9777 | x_set_alpha_background, | 9787 | x_set_alpha_background, |
| 9788 | x_set_use_frame_synchronization, | ||
| 9778 | x_set_shaded, | 9789 | x_set_shaded, |
| 9779 | }; | 9790 | }; |
| 9780 | 9791 | ||
diff --git a/src/xmenu.c b/src/xmenu.c index 3be0fb18766..5b8a8f77a2d 100644 --- a/src/xmenu.c +++ b/src/xmenu.c | |||
| @@ -232,6 +232,7 @@ static void | |||
| 232 | x_menu_translate_generic_event (XEvent *event) | 232 | x_menu_translate_generic_event (XEvent *event) |
| 233 | { | 233 | { |
| 234 | struct x_display_info *dpyinfo; | 234 | struct x_display_info *dpyinfo; |
| 235 | struct xi_device_t *device; | ||
| 235 | XEvent copy; | 236 | XEvent copy; |
| 236 | XIDeviceEvent *xev; | 237 | XIDeviceEvent *xev; |
| 237 | 238 | ||
| @@ -265,6 +266,16 @@ x_menu_translate_generic_event (XEvent *event) | |||
| 265 | copy.xbutton.button = xev->detail; | 266 | copy.xbutton.button = xev->detail; |
| 266 | copy.xbutton.same_screen = True; | 267 | copy.xbutton.same_screen = True; |
| 267 | 268 | ||
| 269 | device = xi_device_from_id (dpyinfo, xev->deviceid); | ||
| 270 | |||
| 271 | /* I don't know the repercussions of changing | ||
| 272 | device->grab on XI_ButtonPress events, so be safe and | ||
| 273 | only do what is necessary to prevent the grab from | ||
| 274 | being left invalid as XMenuActivate swallows | ||
| 275 | events. */ | ||
| 276 | if (device && xev->evtype == XI_ButtonRelease) | ||
| 277 | device->grab &= ~(1 << xev->detail); | ||
| 278 | |||
| 268 | XPutBackEvent (dpyinfo->display, ©); | 279 | XPutBackEvent (dpyinfo->display, ©); |
| 269 | 280 | ||
| 270 | break; | 281 | break; |
| @@ -2507,6 +2518,10 @@ pop_down_menu (void *arg) | |||
| 2507 | struct pop_down_menu *data = arg; | 2518 | struct pop_down_menu *data = arg; |
| 2508 | struct frame *f = data->frame; | 2519 | struct frame *f = data->frame; |
| 2509 | XMenu *menu = data->menu; | 2520 | XMenu *menu = data->menu; |
| 2521 | #ifdef HAVE_XINPUT2 | ||
| 2522 | int i; | ||
| 2523 | struct xi_device_t *device; | ||
| 2524 | #endif | ||
| 2510 | 2525 | ||
| 2511 | block_input (); | 2526 | block_input (); |
| 2512 | #ifndef MSDOS | 2527 | #ifndef MSDOS |
| @@ -2526,6 +2541,17 @@ pop_down_menu (void *arg) | |||
| 2526 | results, and it is a pain to ask which are actually held now. */ | 2541 | results, and it is a pain to ask which are actually held now. */ |
| 2527 | FRAME_DISPLAY_INFO (f)->grabbed = 0; | 2542 | FRAME_DISPLAY_INFO (f)->grabbed = 0; |
| 2528 | 2543 | ||
| 2544 | #ifdef HAVE_XINPUT2 | ||
| 2545 | /* Likewise for XI grabs when the mouse is released on top of the | ||
| 2546 | menu itself. */ | ||
| 2547 | |||
| 2548 | for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i) | ||
| 2549 | { | ||
| 2550 | device = &FRAME_DISPLAY_INFO (f)->devices[i]; | ||
| 2551 | device->grab = 0; | ||
| 2552 | } | ||
| 2553 | #endif | ||
| 2554 | |||
| 2529 | #endif /* HAVE_X_WINDOWS */ | 2555 | #endif /* HAVE_X_WINDOWS */ |
| 2530 | 2556 | ||
| 2531 | unblock_input (); | 2557 | unblock_input (); |
diff --git a/src/xsettings.c b/src/xsettings.c index c29a844e0a8..9c60ff825a4 100644 --- a/src/xsettings.c +++ b/src/xsettings.c | |||
| @@ -964,9 +964,10 @@ read_and_apply_settings (Display_Info *dpyinfo, bool send_event_p) | |||
| 964 | #endif | 964 | #endif |
| 965 | 965 | ||
| 966 | #ifndef HAVE_PGTK | 966 | #ifndef HAVE_PGTK |
| 967 | /* Check if EVENT for the display in DPYINFO is XSettings related. */ | 967 | /* Check if EVENT for the display in DPYINFO is XSettings related. |
| 968 | Return true if it is, after performing associated side effects. */ | ||
| 968 | 969 | ||
| 969 | void | 970 | bool |
| 970 | xft_settings_event (Display_Info *dpyinfo, const XEvent *event) | 971 | xft_settings_event (Display_Info *dpyinfo, const XEvent *event) |
| 971 | { | 972 | { |
| 972 | bool check_window_p = false, apply_settings_p = false; | 973 | bool check_window_p = false, apply_settings_p = false; |
| @@ -1004,6 +1005,8 @@ xft_settings_event (Display_Info *dpyinfo, const XEvent *event) | |||
| 1004 | 1005 | ||
| 1005 | if (apply_settings_p) | 1006 | if (apply_settings_p) |
| 1006 | read_and_apply_settings (dpyinfo, true); | 1007 | read_and_apply_settings (dpyinfo, true); |
| 1008 | |||
| 1009 | return check_window_p || apply_settings_p; | ||
| 1007 | } | 1010 | } |
| 1008 | #endif | 1011 | #endif |
| 1009 | 1012 | ||
diff --git a/src/xsettings.h b/src/xsettings.h index 5e5df37062b..833c2b367dc 100644 --- a/src/xsettings.h +++ b/src/xsettings.h | |||
| @@ -36,7 +36,7 @@ typedef struct pgtk_display_info Display_Info; | |||
| 36 | 36 | ||
| 37 | extern void xsettings_initialize (Display_Info *); | 37 | extern void xsettings_initialize (Display_Info *); |
| 38 | #ifndef HAVE_PGTK | 38 | #ifndef HAVE_PGTK |
| 39 | extern void xft_settings_event (Display_Info *, const XEvent *); | 39 | extern bool xft_settings_event (Display_Info *, const XEvent *); |
| 40 | #endif | 40 | #endif |
| 41 | extern const char *xsettings_get_system_font (void); | 41 | extern const char *xsettings_get_system_font (void); |
| 42 | #ifdef USE_LUCID | 42 | #ifdef USE_LUCID |
diff --git a/src/xterm.c b/src/xterm.c index d7d4cb418f3..48f10269dfc 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -997,6 +997,7 @@ static const struct x_atom_ref x_atom_refs[] = | |||
| 997 | ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea) | 997 | ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea) |
| 998 | ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request) | 998 | ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request) |
| 999 | ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter) | 999 | ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter) |
| 1000 | ATOM_REFS_INIT ("_NET_WM_SYNC_FENCES", Xatom_net_wm_sync_fences) | ||
| 1000 | ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn) | 1001 | ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn) |
| 1001 | ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings) | 1002 | ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings) |
| 1002 | ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time) | 1003 | ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time) |
| @@ -2837,8 +2838,8 @@ x_dnd_free_toplevels (bool display_alive) | |||
| 2837 | struct x_client_list_window *last; | 2838 | struct x_client_list_window *last; |
| 2838 | struct x_client_list_window *tem = x_dnd_toplevels; | 2839 | struct x_client_list_window *tem = x_dnd_toplevels; |
| 2839 | ptrdiff_t n_windows, i, buffer_size; | 2840 | ptrdiff_t n_windows, i, buffer_size; |
| 2840 | Window *destroy_windows; | 2841 | Window *destroy_windows UNINIT; |
| 2841 | unsigned long *prev_masks; | 2842 | unsigned long *prev_masks UNINIT; |
| 2842 | specpdl_ref count; | 2843 | specpdl_ref count; |
| 2843 | Display *dpy; | 2844 | Display *dpy; |
| 2844 | struct x_display_info *dpyinfo; | 2845 | struct x_display_info *dpyinfo; |
| @@ -2847,10 +2848,6 @@ x_dnd_free_toplevels (bool display_alive) | |||
| 2847 | /* Probably called inside an IO error handler. */ | 2848 | /* Probably called inside an IO error handler. */ |
| 2848 | return; | 2849 | return; |
| 2849 | 2850 | ||
| 2850 | /* Pacify GCC. */ | ||
| 2851 | prev_masks = NULL; | ||
| 2852 | destroy_windows = NULL; | ||
| 2853 | |||
| 2854 | if (display_alive) | 2851 | if (display_alive) |
| 2855 | { | 2852 | { |
| 2856 | buffer_size = 1024; | 2853 | buffer_size = 1024; |
| @@ -2913,6 +2910,7 @@ x_dnd_free_toplevels (bool display_alive) | |||
| 2913 | 2910 | ||
| 2914 | if (n_windows) | 2911 | if (n_windows) |
| 2915 | { | 2912 | { |
| 2913 | eassume (dpyinfo); | ||
| 2916 | x_ignore_errors_for_next_request (dpyinfo); | 2914 | x_ignore_errors_for_next_request (dpyinfo); |
| 2917 | 2915 | ||
| 2918 | for (i = 0; i < n_windows; ++i) | 2916 | for (i = 0; i < n_windows; ++i) |
| @@ -4963,15 +4961,6 @@ x_xr_ensure_picture (struct frame *f) | |||
| 4963 | } | 4961 | } |
| 4964 | #endif | 4962 | #endif |
| 4965 | 4963 | ||
| 4966 | /* Remove calls to XFlush by defining XFlush to an empty replacement. | ||
| 4967 | Calls to XFlush should be unnecessary because the X output buffer | ||
| 4968 | is flushed automatically as needed by calls to XPending, | ||
| 4969 | XNextEvent, or XWindowEvent according to the XFlush man page. | ||
| 4970 | XTread_socket calls XPending. Removing XFlush improves | ||
| 4971 | performance. */ | ||
| 4972 | |||
| 4973 | #define XFlush(DISPLAY) (void) 0 | ||
| 4974 | |||
| 4975 | 4964 | ||
| 4976 | /*********************************************************************** | 4965 | /*********************************************************************** |
| 4977 | Debugging | 4966 | Debugging |
| @@ -5293,15 +5282,15 @@ xi_populate_device_from_info (struct xi_device_t *xi_device, | |||
| 5293 | * device->num_classes); | 5282 | * device->num_classes); |
| 5294 | values = NULL; | 5283 | values = NULL; |
| 5295 | #endif | 5284 | #endif |
| 5296 | #ifdef HAVE_XINPUT2_2 | ||
| 5297 | xi_device->touchpoints = NULL; | ||
| 5298 | #endif | ||
| 5299 | 5285 | ||
| 5300 | xi_device->use = device->use; | 5286 | xi_device->use = device->use; |
| 5287 | xi_device->name = build_string (device->name); | ||
| 5288 | xi_device->attachment = device->attachment; | ||
| 5289 | |||
| 5301 | #ifdef HAVE_XINPUT2_2 | 5290 | #ifdef HAVE_XINPUT2_2 |
| 5291 | xi_device->touchpoints = NULL; | ||
| 5302 | xi_device->direct_p = false; | 5292 | xi_device->direct_p = false; |
| 5303 | #endif | 5293 | #endif |
| 5304 | xi_device->name = build_string (device->name); | ||
| 5305 | 5294 | ||
| 5306 | for (c = 0; c < device->num_classes; ++c) | 5295 | for (c = 0; c < device->num_classes; ++c) |
| 5307 | { | 5296 | { |
| @@ -5405,7 +5394,7 @@ xi_populate_device_from_info (struct xi_device_t *xi_device, | |||
| 5405 | static void | 5394 | static void |
| 5406 | x_cache_xi_devices (struct x_display_info *dpyinfo) | 5395 | x_cache_xi_devices (struct x_display_info *dpyinfo) |
| 5407 | { | 5396 | { |
| 5408 | int ndevices, actual_devices; | 5397 | int ndevices, actual_devices, i; |
| 5409 | XIDeviceInfo *infos; | 5398 | XIDeviceInfo *infos; |
| 5410 | 5399 | ||
| 5411 | actual_devices = 0; | 5400 | actual_devices = 0; |
| @@ -5422,9 +5411,9 @@ x_cache_xi_devices (struct x_display_info *dpyinfo) | |||
| 5422 | return; | 5411 | return; |
| 5423 | } | 5412 | } |
| 5424 | 5413 | ||
| 5425 | dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices); | 5414 | dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices); |
| 5426 | 5415 | ||
| 5427 | for (int i = 0; i < ndevices; ++i) | 5416 | for (i = 0; i < ndevices; ++i) |
| 5428 | { | 5417 | { |
| 5429 | if (infos[i].enabled) | 5418 | if (infos[i].enabled) |
| 5430 | xi_populate_device_from_info (&dpyinfo->devices[actual_devices++], | 5419 | xi_populate_device_from_info (&dpyinfo->devices[actual_devices++], |
| @@ -6617,12 +6606,17 @@ x_if_event (Display *dpy, XEvent *event_return, | |||
| 6617 | current_time = current_timespec (); | 6606 | current_time = current_timespec (); |
| 6618 | target = timespec_add (current_time, timeout); | 6607 | target = timespec_add (current_time, timeout); |
| 6619 | 6608 | ||
| 6609 | /* Check if an event is already in the queue. If it is, avoid | ||
| 6610 | syncing. */ | ||
| 6611 | if (XCheckIfEvent (dpy, event_return, predicate, arg)) | ||
| 6612 | return 0; | ||
| 6613 | |||
| 6620 | while (true) | 6614 | while (true) |
| 6621 | { | 6615 | { |
| 6622 | /* Get events into the queue. */ | 6616 | /* Get events into the queue. */ |
| 6623 | XSync (dpy, False); | 6617 | XSync (dpy, False); |
| 6624 | 6618 | ||
| 6625 | /* Check if an event is now in the queue. */ | 6619 | /* Look for an event again. */ |
| 6626 | if (XCheckIfEvent (dpy, event_return, predicate, arg)) | 6620 | if (XCheckIfEvent (dpy, event_return, predicate, arg)) |
| 6627 | return 0; | 6621 | return 0; |
| 6628 | 6622 | ||
| @@ -6646,6 +6640,61 @@ x_if_event (Display *dpy, XEvent *event_return, | |||
| 6646 | } | 6640 | } |
| 6647 | } | 6641 | } |
| 6648 | 6642 | ||
| 6643 | /* Return the monotonic time corresponding to the high-resolution | ||
| 6644 | server timestamp TIMESTAMP. Return 0 if the necessary information | ||
| 6645 | is not available. */ | ||
| 6646 | |||
| 6647 | static uint64_t | ||
| 6648 | x_sync_get_monotonic_time (struct x_display_info *dpyinfo, | ||
| 6649 | uint64_t timestamp) | ||
| 6650 | { | ||
| 6651 | if (dpyinfo->server_time_monotonic_p) | ||
| 6652 | return timestamp; | ||
| 6653 | |||
| 6654 | /* This means we haven't yet initialized the server time offset. */ | ||
| 6655 | if (!dpyinfo->server_time_offset) | ||
| 6656 | return 0; | ||
| 6657 | |||
| 6658 | return timestamp - dpyinfo->server_time_offset; | ||
| 6659 | } | ||
| 6660 | |||
| 6661 | /* Return the current monotonic time in the same format as a | ||
| 6662 | high-resolution server timestamp. */ | ||
| 6663 | |||
| 6664 | static uint64_t | ||
| 6665 | x_sync_current_monotonic_time (void) | ||
| 6666 | { | ||
| 6667 | struct timespec time; | ||
| 6668 | |||
| 6669 | clock_gettime (CLOCK_MONOTONIC, &time); | ||
| 6670 | return time.tv_sec * 1000000 + time.tv_nsec / 1000; | ||
| 6671 | } | ||
| 6672 | |||
| 6673 | /* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took | ||
| 6674 | to draw the last frame. */ | ||
| 6675 | |||
| 6676 | static void | ||
| 6677 | x_sync_note_frame_times (struct x_display_info *dpyinfo, | ||
| 6678 | struct frame *f, XEvent *event) | ||
| 6679 | { | ||
| 6680 | uint64_t low, high, time; | ||
| 6681 | struct x_output *output; | ||
| 6682 | |||
| 6683 | low = event->xclient.data.l[2]; | ||
| 6684 | high = event->xclient.data.l[3]; | ||
| 6685 | output = FRAME_X_OUTPUT (f); | ||
| 6686 | |||
| 6687 | time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32)); | ||
| 6688 | |||
| 6689 | if (time) | ||
| 6690 | output->last_frame_time = time - output->temp_frame_time; | ||
| 6691 | |||
| 6692 | #ifdef FRAME_DEBUG | ||
| 6693 | fprintf (stderr, "Drawing the last frame took: %lu ms (%lu)\n", | ||
| 6694 | output->last_frame_time / 1000, time); | ||
| 6695 | #endif | ||
| 6696 | } | ||
| 6697 | |||
| 6649 | static Bool | 6698 | static Bool |
| 6650 | x_sync_is_frame_drawn_event (Display *dpy, XEvent *event, | 6699 | x_sync_is_frame_drawn_event (Display *dpy, XEvent *event, |
| 6651 | XPointer user_data) | 6700 | XPointer user_data) |
| @@ -6689,7 +6738,12 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) | |||
| 6689 | fprintf (stderr, "Warning: compositing manager spent more than 1 second " | 6738 | fprintf (stderr, "Warning: compositing manager spent more than 1 second " |
| 6690 | "drawing a frame. Frame synchronization has been disabled\n"); | 6739 | "drawing a frame. Frame synchronization has been disabled\n"); |
| 6691 | FRAME_X_OUTPUT (f)->use_vsync_p = false; | 6740 | FRAME_X_OUTPUT (f)->use_vsync_p = false; |
| 6741 | |||
| 6742 | /* Also change the frame parameter to reflect the new state. */ | ||
| 6743 | store_frame_param (f, Quse_frame_synchronization, Qnil); | ||
| 6692 | } | 6744 | } |
| 6745 | else | ||
| 6746 | x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event); | ||
| 6693 | 6747 | ||
| 6694 | FRAME_X_WAITING_FOR_DRAW (f) = false; | 6748 | FRAME_X_WAITING_FOR_DRAW (f) = false; |
| 6695 | } | 6749 | } |
| @@ -6735,6 +6789,10 @@ x_sync_update_begin (struct frame *f) | |||
| 6735 | /* Wait for the last frame to be drawn before drawing this one. */ | 6789 | /* Wait for the last frame to be drawn before drawing this one. */ |
| 6736 | x_sync_wait_for_frame_drawn_event (f); | 6790 | x_sync_wait_for_frame_drawn_event (f); |
| 6737 | 6791 | ||
| 6792 | /* Make a note of the time at which we started to draw this | ||
| 6793 | frame. */ | ||
| 6794 | FRAME_X_OUTPUT (f)->temp_frame_time = x_sync_current_monotonic_time (); | ||
| 6795 | |||
| 6738 | /* Since Emacs needs a non-urgent redraw, ensure that value % 4 == | 6796 | /* Since Emacs needs a non-urgent redraw, ensure that value % 4 == |
| 6739 | 1. Later, add 3 to create the even counter value. */ | 6797 | 1. Later, add 3 to create the even counter value. */ |
| 6740 | if (XSyncValueLow32 (value) % 4 == 2) | 6798 | if (XSyncValueLow32 (value) % 4 == 2) |
| @@ -6755,6 +6813,85 @@ x_sync_update_begin (struct frame *f) | |||
| 6755 | FRAME_X_COUNTER_VALUE (f)); | 6813 | FRAME_X_COUNTER_VALUE (f)); |
| 6756 | } | 6814 | } |
| 6757 | 6815 | ||
| 6816 | #ifdef HAVE_XSYNCTRIGGERFENCE | ||
| 6817 | |||
| 6818 | /* Trigger the sync fence for counter VALUE immediately before a frame | ||
| 6819 | finishes. */ | ||
| 6820 | |||
| 6821 | static void | ||
| 6822 | x_sync_trigger_fence (struct frame *f, XSyncValue value) | ||
| 6823 | { | ||
| 6824 | uint64_t n, low, high, idx; | ||
| 6825 | |||
| 6826 | /* Sync fences aren't supported by the X server. */ | ||
| 6827 | if (FRAME_DISPLAY_INFO (f)->xsync_major < 3 | ||
| 6828 | || (FRAME_DISPLAY_INFO (f)->xsync_major == 3 | ||
| 6829 | && FRAME_DISPLAY_INFO (f)->xsync_minor < 1)) | ||
| 6830 | return; | ||
| 6831 | |||
| 6832 | low = XSyncValueLow32 (value); | ||
| 6833 | high = XSyncValueHigh32 (value); | ||
| 6834 | |||
| 6835 | n = low | (high << 32); | ||
| 6836 | idx = (n / 4) % 2; | ||
| 6837 | |||
| 6838 | #ifdef FRAME_DEBUG | ||
| 6839 | fprintf (stderr, "Triggering synchronization fence: %lu\n", idx); | ||
| 6840 | #endif | ||
| 6841 | |||
| 6842 | XSyncTriggerFence (FRAME_X_DISPLAY (f), | ||
| 6843 | FRAME_X_OUTPUT (f)->sync_fences[idx]); | ||
| 6844 | } | ||
| 6845 | |||
| 6846 | /* Initialize the sync fences on F. */ | ||
| 6847 | |||
| 6848 | void | ||
| 6849 | x_sync_init_fences (struct frame *f) | ||
| 6850 | { | ||
| 6851 | struct x_output *output; | ||
| 6852 | struct x_display_info *dpyinfo; | ||
| 6853 | |||
| 6854 | output = FRAME_X_OUTPUT (f); | ||
| 6855 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 6856 | |||
| 6857 | /* Sync fences aren't supported by the X server. */ | ||
| 6858 | if (dpyinfo->xsync_major < 3 | ||
| 6859 | || (dpyinfo->xsync_major == 3 | ||
| 6860 | && dpyinfo->xsync_minor < 1)) | ||
| 6861 | return; | ||
| 6862 | |||
| 6863 | output->sync_fences[0] | ||
| 6864 | = XSyncCreateFence (FRAME_X_DISPLAY (f), | ||
| 6865 | /* The drawable given below is only used to | ||
| 6866 | determine the screen on which the fence is | ||
| 6867 | created. */ | ||
| 6868 | FRAME_X_WINDOW (f), | ||
| 6869 | False); | ||
| 6870 | output->sync_fences[1] | ||
| 6871 | = XSyncCreateFence (FRAME_X_DISPLAY (f), | ||
| 6872 | FRAME_X_WINDOW (f), | ||
| 6873 | False); | ||
| 6874 | |||
| 6875 | XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), | ||
| 6876 | dpyinfo->Xatom_net_wm_sync_fences, XA_CARDINAL, | ||
| 6877 | 32, PropModeReplace, | ||
| 6878 | (unsigned char *) &output->sync_fences, 2); | ||
| 6879 | } | ||
| 6880 | |||
| 6881 | static void | ||
| 6882 | x_sync_free_fences (struct frame *f) | ||
| 6883 | { | ||
| 6884 | if (FRAME_X_OUTPUT (f)->sync_fences[0] != None) | ||
| 6885 | XSyncDestroyFence (FRAME_X_DISPLAY (f), | ||
| 6886 | FRAME_X_OUTPUT (f)->sync_fences[0]); | ||
| 6887 | |||
| 6888 | if (FRAME_X_OUTPUT (f)->sync_fences[1] != None) | ||
| 6889 | XSyncDestroyFence (FRAME_X_DISPLAY (f), | ||
| 6890 | FRAME_X_OUTPUT (f)->sync_fences[1]); | ||
| 6891 | } | ||
| 6892 | |||
| 6893 | #endif | ||
| 6894 | |||
| 6758 | /* Tell the compositing manager that FRAME has been drawn and can be | 6895 | /* Tell the compositing manager that FRAME has been drawn and can be |
| 6759 | updated. */ | 6896 | updated. */ |
| 6760 | 6897 | ||
| @@ -6787,12 +6924,15 @@ x_sync_update_finish (struct frame *f) | |||
| 6787 | if (overflow) | 6924 | if (overflow) |
| 6788 | XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0); | 6925 | XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0); |
| 6789 | 6926 | ||
| 6927 | /* Trigger any sync fences if necessary. */ | ||
| 6928 | #ifdef HAVE_XSYNCTRIGGERFENCE | ||
| 6929 | x_sync_trigger_fence (f, FRAME_X_COUNTER_VALUE (f)); | ||
| 6930 | #endif | ||
| 6931 | |||
| 6790 | XSyncSetCounter (FRAME_X_DISPLAY (f), | 6932 | XSyncSetCounter (FRAME_X_DISPLAY (f), |
| 6791 | FRAME_X_EXTENDED_COUNTER (f), | 6933 | FRAME_X_EXTENDED_COUNTER (f), |
| 6792 | FRAME_X_COUNTER_VALUE (f)); | 6934 | FRAME_X_COUNTER_VALUE (f)); |
| 6793 | 6935 | ||
| 6794 | /* FIXME: this leads to freezes if the compositing manager crashes | ||
| 6795 | in the meantime. */ | ||
| 6796 | if (FRAME_OUTPUT_DATA (f)->use_vsync_p) | 6936 | if (FRAME_OUTPUT_DATA (f)->use_vsync_p) |
| 6797 | FRAME_X_WAITING_FOR_DRAW (f) = true; | 6937 | FRAME_X_WAITING_FOR_DRAW (f) = true; |
| 6798 | } | 6938 | } |
| @@ -6805,6 +6945,8 @@ x_sync_handle_frame_drawn (struct x_display_info *dpyinfo, | |||
| 6805 | { | 6945 | { |
| 6806 | if (FRAME_OUTER_WINDOW (f) == message->xclient.window) | 6946 | if (FRAME_OUTER_WINDOW (f) == message->xclient.window) |
| 6807 | FRAME_X_WAITING_FOR_DRAW (f) = false; | 6947 | FRAME_X_WAITING_FOR_DRAW (f) = false; |
| 6948 | |||
| 6949 | x_sync_note_frame_times (dpyinfo, f, message); | ||
| 6808 | } | 6950 | } |
| 6809 | #endif | 6951 | #endif |
| 6810 | 6952 | ||
| @@ -7388,6 +7530,9 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, | |||
| 7388 | #ifndef USE_GTK | 7530 | #ifndef USE_GTK |
| 7389 | struct frame *focus_frame; | 7531 | struct frame *focus_frame; |
| 7390 | Time old_time; | 7532 | Time old_time; |
| 7533 | #if defined HAVE_XSYNC | ||
| 7534 | uint64_t monotonic_time; | ||
| 7535 | #endif | ||
| 7391 | 7536 | ||
| 7392 | focus_frame = dpyinfo->x_focus_frame; | 7537 | focus_frame = dpyinfo->x_focus_frame; |
| 7393 | old_time = dpyinfo->last_user_time; | 7538 | old_time = dpyinfo->last_user_time; |
| @@ -7400,6 +7545,28 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, | |||
| 7400 | if (!send_event || time > dpyinfo->last_user_time) | 7545 | if (!send_event || time > dpyinfo->last_user_time) |
| 7401 | dpyinfo->last_user_time = time; | 7546 | dpyinfo->last_user_time = time; |
| 7402 | 7547 | ||
| 7548 | #if defined HAVE_XSYNC && !defined USE_GTK | ||
| 7549 | if (!send_event) | ||
| 7550 | { | ||
| 7551 | /* See if the current CLOCK_MONOTONIC time is reasonably close | ||
| 7552 | to the X server time. */ | ||
| 7553 | monotonic_time = x_sync_current_monotonic_time (); | ||
| 7554 | |||
| 7555 | if (time * 1000 > monotonic_time - 500 * 1000 | ||
| 7556 | && time * 1000 < monotonic_time + 500 * 1000) | ||
| 7557 | dpyinfo->server_time_monotonic_p = true; | ||
| 7558 | else | ||
| 7559 | { | ||
| 7560 | /* Compute an offset that can be subtracted from the server | ||
| 7561 | time to estimate the monotonic time on the X server. */ | ||
| 7562 | |||
| 7563 | dpyinfo->server_time_monotonic_p = false; | ||
| 7564 | dpyinfo->server_time_offset | ||
| 7565 | = ((int64_t) time * 1000) - monotonic_time; | ||
| 7566 | } | ||
| 7567 | } | ||
| 7568 | #endif | ||
| 7569 | |||
| 7403 | #ifndef USE_GTK | 7570 | #ifndef USE_GTK |
| 7404 | /* Don't waste bandwidth if the time hasn't actually changed. */ | 7571 | /* Don't waste bandwidth if the time hasn't actually changed. */ |
| 7405 | if (focus_frame && old_time != dpyinfo->last_user_time) | 7572 | if (focus_frame && old_time != dpyinfo->last_user_time) |
| @@ -7419,6 +7586,26 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, | |||
| 7419 | #endif | 7586 | #endif |
| 7420 | } | 7587 | } |
| 7421 | 7588 | ||
| 7589 | #ifdef USE_GTK | ||
| 7590 | |||
| 7591 | static void | ||
| 7592 | x_set_gtk_user_time (struct frame *f, Time time) | ||
| 7593 | { | ||
| 7594 | GtkWidget *widget; | ||
| 7595 | GdkWindow *window; | ||
| 7596 | |||
| 7597 | widget = FRAME_GTK_OUTER_WIDGET (f); | ||
| 7598 | window = gtk_widget_get_window (widget); | ||
| 7599 | |||
| 7600 | /* This widget isn't realized yet. */ | ||
| 7601 | if (!window) | ||
| 7602 | return; | ||
| 7603 | |||
| 7604 | gdk_x11_window_set_user_time (window, time); | ||
| 7605 | } | ||
| 7606 | |||
| 7607 | #endif | ||
| 7608 | |||
| 7422 | /* Not needed on GTK because GTK handles reporting the user time | 7609 | /* Not needed on GTK because GTK handles reporting the user time |
| 7423 | itself. */ | 7610 | itself. */ |
| 7424 | 7611 | ||
| @@ -9308,9 +9495,7 @@ x_composite_image (struct glyph_string *s, Pixmap dest, | |||
| 9308 | { | 9495 | { |
| 9309 | Picture destination; | 9496 | Picture destination; |
| 9310 | XRenderPictFormat *default_format; | 9497 | XRenderPictFormat *default_format; |
| 9311 | XRenderPictureAttributes attr; | 9498 | XRenderPictureAttributes attr UNINIT; |
| 9312 | /* Pacify GCC. */ | ||
| 9313 | memset (&attr, 0, sizeof attr); | ||
| 9314 | 9499 | ||
| 9315 | default_format = FRAME_X_PICTURE_FORMAT (s->f); | 9500 | default_format = FRAME_X_PICTURE_FORMAT (s->f); |
| 9316 | destination = XRenderCreatePicture (display, dest, | 9501 | destination = XRenderCreatePicture (display, dest, |
| @@ -10466,16 +10651,12 @@ x_clear_frame (struct frame *f) | |||
| 10466 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | 10651 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); |
| 10467 | 10652 | ||
| 10468 | block_input (); | 10653 | block_input (); |
| 10469 | |||
| 10470 | font_drop_xrender_surfaces (f); | 10654 | font_drop_xrender_surfaces (f); |
| 10471 | x_clear_window (f); | 10655 | x_clear_window (f); |
| 10472 | 10656 | ||
| 10473 | /* We have to clear the scroll bars. If we have changed colors or | 10657 | /* We have to clear the scroll bars. If we have changed colors or |
| 10474 | something like that, then they should be notified. */ | 10658 | something like that, then they should be notified. */ |
| 10475 | x_scroll_bar_clear (f); | 10659 | x_scroll_bar_clear (f); |
| 10476 | |||
| 10477 | XFlush (FRAME_X_DISPLAY (f)); | ||
| 10478 | |||
| 10479 | unblock_input (); | 10660 | unblock_input (); |
| 10480 | } | 10661 | } |
| 10481 | 10662 | ||
| @@ -10853,7 +11034,6 @@ x_scroll_run (struct window *w, struct run *run) | |||
| 10853 | view->clip_bottom - view->clip_top); | 11034 | view->clip_bottom - view->clip_top); |
| 10854 | } | 11035 | } |
| 10855 | xwidget_expose (view); | 11036 | xwidget_expose (view); |
| 10856 | XFlush (dpy); | ||
| 10857 | } | 11037 | } |
| 10858 | } | 11038 | } |
| 10859 | } | 11039 | } |
| @@ -12286,6 +12466,459 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 12286 | return unbind_to (base, Qnil); | 12466 | return unbind_to (base, Qnil); |
| 12287 | } | 12467 | } |
| 12288 | 12468 | ||
| 12469 | #ifdef HAVE_XINPUT2 | ||
| 12470 | |||
| 12471 | /* Since the input extension assigns a keyboard focus to each master | ||
| 12472 | device, there is no longer a 1:1 correspondence between the | ||
| 12473 | selected frame and the focus frame immediately after the keyboard | ||
| 12474 | focus is switched to a given frame. This situation is handled by | ||
| 12475 | keeping track of each master device's focus frame, the time of the | ||
| 12476 | last interaction with that frame, and always keeping the focus on | ||
| 12477 | the most recently selected frame. We also use the pointer of the | ||
| 12478 | device that is keeping the current frame focused in functions like | ||
| 12479 | `mouse-position'. */ | ||
| 12480 | |||
| 12481 | static void | ||
| 12482 | xi_handle_focus_change (struct x_display_info *dpyinfo) | ||
| 12483 | { | ||
| 12484 | struct input_event ie; | ||
| 12485 | struct frame *focus, *new; | ||
| 12486 | struct xi_device_t *device, *source = NULL; | ||
| 12487 | ptrdiff_t i; | ||
| 12488 | Time time; | ||
| 12489 | #ifdef USE_GTK | ||
| 12490 | struct x_output *output; | ||
| 12491 | GtkWidget *widget; | ||
| 12492 | #endif | ||
| 12493 | |||
| 12494 | focus = dpyinfo->x_focus_frame; | ||
| 12495 | new = NULL; | ||
| 12496 | time = 0; | ||
| 12497 | |||
| 12498 | dpyinfo->client_pointer_device = -1; | ||
| 12499 | |||
| 12500 | for (i = 0; i < dpyinfo->num_devices; ++i) | ||
| 12501 | { | ||
| 12502 | device = &dpyinfo->devices[i]; | ||
| 12503 | |||
| 12504 | if (device->focus_frame | ||
| 12505 | && device->focus_frame_time > time) | ||
| 12506 | { | ||
| 12507 | new = device->focus_frame; | ||
| 12508 | time = device->focus_frame_time; | ||
| 12509 | source = device; | ||
| 12510 | |||
| 12511 | /* Use this device for future calls to `mouse-position' etc. | ||
| 12512 | If it is a keyboard, use its attached pointer. */ | ||
| 12513 | |||
| 12514 | if (device->use == XIMasterKeyboard) | ||
| 12515 | dpyinfo->client_pointer_device = device->attachment; | ||
| 12516 | else | ||
| 12517 | dpyinfo->client_pointer_device = device->device_id; | ||
| 12518 | } | ||
| 12519 | |||
| 12520 | if (device->focus_implicit_frame | ||
| 12521 | && device->focus_implicit_time > time) | ||
| 12522 | { | ||
| 12523 | new = device->focus_implicit_frame; | ||
| 12524 | time = device->focus_implicit_time; | ||
| 12525 | source = device; | ||
| 12526 | |||
| 12527 | /* Use this device for future calls to `mouse-position' etc. | ||
| 12528 | If it is a keyboard, use its attached pointer. */ | ||
| 12529 | |||
| 12530 | if (device->use == XIMasterKeyboard) | ||
| 12531 | dpyinfo->client_pointer_device = device->attachment; | ||
| 12532 | else | ||
| 12533 | dpyinfo->client_pointer_device = device->device_id; | ||
| 12534 | } | ||
| 12535 | } | ||
| 12536 | |||
| 12537 | if (new != focus && focus) | ||
| 12538 | { | ||
| 12539 | #ifdef HAVE_X_I18N | ||
| 12540 | if (FRAME_XIC (focus)) | ||
| 12541 | XUnsetICFocus (FRAME_XIC (focus)); | ||
| 12542 | #endif | ||
| 12543 | |||
| 12544 | #ifdef USE_GTK | ||
| 12545 | output = FRAME_X_OUTPUT (focus); | ||
| 12546 | |||
| 12547 | if (x_gtk_use_native_input) | ||
| 12548 | { | ||
| 12549 | gtk_im_context_focus_out (output->im_context); | ||
| 12550 | gtk_im_context_set_client_window (output->im_context, | ||
| 12551 | NULL); | ||
| 12552 | } | ||
| 12553 | #endif | ||
| 12554 | |||
| 12555 | EVENT_INIT (ie); | ||
| 12556 | ie.kind = FOCUS_OUT_EVENT; | ||
| 12557 | XSETFRAME (ie.frame_or_window, focus); | ||
| 12558 | |||
| 12559 | kbd_buffer_store_event (&ie); | ||
| 12560 | } | ||
| 12561 | |||
| 12562 | if (new != focus && new) | ||
| 12563 | { | ||
| 12564 | #ifdef HAVE_X_I18N | ||
| 12565 | if (FRAME_XIC (new)) | ||
| 12566 | XSetICFocus (FRAME_XIC (new)); | ||
| 12567 | #endif | ||
| 12568 | |||
| 12569 | #ifdef USE_GTK | ||
| 12570 | output = FRAME_X_OUTPUT (new); | ||
| 12571 | |||
| 12572 | if (x_gtk_use_native_input) | ||
| 12573 | { | ||
| 12574 | widget = FRAME_GTK_OUTER_WIDGET (new); | ||
| 12575 | |||
| 12576 | gtk_im_context_focus_in (output->im_context); | ||
| 12577 | gtk_im_context_set_client_window (output->im_context, | ||
| 12578 | gtk_widget_get_window (widget)); | ||
| 12579 | } | ||
| 12580 | #endif | ||
| 12581 | |||
| 12582 | EVENT_INIT (ie); | ||
| 12583 | ie.kind = FOCUS_IN_EVENT; | ||
| 12584 | ie.device = source->name; | ||
| 12585 | XSETFRAME (ie.frame_or_window, new); | ||
| 12586 | |||
| 12587 | kbd_buffer_store_event (&ie); | ||
| 12588 | } | ||
| 12589 | |||
| 12590 | x_new_focus_frame (dpyinfo, new); | ||
| 12591 | } | ||
| 12592 | |||
| 12593 | static void | ||
| 12594 | xi_focus_handle_for_device (struct x_display_info *dpyinfo, | ||
| 12595 | struct frame *mentioned_frame, | ||
| 12596 | XIEvent *base_event) | ||
| 12597 | { | ||
| 12598 | struct xi_device_t *device; | ||
| 12599 | XIEnterEvent *event; | ||
| 12600 | |||
| 12601 | /* XILeaveEvent, XIFocusInEvent, etc are just synonyms for | ||
| 12602 | XIEnterEvent. */ | ||
| 12603 | event = (XIEnterEvent *) base_event; | ||
| 12604 | device = xi_device_from_id (dpyinfo, event->deviceid); | ||
| 12605 | |||
| 12606 | if (!device) | ||
| 12607 | return; | ||
| 12608 | |||
| 12609 | switch (event->evtype) | ||
| 12610 | { | ||
| 12611 | case XI_FocusIn: | ||
| 12612 | device->focus_frame = mentioned_frame; | ||
| 12613 | device->focus_frame_time = event->time; | ||
| 12614 | break; | ||
| 12615 | |||
| 12616 | case XI_FocusOut: | ||
| 12617 | device->focus_frame = NULL; | ||
| 12618 | break; | ||
| 12619 | |||
| 12620 | case XI_Enter: | ||
| 12621 | if (!event->focus) | ||
| 12622 | break; | ||
| 12623 | |||
| 12624 | if (device->use == XIMasterPointer) | ||
| 12625 | device = xi_device_from_id (dpyinfo, device->attachment); | ||
| 12626 | |||
| 12627 | if (!device) | ||
| 12628 | break; | ||
| 12629 | |||
| 12630 | device->focus_implicit_frame = mentioned_frame; | ||
| 12631 | device->focus_implicit_time = event->time; | ||
| 12632 | break; | ||
| 12633 | |||
| 12634 | case XI_Leave: | ||
| 12635 | if (!event->focus) | ||
| 12636 | break; | ||
| 12637 | |||
| 12638 | if (device->use == XIMasterPointer) | ||
| 12639 | device = xi_device_from_id (dpyinfo, device->attachment); | ||
| 12640 | |||
| 12641 | if (!device) | ||
| 12642 | break; | ||
| 12643 | |||
| 12644 | device->focus_implicit_frame = NULL; | ||
| 12645 | break; | ||
| 12646 | } | ||
| 12647 | |||
| 12648 | xi_handle_focus_change (dpyinfo); | ||
| 12649 | } | ||
| 12650 | |||
| 12651 | static void | ||
| 12652 | xi_handle_delete_frame (struct x_display_info *dpyinfo, | ||
| 12653 | struct frame *f) | ||
| 12654 | { | ||
| 12655 | struct xi_device_t *device; | ||
| 12656 | ptrdiff_t i; | ||
| 12657 | |||
| 12658 | for (i = 0; i < dpyinfo->num_devices; ++i) | ||
| 12659 | { | ||
| 12660 | device = &dpyinfo->devices[i]; | ||
| 12661 | |||
| 12662 | if (device->focus_frame == f) | ||
| 12663 | device->focus_frame = NULL; | ||
| 12664 | |||
| 12665 | if (device->focus_implicit_frame == f) | ||
| 12666 | device->focus_implicit_frame = NULL; | ||
| 12667 | } | ||
| 12668 | } | ||
| 12669 | |||
| 12670 | /* Handle an interaction by DEVICE on frame F. TIME is the time of | ||
| 12671 | the interaction; if F isn't currently the global focus frame, but | ||
| 12672 | is the focus of DEVICE, make it the focus frame. */ | ||
| 12673 | |||
| 12674 | static void | ||
| 12675 | xi_handle_interaction (struct x_display_info *dpyinfo, | ||
| 12676 | struct frame *f, struct xi_device_t *device, | ||
| 12677 | Time time) | ||
| 12678 | { | ||
| 12679 | bool change; | ||
| 12680 | |||
| 12681 | /* If DEVICE is a pointer, use its attached keyboard device. */ | ||
| 12682 | if (device->use == XIMasterPointer) | ||
| 12683 | device = xi_device_from_id (dpyinfo, device->attachment); | ||
| 12684 | |||
| 12685 | if (!device) | ||
| 12686 | return; | ||
| 12687 | |||
| 12688 | change = false; | ||
| 12689 | |||
| 12690 | if (device->focus_frame == f) | ||
| 12691 | { | ||
| 12692 | device->focus_frame_time = time; | ||
| 12693 | change = true; | ||
| 12694 | } | ||
| 12695 | |||
| 12696 | if (device->focus_implicit_frame == f) | ||
| 12697 | { | ||
| 12698 | device->focus_implicit_time = time; | ||
| 12699 | change = true; | ||
| 12700 | } | ||
| 12701 | |||
| 12702 | /* If F isn't currently focused, update the focus state. */ | ||
| 12703 | if (change && f != dpyinfo->x_focus_frame) | ||
| 12704 | xi_handle_focus_change (dpyinfo); | ||
| 12705 | } | ||
| 12706 | |||
| 12707 | #ifdef HAVE_XINPUT2_1 | ||
| 12708 | |||
| 12709 | /* Look up a scroll valuator in DEVICE by NUMBER. */ | ||
| 12710 | |||
| 12711 | static struct xi_scroll_valuator_t * | ||
| 12712 | xi_get_scroll_valuator (struct xi_device_t *device, int number) | ||
| 12713 | { | ||
| 12714 | int i; | ||
| 12715 | |||
| 12716 | for (i = 0; i < device->scroll_valuator_count; ++i) | ||
| 12717 | { | ||
| 12718 | if (device->valuators[i].number == number) | ||
| 12719 | return &device->valuators[i]; | ||
| 12720 | } | ||
| 12721 | |||
| 12722 | return NULL; | ||
| 12723 | } | ||
| 12724 | |||
| 12725 | #endif | ||
| 12726 | |||
| 12727 | /* Handle EVENT, a DeviceChanged event. Look up the device that | ||
| 12728 | changed, and update its information with the data in EVENT. */ | ||
| 12729 | |||
| 12730 | static void | ||
| 12731 | xi_handle_device_changed (struct x_display_info *dpyinfo, | ||
| 12732 | struct xi_device_t *device, | ||
| 12733 | XIDeviceChangedEvent *event) | ||
| 12734 | { | ||
| 12735 | #ifdef HAVE_XINPUT2_1 | ||
| 12736 | XIDeviceInfo *info; | ||
| 12737 | XIScrollClassInfo *scroll; | ||
| 12738 | int i, ndevices; | ||
| 12739 | struct xi_scroll_valuator_t *valuator; | ||
| 12740 | XIValuatorClassInfo *valuator_info; | ||
| 12741 | #endif | ||
| 12742 | #ifdef HAVE_XINPUT2_2 | ||
| 12743 | struct xi_touch_point_t *tem, *last; | ||
| 12744 | XITouchClassInfo *touch; | ||
| 12745 | #endif | ||
| 12746 | |||
| 12747 | #ifdef HAVE_XINPUT2_1 | ||
| 12748 | /* When a DeviceChange event is received for a master device, we | ||
| 12749 | don't get any scroll valuators along with it. This is possibly | ||
| 12750 | an X server bug but I really don't want to dig any further, so | ||
| 12751 | fetch the scroll valuators manually. (bug#57020) */ | ||
| 12752 | |||
| 12753 | x_catch_errors (dpyinfo->display); | ||
| 12754 | info = XIQueryDevice (dpyinfo->display, event->deviceid, | ||
| 12755 | /* ndevices is always 1 if a deviceid is | ||
| 12756 | specified. If the request fails, NULL will | ||
| 12757 | be returned. */ | ||
| 12758 | &ndevices); | ||
| 12759 | x_uncatch_errors (); | ||
| 12760 | |||
| 12761 | if (info) | ||
| 12762 | { | ||
| 12763 | device->valuators = xrealloc (device->valuators, | ||
| 12764 | (info->num_classes | ||
| 12765 | * sizeof *device->valuators)); | ||
| 12766 | device->scroll_valuator_count = 0; | ||
| 12767 | #ifdef HAVE_XINPUT2_2 | ||
| 12768 | device->direct_p = false; | ||
| 12769 | #endif | ||
| 12770 | |||
| 12771 | for (i = 0; i < info->num_classes; ++i) | ||
| 12772 | { | ||
| 12773 | switch (info->classes[i]->type) | ||
| 12774 | { | ||
| 12775 | case XIScrollClass: | ||
| 12776 | scroll = (XIScrollClassInfo *) info->classes[i]; | ||
| 12777 | |||
| 12778 | valuator = &device->valuators[device->scroll_valuator_count++]; | ||
| 12779 | valuator->horizontal = (scroll->scroll_type | ||
| 12780 | == XIScrollTypeHorizontal); | ||
| 12781 | valuator->invalid_p = true; | ||
| 12782 | valuator->emacs_value = DBL_MIN; | ||
| 12783 | valuator->increment = scroll->increment; | ||
| 12784 | valuator->number = scroll->number; | ||
| 12785 | break; | ||
| 12786 | |||
| 12787 | #ifdef HAVE_XINPUT2_2 | ||
| 12788 | case XITouchClass: | ||
| 12789 | touch = (XITouchClassInfo *) info->classes[i]; | ||
| 12790 | |||
| 12791 | if (touch->mode == XIDirectTouch) | ||
| 12792 | device->direct_p = true; | ||
| 12793 | break; | ||
| 12794 | #endif | ||
| 12795 | } | ||
| 12796 | } | ||
| 12797 | |||
| 12798 | /* Restore the values of any scroll valuators that we already | ||
| 12799 | know about. */ | ||
| 12800 | |||
| 12801 | for (i = 0; i < info->num_classes; ++i) | ||
| 12802 | { | ||
| 12803 | switch (info->classes[i]->type) | ||
| 12804 | { | ||
| 12805 | case XIValuatorClass: | ||
| 12806 | valuator_info = (XIValuatorClassInfo *) info->classes[i]; | ||
| 12807 | |||
| 12808 | valuator = xi_get_scroll_valuator (device, | ||
| 12809 | valuator_info->number); | ||
| 12810 | if (valuator) | ||
| 12811 | { | ||
| 12812 | valuator->invalid_p = false; | ||
| 12813 | valuator->current_value = valuator_info->value; | ||
| 12814 | |||
| 12815 | /* Make sure that this is reset if the pointer moves | ||
| 12816 | into a window of ours. | ||
| 12817 | |||
| 12818 | Otherwise the valuator state could be left | ||
| 12819 | invalid if the DeviceChange event happened with | ||
| 12820 | the pointer outside any Emacs frame. */ | ||
| 12821 | valuator->pending_enter_reset = true; | ||
| 12822 | } | ||
| 12823 | |||
| 12824 | break; | ||
| 12825 | } | ||
| 12826 | } | ||
| 12827 | |||
| 12828 | #ifdef HAVE_XINPUT2_2 | ||
| 12829 | /* The device is no longer a DirectTouch device, so | ||
| 12830 | remove any touchpoints that we might have | ||
| 12831 | recorded. */ | ||
| 12832 | if (!device->direct_p) | ||
| 12833 | { | ||
| 12834 | tem = device->touchpoints; | ||
| 12835 | |||
| 12836 | while (tem) | ||
| 12837 | { | ||
| 12838 | last = tem; | ||
| 12839 | tem = tem->next; | ||
| 12840 | xfree (last); | ||
| 12841 | } | ||
| 12842 | |||
| 12843 | device->touchpoints = NULL; | ||
| 12844 | } | ||
| 12845 | #endif | ||
| 12846 | |||
| 12847 | XIFreeDeviceInfo (info); | ||
| 12848 | } | ||
| 12849 | #endif | ||
| 12850 | } | ||
| 12851 | |||
| 12852 | /* Remove the client-side record of every device in TO_DISABLE. | ||
| 12853 | Called while processing XI_HierarchyChanged events. We batch up | ||
| 12854 | multiple disabled devices because it is more efficient to disable | ||
| 12855 | them at once. */ | ||
| 12856 | |||
| 12857 | static void | ||
| 12858 | xi_disable_devices (struct x_display_info *dpyinfo, | ||
| 12859 | int *to_disable, int n_disabled) | ||
| 12860 | { | ||
| 12861 | struct xi_device_t *devices; | ||
| 12862 | int ndevices, i, j; | ||
| 12863 | #ifdef HAVE_XINPUT2_2 | ||
| 12864 | struct xi_touch_point_t *tem, *last; | ||
| 12865 | #endif | ||
| 12866 | |||
| 12867 | /* Don't pointlessly copy dpyinfo->devices if there are no devices | ||
| 12868 | to disable. */ | ||
| 12869 | if (!n_disabled) | ||
| 12870 | return; | ||
| 12871 | |||
| 12872 | ndevices = 0; | ||
| 12873 | devices = xzalloc (sizeof *devices * dpyinfo->num_devices); | ||
| 12874 | |||
| 12875 | /* Loop through every device currently in DPYINFO, and copy it to | ||
| 12876 | DEVICES if it is not in TO_DISABLE. Note that this function | ||
| 12877 | should be called with input blocked, since xfree can otherwise | ||
| 12878 | call GC, which will call mark_xterm with invalid state. */ | ||
| 12879 | for (i = 0; i < dpyinfo->num_devices; ++i) | ||
| 12880 | { | ||
| 12881 | for (j = 0; j < n_disabled; ++j) | ||
| 12882 | { | ||
| 12883 | if (to_disable[j] == dpyinfo->devices[i].device_id) | ||
| 12884 | { | ||
| 12885 | /* Free any scroll valuators that might be on this | ||
| 12886 | device. */ | ||
| 12887 | #ifdef HAVE_XINPUT2_1 | ||
| 12888 | xfree (dpyinfo->devices[i].valuators); | ||
| 12889 | #endif | ||
| 12890 | |||
| 12891 | /* Free any currently active touch points on this | ||
| 12892 | device. */ | ||
| 12893 | #ifdef HAVE_XINPUT2_2 | ||
| 12894 | tem = dpyinfo->devices[i].touchpoints; | ||
| 12895 | while (tem) | ||
| 12896 | { | ||
| 12897 | last = tem; | ||
| 12898 | tem = tem->next; | ||
| 12899 | xfree (last); | ||
| 12900 | } | ||
| 12901 | #endif | ||
| 12902 | |||
| 12903 | goto out; | ||
| 12904 | } | ||
| 12905 | |||
| 12906 | devices[ndevices++] = dpyinfo->devices[i]; | ||
| 12907 | |||
| 12908 | out: | ||
| 12909 | continue; | ||
| 12910 | } | ||
| 12911 | } | ||
| 12912 | |||
| 12913 | /* Free the old devices array and replace it with ndevices. */ | ||
| 12914 | xfree (dpyinfo->devices); | ||
| 12915 | |||
| 12916 | dpyinfo->devices = devices; | ||
| 12917 | dpyinfo->num_devices = ndevices; | ||
| 12918 | } | ||
| 12919 | |||
| 12920 | #endif | ||
| 12921 | |||
| 12289 | /* The focus may have changed. Figure out if it is a real focus change, | 12922 | /* The focus may have changed. Figure out if it is a real focus change, |
| 12290 | by checking both FocusIn/Out and Enter/LeaveNotify events. | 12923 | by checking both FocusIn/Out and Enter/LeaveNotify events. |
| 12291 | 12924 | ||
| @@ -12316,37 +12949,6 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame, | |||
| 12316 | } | 12949 | } |
| 12317 | break; | 12950 | break; |
| 12318 | 12951 | ||
| 12319 | #ifdef HAVE_XINPUT2 | ||
| 12320 | case GenericEvent: | ||
| 12321 | { | ||
| 12322 | XIEvent *xi_event = event->xcookie.data; | ||
| 12323 | XIEnterEvent *enter_or_focus = event->xcookie.data; | ||
| 12324 | |||
| 12325 | struct frame *focus_frame = dpyinfo->x_focus_event_frame; | ||
| 12326 | int focus_state | ||
| 12327 | = focus_frame ? focus_frame->output_data.x->focus_state : 0; | ||
| 12328 | |||
| 12329 | if (xi_event->evtype == XI_FocusIn | ||
| 12330 | || xi_event->evtype == XI_FocusOut) | ||
| 12331 | x_focus_changed ((xi_event->evtype == XI_FocusIn | ||
| 12332 | ? FocusIn : FocusOut), | ||
| 12333 | ((enter_or_focus->detail | ||
| 12334 | == XINotifyPointer) | ||
| 12335 | ? FOCUS_IMPLICIT : FOCUS_EXPLICIT), | ||
| 12336 | dpyinfo, frame, bufp); | ||
| 12337 | else if ((xi_event->evtype == XI_Enter | ||
| 12338 | || xi_event->evtype == XI_Leave) | ||
| 12339 | && (enter_or_focus->detail != XINotifyInferior) | ||
| 12340 | && enter_or_focus->focus | ||
| 12341 | && !(focus_state & FOCUS_EXPLICIT)) | ||
| 12342 | x_focus_changed ((xi_event->evtype == XI_Enter | ||
| 12343 | ? FocusIn : FocusOut), | ||
| 12344 | FOCUS_IMPLICIT, | ||
| 12345 | dpyinfo, frame, bufp); | ||
| 12346 | break; | ||
| 12347 | } | ||
| 12348 | #endif | ||
| 12349 | |||
| 12350 | case FocusIn: | 12952 | case FocusIn: |
| 12351 | case FocusOut: | 12953 | case FocusOut: |
| 12352 | /* Ignore transient focus events from hotkeys, window manager | 12954 | /* Ignore transient focus events from hotkeys, window manager |
| @@ -12692,6 +13294,68 @@ get_keysym_name (int keysym) | |||
| 12692 | return value; | 13294 | return value; |
| 12693 | } | 13295 | } |
| 12694 | 13296 | ||
| 13297 | /* Like XQueryPointer, but always use the right client pointer | ||
| 13298 | device. */ | ||
| 13299 | |||
| 13300 | Bool | ||
| 13301 | x_query_pointer (Display *dpy, Window w, Window *root_return, | ||
| 13302 | Window *child_return, int *root_x_return, | ||
| 13303 | int *root_y_return, int *win_x_return, | ||
| 13304 | int *win_y_return, unsigned int *mask_return) | ||
| 13305 | { | ||
| 13306 | Bool rc; | ||
| 13307 | #ifdef HAVE_XINPUT2 | ||
| 13308 | struct x_display_info *dpyinfo; | ||
| 13309 | bool had_errors; | ||
| 13310 | XIModifierState modifiers; | ||
| 13311 | XIButtonState buttons; | ||
| 13312 | XIGroupState group; /* Unused. */ | ||
| 13313 | double root_x, root_y, win_x, win_y; | ||
| 13314 | unsigned int state; | ||
| 13315 | #endif | ||
| 13316 | |||
| 13317 | #ifdef HAVE_XINPUT2 | ||
| 13318 | dpyinfo = x_display_info_for_display (dpy); | ||
| 13319 | if (dpyinfo && dpyinfo->client_pointer_device != -1) | ||
| 13320 | { | ||
| 13321 | /* Catch errors caused by the device going away. This is not | ||
| 13322 | very expensive, since XIQueryPointer will sync anyway. */ | ||
| 13323 | x_catch_errors (dpy); | ||
| 13324 | rc = XIQueryPointer (dpyinfo->display, | ||
| 13325 | dpyinfo->client_pointer_device, | ||
| 13326 | w, root_return, child_return, | ||
| 13327 | &root_x, &root_y, &win_x, &win_y, | ||
| 13328 | &buttons, &modifiers, &group); | ||
| 13329 | had_errors = x_had_errors_p (dpy); | ||
| 13330 | x_uncatch_errors_after_check (); | ||
| 13331 | |||
| 13332 | if (had_errors) | ||
| 13333 | rc = XQueryPointer (dpyinfo->display, w, root_return, | ||
| 13334 | child_return, root_x_return, | ||
| 13335 | root_y_return, win_x_return, | ||
| 13336 | win_y_return, mask_return); | ||
| 13337 | else | ||
| 13338 | { | ||
| 13339 | state = 0; | ||
| 13340 | |||
| 13341 | xi_convert_button_state (&buttons, &state); | ||
| 13342 | *mask_return = state | modifiers.effective; | ||
| 13343 | |||
| 13344 | *root_x_return = lrint (root_x); | ||
| 13345 | *root_y_return = lrint (root_y); | ||
| 13346 | *win_x_return = lrint (win_x); | ||
| 13347 | *win_y_return = lrint (win_y); | ||
| 13348 | } | ||
| 13349 | } | ||
| 13350 | else | ||
| 13351 | #endif | ||
| 13352 | rc = XQueryPointer (dpy, w, root_return, child_return, | ||
| 13353 | root_x_return, root_y_return, win_x_return, | ||
| 13354 | win_y_return, mask_return); | ||
| 13355 | |||
| 13356 | return rc; | ||
| 13357 | } | ||
| 13358 | |||
| 12695 | /* Mouse clicks and mouse movement. Rah. | 13359 | /* Mouse clicks and mouse movement. Rah. |
| 12696 | 13360 | ||
| 12697 | Formerly, we used PointerMotionHintMask (in standard_event_mask) | 13361 | Formerly, we used PointerMotionHintMask (in standard_event_mask) |
| @@ -12958,20 +13622,20 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, | |||
| 12958 | dpyinfo->last_mouse_scroll_bar = NULL; | 13622 | dpyinfo->last_mouse_scroll_bar = NULL; |
| 12959 | 13623 | ||
| 12960 | /* Figure out which root window we're on. */ | 13624 | /* Figure out which root window we're on. */ |
| 12961 | XQueryPointer (FRAME_X_DISPLAY (*fp), | 13625 | x_query_pointer (FRAME_X_DISPLAY (*fp), |
| 12962 | DefaultRootWindow (FRAME_X_DISPLAY (*fp)), | 13626 | DefaultRootWindow (FRAME_X_DISPLAY (*fp)), |
| 12963 | /* The root window which contains the pointer. */ | 13627 | /* The root window which contains the pointer. */ |
| 12964 | &root, | 13628 | &root, |
| 12965 | /* Trash which we can't trust if the pointer is on | 13629 | /* Trash which we can't trust if the pointer is on |
| 12966 | a different screen. */ | 13630 | a different screen. */ |
| 12967 | &dummy_window, | 13631 | &dummy_window, |
| 12968 | /* The position on that root window. */ | 13632 | /* The position on that root window. */ |
| 12969 | &root_x, &root_y, | 13633 | &root_x, &root_y, |
| 12970 | /* More trash we can't trust. */ | 13634 | /* More trash we can't trust. */ |
| 12971 | &dummy, &dummy, | 13635 | &dummy, &dummy, |
| 12972 | /* Modifier keys and pointer buttons, about which | 13636 | /* Modifier keys and pointer buttons, about which |
| 12973 | we don't care. */ | 13637 | we don't care. */ |
| 12974 | (unsigned int *) &dummy); | 13638 | (unsigned int *) &dummy); |
| 12975 | 13639 | ||
| 12976 | /* Now we have a position on the root; find the innermost window | 13640 | /* Now we have a position on the root; find the innermost window |
| 12977 | containing the pointer. */ | 13641 | containing the pointer. */ |
| @@ -13206,6 +13870,37 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, | |||
| 13206 | 13870 | ||
| 13207 | /* Scroll bar support. */ | 13871 | /* Scroll bar support. */ |
| 13208 | 13872 | ||
| 13873 | #if defined HAVE_XINPUT2 | ||
| 13874 | |||
| 13875 | /* Select for input extension events used by scroll bars. This will | ||
| 13876 | result in the corresponding core events not being generated for | ||
| 13877 | SCROLL_BAR. */ | ||
| 13878 | |||
| 13879 | MAYBE_UNUSED static void | ||
| 13880 | xi_select_scroll_bar_events (struct x_display_info *dpyinfo, | ||
| 13881 | Window scroll_bar) | ||
| 13882 | { | ||
| 13883 | XIEventMask mask; | ||
| 13884 | unsigned char *m; | ||
| 13885 | ptrdiff_t length; | ||
| 13886 | |||
| 13887 | length = XIMaskLen (XI_LASTEVENT); | ||
| 13888 | mask.mask = m = alloca (length); | ||
| 13889 | memset (m, 0, length); | ||
| 13890 | mask.mask_len = length; | ||
| 13891 | |||
| 13892 | mask.deviceid = XIAllMasterDevices; | ||
| 13893 | XISetMask (m, XI_ButtonPress); | ||
| 13894 | XISetMask (m, XI_ButtonRelease); | ||
| 13895 | XISetMask (m, XI_Motion); | ||
| 13896 | XISetMask (m, XI_Enter); | ||
| 13897 | XISetMask (m, XI_Leave); | ||
| 13898 | |||
| 13899 | XISelectEvents (dpyinfo->display, scroll_bar, &mask, 1); | ||
| 13900 | } | ||
| 13901 | |||
| 13902 | #endif | ||
| 13903 | |||
| 13209 | /* Given an X window ID and a DISPLAY, find the struct scroll_bar which | 13904 | /* Given an X window ID and a DISPLAY, find the struct scroll_bar which |
| 13210 | manages it. | 13905 | manages it. |
| 13211 | This can be called in GC, so we have to make sure to strip off mark | 13906 | This can be called in GC, so we have to make sure to strip off mark |
| @@ -13996,25 +14691,8 @@ x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) | |||
| 13996 | /* Ask for input extension button and motion events. This lets us | 14691 | /* Ask for input extension button and motion events. This lets us |
| 13997 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ | 14692 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ |
| 13998 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | 14693 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) |
| 13999 | { | 14694 | xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f), |
| 14000 | XIEventMask mask; | 14695 | XtWindow (widget)); |
| 14001 | ptrdiff_t l = XIMaskLen (XI_LASTEVENT); | ||
| 14002 | unsigned char *m; | ||
| 14003 | |||
| 14004 | mask.mask = m = alloca (l); | ||
| 14005 | memset (m, 0, l); | ||
| 14006 | mask.mask_len = l; | ||
| 14007 | |||
| 14008 | mask.deviceid = XIAllMasterDevices; | ||
| 14009 | XISetMask (m, XI_ButtonPress); | ||
| 14010 | XISetMask (m, XI_ButtonRelease); | ||
| 14011 | XISetMask (m, XI_Motion); | ||
| 14012 | XISetMask (m, XI_Enter); | ||
| 14013 | XISetMask (m, XI_Leave); | ||
| 14014 | |||
| 14015 | XISelectEvents (XtDisplay (widget), XtWindow (widget), | ||
| 14016 | &mask, 1); | ||
| 14017 | } | ||
| 14018 | #endif | 14696 | #endif |
| 14019 | #else /* !USE_MOTIF i.e. use Xaw */ | 14697 | #else /* !USE_MOTIF i.e. use Xaw */ |
| 14020 | 14698 | ||
| @@ -14221,25 +14899,8 @@ x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar) | |||
| 14221 | /* Ask for input extension button and motion events. This lets us | 14899 | /* Ask for input extension button and motion events. This lets us |
| 14222 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ | 14900 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ |
| 14223 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | 14901 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) |
| 14224 | { | 14902 | xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f), |
| 14225 | XIEventMask mask; | 14903 | XtWindow (widget)); |
| 14226 | ptrdiff_t l = XIMaskLen (XI_LASTEVENT); | ||
| 14227 | unsigned char *m; | ||
| 14228 | |||
| 14229 | mask.mask = m = alloca (l); | ||
| 14230 | memset (m, 0, l); | ||
| 14231 | mask.mask_len = l; | ||
| 14232 | |||
| 14233 | mask.deviceid = XIAllMasterDevices; | ||
| 14234 | XISetMask (m, XI_ButtonPress); | ||
| 14235 | XISetMask (m, XI_ButtonRelease); | ||
| 14236 | XISetMask (m, XI_Motion); | ||
| 14237 | XISetMask (m, XI_Enter); | ||
| 14238 | XISetMask (m, XI_Leave); | ||
| 14239 | |||
| 14240 | XISelectEvents (XtDisplay (widget), XtWindow (widget), | ||
| 14241 | &mask, 1); | ||
| 14242 | } | ||
| 14243 | #endif | 14904 | #endif |
| 14244 | #else /* !USE_MOTIF i.e. use Xaw */ | 14905 | #else /* !USE_MOTIF i.e. use Xaw */ |
| 14245 | 14906 | ||
| @@ -14661,24 +15322,8 @@ x_scroll_bar_create (struct window *w, int top, int left, | |||
| 14661 | /* Ask for input extension button and motion events. This lets us | 15322 | /* Ask for input extension button and motion events. This lets us |
| 14662 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ | 15323 | send the proper `wheel-up' or `wheel-down' events to Emacs. */ |
| 14663 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | 15324 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) |
| 14664 | { | 15325 | xi_select_scroll_bar_events (FRAME_DISPLAY_INFO (f), |
| 14665 | XIEventMask mask; | 15326 | window); |
| 14666 | ptrdiff_t l = XIMaskLen (XI_LASTEVENT); | ||
| 14667 | unsigned char *m; | ||
| 14668 | |||
| 14669 | mask.mask = m = alloca (l); | ||
| 14670 | memset (m, 0, l); | ||
| 14671 | mask.mask_len = l; | ||
| 14672 | |||
| 14673 | mask.deviceid = XIAllMasterDevices; | ||
| 14674 | XISetMask (m, XI_ButtonPress); | ||
| 14675 | XISetMask (m, XI_ButtonRelease); | ||
| 14676 | XISetMask (m, XI_Motion); | ||
| 14677 | XISetMask (m, XI_Enter); | ||
| 14678 | XISetMask (m, XI_Leave); | ||
| 14679 | |||
| 14680 | XISelectEvents (FRAME_X_DISPLAY (f), window, &mask, 1); | ||
| 14681 | } | ||
| 14682 | #endif | 15327 | #endif |
| 14683 | 15328 | ||
| 14684 | bar->x_window = window; | 15329 | bar->x_window = window; |
| @@ -15563,17 +16208,17 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window, | |||
| 15563 | 16208 | ||
| 15564 | /* Get the mouse's position relative to the scroll bar window, and | 16209 | /* Get the mouse's position relative to the scroll bar window, and |
| 15565 | report that. */ | 16210 | report that. */ |
| 15566 | if (XQueryPointer (FRAME_X_DISPLAY (f), w, | 16211 | if (x_query_pointer (FRAME_X_DISPLAY (f), w, |
| 15567 | 16212 | ||
| 15568 | /* Root, child, root x and root y. */ | 16213 | /* Root, child, root x and root y. */ |
| 15569 | &dummy_window, &dummy_window, | 16214 | &dummy_window, &dummy_window, |
| 15570 | &dummy_coord, &dummy_coord, | 16215 | &dummy_coord, &dummy_coord, |
| 15571 | 16216 | ||
| 15572 | /* Position relative to scroll bar. */ | 16217 | /* Position relative to scroll bar. */ |
| 15573 | &win_x, &win_y, | 16218 | &win_x, &win_y, |
| 15574 | 16219 | ||
| 15575 | /* Mouse buttons and modifier keys. */ | 16220 | /* Mouse buttons and modifier keys. */ |
| 15576 | &dummy_mask)) | 16221 | &dummy_mask)) |
| 15577 | { | 16222 | { |
| 15578 | int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height); | 16223 | int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height); |
| 15579 | 16224 | ||
| @@ -15632,17 +16277,17 @@ x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_windo | |||
| 15632 | 16277 | ||
| 15633 | /* Get the mouse's position relative to the scroll bar window, and | 16278 | /* Get the mouse's position relative to the scroll bar window, and |
| 15634 | report that. */ | 16279 | report that. */ |
| 15635 | if (XQueryPointer (FRAME_X_DISPLAY (f), w, | 16280 | if (x_query_pointer (FRAME_X_DISPLAY (f), w, |
| 15636 | 16281 | ||
| 15637 | /* Root, child, root x and root y. */ | 16282 | /* Root, child, root x and root y. */ |
| 15638 | &dummy_window, &dummy_window, | 16283 | &dummy_window, &dummy_window, |
| 15639 | &dummy_coord, &dummy_coord, | 16284 | &dummy_coord, &dummy_coord, |
| 15640 | 16285 | ||
| 15641 | /* Position relative to scroll bar. */ | 16286 | /* Position relative to scroll bar. */ |
| 15642 | &win_x, &win_y, | 16287 | &win_x, &win_y, |
| 15643 | 16288 | ||
| 15644 | /* Mouse buttons and modifier keys. */ | 16289 | /* Mouse buttons and modifier keys. */ |
| 15645 | &dummy_mask)) | 16290 | &dummy_mask)) |
| 15646 | { | 16291 | { |
| 15647 | int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); | 16292 | int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width); |
| 15648 | 16293 | ||
| @@ -16501,6 +17146,29 @@ x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout) | |||
| 16501 | } | 17146 | } |
| 16502 | } | 17147 | } |
| 16503 | 17148 | ||
| 17149 | /* Find whether or not an undelivered MONITORS_CHANGED_EVENT is | ||
| 17150 | already on the event queue. DPYINFO is the display any such event | ||
| 17151 | must apply to. */ | ||
| 17152 | |||
| 17153 | static bool | ||
| 17154 | x_find_monitors_changed_event (struct x_display_info *dpyinfo) | ||
| 17155 | { | ||
| 17156 | union buffered_input_event *event; | ||
| 17157 | |||
| 17158 | event = kbd_fetch_ptr; | ||
| 17159 | |||
| 17160 | while (event != kbd_store_ptr) | ||
| 17161 | { | ||
| 17162 | if (event->ie.kind == MONITORS_CHANGED_EVENT | ||
| 17163 | && XTERMINAL (event->ie.arg) == dpyinfo->terminal) | ||
| 17164 | return true; | ||
| 17165 | |||
| 17166 | event = X_NEXT_KBD_EVENT (event); | ||
| 17167 | } | ||
| 17168 | |||
| 17169 | return false; | ||
| 17170 | } | ||
| 17171 | |||
| 16504 | #ifdef USE_GTK | 17172 | #ifdef USE_GTK |
| 16505 | static void | 17173 | static void |
| 16506 | x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) | 17174 | x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) |
| @@ -16518,6 +17186,9 @@ x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) | |||
| 16518 | if (!dpyinfo) | 17186 | if (!dpyinfo) |
| 16519 | return; | 17187 | return; |
| 16520 | 17188 | ||
| 17189 | if (x_find_monitors_changed_event (dpyinfo)) | ||
| 17190 | return; | ||
| 17191 | |||
| 16521 | XSETTERMINAL (terminal, dpyinfo->terminal); | 17192 | XSETTERMINAL (terminal, dpyinfo->terminal); |
| 16522 | 17193 | ||
| 16523 | current_monitors | 17194 | current_monitors |
| @@ -16645,6 +17316,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 16645 | union buffered_input_event inev; | 17316 | union buffered_input_event inev; |
| 16646 | int count = 0; | 17317 | int count = 0; |
| 16647 | int do_help = 0; | 17318 | int do_help = 0; |
| 17319 | #ifdef HAVE_XINPUT2 | ||
| 17320 | struct xi_device_t *gen_help_device; | ||
| 17321 | Time gen_help_time; | ||
| 17322 | #endif | ||
| 16648 | ptrdiff_t nbytes = 0; | 17323 | ptrdiff_t nbytes = 0; |
| 16649 | struct frame *any, *f = NULL; | 17324 | struct frame *any, *f = NULL; |
| 16650 | Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight; | 17325 | Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight; |
| @@ -16674,6 +17349,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 16674 | EVENT_INIT (inev.ie); | 17349 | EVENT_INIT (inev.ie); |
| 16675 | inev.ie.kind = NO_EVENT; | 17350 | inev.ie.kind = NO_EVENT; |
| 16676 | inev.ie.arg = Qnil; | 17351 | inev.ie.arg = Qnil; |
| 17352 | #ifdef HAVE_XINPUT2 | ||
| 17353 | gen_help_device = NULL; | ||
| 17354 | #endif | ||
| 16677 | 17355 | ||
| 16678 | /* Ignore events coming from various extensions, such as XFIXES and | 17356 | /* Ignore events coming from various extensions, such as XFIXES and |
| 16679 | XKB. */ | 17357 | XKB. */ |
| @@ -17172,7 +17850,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17172 | goto done; | 17850 | goto done; |
| 17173 | #endif | 17851 | #endif |
| 17174 | 17852 | ||
| 17175 | xft_settings_event (dpyinfo, event); | 17853 | if (xft_settings_event (dpyinfo, event)) |
| 17854 | goto done; | ||
| 17176 | 17855 | ||
| 17177 | f = any; | 17856 | f = any; |
| 17178 | /* We don't want to ever leak tooltip frames to Lisp code. */ | 17857 | /* We don't want to ever leak tooltip frames to Lisp code. */ |
| @@ -17198,6 +17877,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17198 | if (!x_window_to_frame (dpyinfo, event->xselection.requestor)) | 17877 | if (!x_window_to_frame (dpyinfo, event->xselection.requestor)) |
| 17199 | goto OTHER; | 17878 | goto OTHER; |
| 17200 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ | 17879 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ |
| 17880 | #ifdef HAVE_GTK3 | ||
| 17881 | /* GTK 3 apparently chokes on these events since they have no | ||
| 17882 | associated device. (bug#56869, another bug as well that I | ||
| 17883 | can't find) */ | ||
| 17884 | *finish = X_EVENT_DROP; | ||
| 17885 | #endif | ||
| 17201 | x_handle_selection_notify (&event->xselection); | 17886 | x_handle_selection_notify (&event->xselection); |
| 17202 | break; | 17887 | break; |
| 17203 | 17888 | ||
| @@ -17206,6 +17891,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17206 | if (!x_window_to_frame (dpyinfo, event->xselectionclear.window)) | 17891 | if (!x_window_to_frame (dpyinfo, event->xselectionclear.window)) |
| 17207 | goto OTHER; | 17892 | goto OTHER; |
| 17208 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ | 17893 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ |
| 17894 | #ifdef HAVE_GTK3 | ||
| 17895 | *finish = X_EVENT_DROP; | ||
| 17896 | #endif | ||
| 17209 | { | 17897 | { |
| 17210 | const XSelectionClearEvent *eventp = &event->xselectionclear; | 17898 | const XSelectionClearEvent *eventp = &event->xselectionclear; |
| 17211 | 17899 | ||
| @@ -17232,6 +17920,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17232 | if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner)) | 17920 | if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner)) |
| 17233 | goto OTHER; | 17921 | goto OTHER; |
| 17234 | #endif /* USE_X_TOOLKIT */ | 17922 | #endif /* USE_X_TOOLKIT */ |
| 17923 | #ifdef HAVE_GTK3 | ||
| 17924 | *finish = X_EVENT_DROP; | ||
| 17925 | #endif | ||
| 17235 | { | 17926 | { |
| 17236 | const XSelectionRequestEvent *eventp = &event->xselectionrequest; | 17927 | const XSelectionRequestEvent *eventp = &event->xselectionrequest; |
| 17237 | 17928 | ||
| @@ -17873,6 +18564,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17873 | x_display_set_last_user_time (dpyinfo, event->xkey.time, | 18564 | x_display_set_last_user_time (dpyinfo, event->xkey.time, |
| 17874 | event->xkey.send_event); | 18565 | event->xkey.send_event); |
| 17875 | ignore_next_mouse_click_timeout = 0; | 18566 | ignore_next_mouse_click_timeout = 0; |
| 18567 | |||
| 17876 | coding = Qlatin_1; | 18568 | coding = Qlatin_1; |
| 17877 | 18569 | ||
| 17878 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 18570 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| @@ -17883,6 +18575,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 17883 | 18575 | ||
| 17884 | f = any; | 18576 | f = any; |
| 17885 | 18577 | ||
| 18578 | #ifdef USE_GTK | ||
| 18579 | if (f) | ||
| 18580 | x_set_gtk_user_time (f, event->xkey.time); | ||
| 18581 | #endif | ||
| 18582 | |||
| 17886 | /* If mouse-highlight is an integer, input clears out | 18583 | /* If mouse-highlight is an integer, input clears out |
| 17887 | mouse highlighting. */ | 18584 | mouse highlighting. */ |
| 17888 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | 18585 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) |
| @@ -18462,7 +19159,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 18462 | { | 19159 | { |
| 18463 | /* Now clear dpyinfo->last_mouse_motion_frame, or | 19160 | /* Now clear dpyinfo->last_mouse_motion_frame, or |
| 18464 | gui_redo_mouse_highlight will end up highlighting the | 19161 | gui_redo_mouse_highlight will end up highlighting the |
| 18465 | last known poisition of the mouse if a tooltip frame is | 19162 | last known position of the mouse if a tooltip frame is |
| 18466 | later unmapped. */ | 19163 | later unmapped. */ |
| 18467 | 19164 | ||
| 18468 | if (f == dpyinfo->last_mouse_motion_frame) | 19165 | if (f == dpyinfo->last_mouse_motion_frame) |
| @@ -18885,13 +19582,20 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 18885 | if (configureEvent.xconfigure.width != dpyinfo->screen_width | 19582 | if (configureEvent.xconfigure.width != dpyinfo->screen_width |
| 18886 | || configureEvent.xconfigure.height != dpyinfo->screen_height) | 19583 | || configureEvent.xconfigure.height != dpyinfo->screen_height) |
| 18887 | { | 19584 | { |
| 18888 | inev.ie.kind = MONITORS_CHANGED_EVENT; | 19585 | /* Also avoid storing duplicate events here, since |
| 18889 | XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); | 19586 | Fx_display_monitor_attributes_list will return the |
| 19587 | same information for both invocations of the | ||
| 19588 | hook. */ | ||
| 19589 | if (!x_find_monitors_changed_event (dpyinfo)) | ||
| 19590 | { | ||
| 19591 | inev.ie.kind = MONITORS_CHANGED_EVENT; | ||
| 19592 | XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); | ||
| 18890 | 19593 | ||
| 18891 | /* Store this event now since inev.ie.type could be set to | 19594 | /* Store this event now since inev.ie.type could be set to |
| 18892 | MOVE_FRAME_EVENT later. */ | 19595 | MOVE_FRAME_EVENT later. */ |
| 18893 | kbd_buffer_store_event (&inev.ie); | 19596 | kbd_buffer_store_event (&inev.ie); |
| 18894 | inev.ie.kind = NO_EVENT; | 19597 | inev.ie.kind = NO_EVENT; |
| 19598 | } | ||
| 18895 | 19599 | ||
| 18896 | /* Also update the position of the drag-and-drop | 19600 | /* Also update the position of the drag-and-drop |
| 18897 | tooltip. */ | 19601 | tooltip. */ |
| @@ -19663,11 +20367,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 19663 | { | 20367 | { |
| 19664 | case XI_FocusIn: | 20368 | case XI_FocusIn: |
| 19665 | { | 20369 | { |
| 19666 | XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event; | 20370 | XIFocusInEvent *focusin; |
| 19667 | struct xi_device_t *source; | ||
| 19668 | 20371 | ||
| 20372 | focusin = (XIFocusInEvent *) xi_event; | ||
| 19669 | any = x_any_window_to_frame (dpyinfo, focusin->event); | 20373 | any = x_any_window_to_frame (dpyinfo, focusin->event); |
| 19670 | source = xi_device_from_id (dpyinfo, focusin->sourceid); | 20374 | |
| 19671 | #ifdef USE_GTK | 20375 | #ifdef USE_GTK |
| 19672 | /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap | 20376 | /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap |
| 19673 | minimized/iconified windows; thus, for those WMs we won't get | 20377 | minimized/iconified windows; thus, for those WMs we won't get |
| @@ -19696,24 +20400,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 19696 | } | 20400 | } |
| 19697 | } | 20401 | } |
| 19698 | 20402 | ||
| 19699 | x_detect_focus_change (dpyinfo, any, event, &inev.ie); | 20403 | xi_focus_handle_for_device (dpyinfo, any, xi_event); |
| 19700 | 20404 | ||
| 19701 | if (inev.ie.kind != NO_EVENT && source) | ||
| 19702 | inev.ie.device = source->name; | ||
| 19703 | goto XI_OTHER; | 20405 | goto XI_OTHER; |
| 19704 | } | 20406 | } |
| 19705 | 20407 | ||
| 19706 | case XI_FocusOut: | 20408 | case XI_FocusOut: |
| 19707 | { | 20409 | { |
| 19708 | XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event; | 20410 | XIFocusOutEvent *focusout; |
| 19709 | struct xi_device_t *source; | ||
| 19710 | 20411 | ||
| 20412 | focusout = (XIFocusOutEvent *) xi_event; | ||
| 19711 | any = x_any_window_to_frame (dpyinfo, focusout->event); | 20413 | any = x_any_window_to_frame (dpyinfo, focusout->event); |
| 19712 | source = xi_device_from_id (dpyinfo, focusout->sourceid); | 20414 | xi_focus_handle_for_device (dpyinfo, any, xi_event); |
| 19713 | x_detect_focus_change (dpyinfo, any, event, &inev.ie); | ||
| 19714 | 20415 | ||
| 19715 | if (inev.ie.kind != NO_EVENT && source) | ||
| 19716 | inev.ie.device = source->name; | ||
| 19717 | goto XI_OTHER; | 20416 | goto XI_OTHER; |
| 19718 | } | 20417 | } |
| 19719 | 20418 | ||
| @@ -19762,7 +20461,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 19762 | are an inferiors of the frame's top window, which will | 20461 | are an inferiors of the frame's top window, which will |
| 19763 | get virtual events. */ | 20462 | get virtual events. */ |
| 19764 | if (any) | 20463 | if (any) |
| 19765 | x_detect_focus_change (dpyinfo, any, event, &inev.ie); | 20464 | xi_focus_handle_for_device (dpyinfo, any, xi_event); |
| 19766 | 20465 | ||
| 19767 | if (!any) | 20466 | if (!any) |
| 19768 | any = x_any_window_to_frame (dpyinfo, enter->event); | 20467 | any = x_any_window_to_frame (dpyinfo, enter->event); |
| @@ -19902,7 +20601,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 19902 | #endif | 20601 | #endif |
| 19903 | 20602 | ||
| 19904 | if (any) | 20603 | if (any) |
| 19905 | x_detect_focus_change (dpyinfo, any, event, &inev.ie); | 20604 | xi_focus_handle_for_device (dpyinfo, any, xi_event); |
| 19906 | 20605 | ||
| 19907 | #ifndef USE_X_TOOLKIT | 20606 | #ifndef USE_X_TOOLKIT |
| 19908 | f = x_top_window_to_frame (dpyinfo, leave->event); | 20607 | f = x_top_window_to_frame (dpyinfo, leave->event); |
| @@ -19929,7 +20628,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 19929 | { | 20628 | { |
| 19930 | /* Now clear dpyinfo->last_mouse_motion_frame, or | 20629 | /* Now clear dpyinfo->last_mouse_motion_frame, or |
| 19931 | gui_redo_mouse_highlight will end up highlighting | 20630 | gui_redo_mouse_highlight will end up highlighting |
| 19932 | the last known poisition of the mouse if a | 20631 | the last known position of the mouse if a |
| 19933 | tooltip frame is later unmapped. */ | 20632 | tooltip frame is later unmapped. */ |
| 19934 | 20633 | ||
| 19935 | if (f == dpyinfo->last_mouse_motion_frame) | 20634 | if (f == dpyinfo->last_mouse_motion_frame) |
| @@ -20590,7 +21289,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20590 | has changed, generate a HELP_EVENT. */ | 21289 | has changed, generate a HELP_EVENT. */ |
| 20591 | if (!NILP (help_echo_string) | 21290 | if (!NILP (help_echo_string) |
| 20592 | || !NILP (previous_help_echo_string)) | 21291 | || !NILP (previous_help_echo_string)) |
| 20593 | do_help = 1; | 21292 | { |
| 21293 | /* Also allow the focus and client pointer to be | ||
| 21294 | adjusted accordingly, in case a help tooltip is | ||
| 21295 | shown. */ | ||
| 21296 | gen_help_device = device; | ||
| 21297 | gen_help_time = xev->time; | ||
| 21298 | |||
| 21299 | do_help = 1; | ||
| 21300 | } | ||
| 20594 | goto XI_OTHER; | 21301 | goto XI_OTHER; |
| 20595 | } | 21302 | } |
| 20596 | 21303 | ||
| @@ -20653,6 +21360,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20653 | } | 21360 | } |
| 20654 | #endif | 21361 | #endif |
| 20655 | 21362 | ||
| 21363 | if (f && device) | ||
| 21364 | xi_handle_interaction (dpyinfo, f, device, | ||
| 21365 | xev->time); | ||
| 21366 | |||
| 20656 | if (xev->evtype == XI_ButtonPress | 21367 | if (xev->evtype == XI_ButtonPress |
| 20657 | && x_dnd_last_seen_window != None) | 21368 | && x_dnd_last_seen_window != None) |
| 20658 | { | 21369 | { |
| @@ -20899,11 +21610,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20899 | xev->send_event); | 21610 | xev->send_event); |
| 20900 | 21611 | ||
| 20901 | source = xi_device_from_id (dpyinfo, xev->sourceid); | 21612 | source = xi_device_from_id (dpyinfo, xev->sourceid); |
| 21613 | device = xi_device_from_id (dpyinfo, xev->deviceid); | ||
| 20902 | 21614 | ||
| 20903 | #ifdef HAVE_XWIDGETS | 21615 | #ifdef HAVE_XWIDGETS |
| 20904 | xvw = xwidget_view_from_window (xev->event); | 21616 | xvw = xwidget_view_from_window (xev->event); |
| 20905 | if (xvw) | 21617 | if (xvw) |
| 20906 | { | 21618 | { |
| 21619 | /* If the user interacts with a frame that's focused | ||
| 21620 | on another device, but not the current focus | ||
| 21621 | frame, make it the focus frame. */ | ||
| 21622 | if (device) | ||
| 21623 | xi_handle_interaction (dpyinfo, xvw->frame, | ||
| 21624 | device, xev->time); | ||
| 21625 | |||
| 20907 | xwidget_button (xvw, xev->evtype == XI_ButtonPress, | 21626 | xwidget_button (xvw, xev->evtype == XI_ButtonPress, |
| 20908 | lrint (xev->event_x), lrint (xev->event_y), | 21627 | lrint (xev->event_x), lrint (xev->event_y), |
| 20909 | xev->detail, xi_convert_event_state (xev), | 21628 | xev->detail, xi_convert_event_state (xev), |
| @@ -20923,8 +21642,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20923 | } | 21642 | } |
| 20924 | #endif | 21643 | #endif |
| 20925 | 21644 | ||
| 20926 | device = xi_device_from_id (dpyinfo, xev->deviceid); | ||
| 20927 | |||
| 20928 | if (!device) | 21645 | if (!device) |
| 20929 | goto XI_OTHER; | 21646 | goto XI_OTHER; |
| 20930 | 21647 | ||
| @@ -20962,6 +21679,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20962 | } | 21679 | } |
| 20963 | } | 21680 | } |
| 20964 | 21681 | ||
| 21682 | if (f) | ||
| 21683 | { | ||
| 21684 | /* If the user interacts with a frame that's focused | ||
| 21685 | on another device, but not the current focus | ||
| 21686 | frame, make it the focus frame. */ | ||
| 21687 | if (device) | ||
| 21688 | xi_handle_interaction (dpyinfo, f, device, | ||
| 21689 | xev->time); | ||
| 21690 | } | ||
| 21691 | |||
| 20965 | #ifdef USE_GTK | 21692 | #ifdef USE_GTK |
| 20966 | if (!f) | 21693 | if (!f) |
| 20967 | { | 21694 | { |
| @@ -21243,6 +21970,25 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21243 | 21970 | ||
| 21244 | f = x_any_window_to_frame (dpyinfo, xev->event); | 21971 | f = x_any_window_to_frame (dpyinfo, xev->event); |
| 21245 | 21972 | ||
| 21973 | /* GTK handles TAB events in an undesirable manner, so | ||
| 21974 | keyboard events are always dropped. But as a side | ||
| 21975 | effect, the user time will no longer be set by GDK, | ||
| 21976 | so do that manually. */ | ||
| 21977 | #ifdef USE_GTK | ||
| 21978 | if (f) | ||
| 21979 | x_set_gtk_user_time (f, xev->time); | ||
| 21980 | #endif | ||
| 21981 | |||
| 21982 | if (f) | ||
| 21983 | { | ||
| 21984 | /* If the user interacts with a frame that's focused | ||
| 21985 | on another device, but not the current focus | ||
| 21986 | frame, make it the focus frame. */ | ||
| 21987 | if (device) | ||
| 21988 | xi_handle_interaction (dpyinfo, f, device, | ||
| 21989 | xev->time); | ||
| 21990 | } | ||
| 21991 | |||
| 21246 | XKeyPressedEvent xkey; | 21992 | XKeyPressedEvent xkey; |
| 21247 | 21993 | ||
| 21248 | memset (&xkey, 0, sizeof xkey); | 21994 | memset (&xkey, 0, sizeof xkey); |
| @@ -21717,14 +22463,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21717 | 22463 | ||
| 21718 | case XI_HierarchyChanged: | 22464 | case XI_HierarchyChanged: |
| 21719 | { | 22465 | { |
| 21720 | XIHierarchyEvent *hev = (XIHierarchyEvent *) xi_event; | 22466 | XIHierarchyEvent *hev; |
| 21721 | XIDeviceInfo *info; | 22467 | XIDeviceInfo *info; |
| 21722 | int i, j, ndevices, n_disabled, *disabled; | 22468 | int i, ndevices, n_disabled, *disabled; |
| 21723 | struct xi_device_t *device, *devices; | 22469 | struct xi_device_t *device; |
| 21724 | #ifdef HAVE_XINPUT2_2 | 22470 | bool any_changed; |
| 21725 | struct xi_touch_point_t *tem, *last; | ||
| 21726 | #endif | ||
| 21727 | 22471 | ||
| 22472 | any_changed = false; | ||
| 22473 | hev = (XIHierarchyEvent *) xi_event; | ||
| 21728 | disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info); | 22474 | disabled = SAFE_ALLOCA (sizeof *disabled * hev->num_info); |
| 21729 | n_disabled = 0; | 22475 | n_disabled = 0; |
| 21730 | 22476 | ||
| @@ -21734,44 +22480,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21734 | { | 22480 | { |
| 21735 | /* Handle all disabled devices now, to prevent | 22481 | /* Handle all disabled devices now, to prevent |
| 21736 | things happening out-of-order later. */ | 22482 | things happening out-of-order later. */ |
| 21737 | if (n_disabled) | ||
| 21738 | { | ||
| 21739 | ndevices = 0; | ||
| 21740 | devices = xmalloc (sizeof *devices * dpyinfo->num_devices); | ||
| 21741 | |||
| 21742 | for (i = 0; i < dpyinfo->num_devices; ++i) | ||
| 21743 | { | ||
| 21744 | for (j = 0; j < n_disabled; ++j) | ||
| 21745 | { | ||
| 21746 | if (disabled[j] == dpyinfo->devices[i].device_id) | ||
| 21747 | { | ||
| 21748 | #ifdef HAVE_XINPUT2_1 | ||
| 21749 | xfree (dpyinfo->devices[i].valuators); | ||
| 21750 | #endif | ||
| 21751 | #ifdef HAVE_XINPUT2_2 | ||
| 21752 | tem = dpyinfo->devices[i].touchpoints; | ||
| 21753 | while (tem) | ||
| 21754 | { | ||
| 21755 | last = tem; | ||
| 21756 | tem = tem->next; | ||
| 21757 | xfree (last); | ||
| 21758 | } | ||
| 21759 | #endif | ||
| 21760 | goto continue_detachment; | ||
| 21761 | } | ||
| 21762 | } | ||
| 21763 | |||
| 21764 | devices[ndevices++] = dpyinfo->devices[i]; | ||
| 21765 | |||
| 21766 | continue_detachment: | ||
| 21767 | continue; | ||
| 21768 | } | ||
| 21769 | |||
| 21770 | xfree (dpyinfo->devices); | ||
| 21771 | dpyinfo->devices = devices; | ||
| 21772 | dpyinfo->num_devices = ndevices; | ||
| 21773 | 22483 | ||
| 22484 | if (ndevices) | ||
| 22485 | { | ||
| 22486 | xi_disable_devices (dpyinfo, disabled, n_disabled); | ||
| 21774 | n_disabled = 0; | 22487 | n_disabled = 0; |
| 22488 | |||
| 22489 | /* This flag really just means that disabled | ||
| 22490 | devices were handled early and should be | ||
| 22491 | used in conjunction with n_disabled. */ | ||
| 22492 | any_changed = true; | ||
| 21775 | } | 22493 | } |
| 21776 | 22494 | ||
| 21777 | x_catch_errors (dpyinfo->display); | 22495 | x_catch_errors (dpyinfo->display); |
| @@ -21784,6 +22502,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21784 | dpyinfo->devices | 22502 | dpyinfo->devices |
| 21785 | = xrealloc (dpyinfo->devices, (sizeof *dpyinfo->devices | 22503 | = xrealloc (dpyinfo->devices, (sizeof *dpyinfo->devices |
| 21786 | * ++dpyinfo->num_devices)); | 22504 | * ++dpyinfo->num_devices)); |
| 22505 | memset (dpyinfo->devices + dpyinfo->num_devices - 1, | ||
| 22506 | 0, sizeof *dpyinfo->devices); | ||
| 21787 | device = &dpyinfo->devices[dpyinfo->num_devices - 1]; | 22507 | device = &dpyinfo->devices[dpyinfo->num_devices - 1]; |
| 21788 | xi_populate_device_from_info (device, info); | 22508 | xi_populate_device_from_info (device, info); |
| 21789 | } | 22509 | } |
| @@ -21805,7 +22525,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21805 | if (info) | 22525 | if (info) |
| 21806 | { | 22526 | { |
| 21807 | if (device && info->enabled) | 22527 | if (device && info->enabled) |
| 21808 | device->use = info->use; | 22528 | { |
| 22529 | device->use = info->use; | ||
| 22530 | device->attachment = info->attachment; | ||
| 22531 | } | ||
| 21809 | else if (device) | 22532 | else if (device) |
| 21810 | disabled[n_disabled++] = hev->info[i].deviceid; | 22533 | disabled[n_disabled++] = hev->info[i].deviceid; |
| 21811 | 22534 | ||
| @@ -21814,174 +22537,37 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21814 | } | 22537 | } |
| 21815 | } | 22538 | } |
| 21816 | 22539 | ||
| 21817 | if (n_disabled) | 22540 | /* Delete all devices that were disabled by this |
| 21818 | { | 22541 | event. */ |
| 21819 | ndevices = 0; | 22542 | xi_disable_devices (dpyinfo, disabled, n_disabled); |
| 21820 | devices = xmalloc (sizeof *devices * dpyinfo->num_devices); | ||
| 21821 | |||
| 21822 | for (i = 0; i < dpyinfo->num_devices; ++i) | ||
| 21823 | { | ||
| 21824 | for (j = 0; j < n_disabled; ++j) | ||
| 21825 | { | ||
| 21826 | if (disabled[j] == dpyinfo->devices[i].device_id) | ||
| 21827 | { | ||
| 21828 | #ifdef HAVE_XINPUT2_1 | ||
| 21829 | xfree (dpyinfo->devices[i].valuators); | ||
| 21830 | #endif | ||
| 21831 | #ifdef HAVE_XINPUT2_2 | ||
| 21832 | tem = dpyinfo->devices[i].touchpoints; | ||
| 21833 | while (tem) | ||
| 21834 | { | ||
| 21835 | last = tem; | ||
| 21836 | tem = tem->next; | ||
| 21837 | xfree (last); | ||
| 21838 | } | ||
| 21839 | #endif | ||
| 21840 | goto break_detachment; | ||
| 21841 | } | ||
| 21842 | } | ||
| 21843 | |||
| 21844 | devices[ndevices++] = dpyinfo->devices[i]; | ||
| 21845 | |||
| 21846 | break_detachment: | ||
| 21847 | continue; | ||
| 21848 | } | ||
| 21849 | 22543 | ||
| 21850 | xfree (dpyinfo->devices); | 22544 | /* If the device hierarchy has been changed, recompute |
| 21851 | dpyinfo->devices = devices; | 22545 | focus. This might seem like a micro-optimization but |
| 21852 | dpyinfo->num_devices = ndevices; | 22546 | it actually keeps the focus from changing in some |
| 21853 | } | 22547 | cases where it would be undesierable. */ |
| 22548 | if (any_changed || n_disabled) | ||
| 22549 | xi_handle_focus_change (dpyinfo); | ||
| 21854 | 22550 | ||
| 21855 | goto XI_OTHER; | 22551 | goto XI_OTHER; |
| 21856 | } | 22552 | } |
| 21857 | 22553 | ||
| 21858 | case XI_DeviceChanged: | 22554 | case XI_DeviceChanged: |
| 21859 | { | 22555 | { |
| 21860 | XIDeviceChangedEvent *device_changed = (XIDeviceChangedEvent *) xi_event; | 22556 | XIDeviceChangedEvent *device_changed; |
| 21861 | struct xi_device_t *device; | 22557 | struct xi_device_t *device; |
| 21862 | #ifdef HAVE_XINPUT2_2 | ||
| 21863 | struct xi_touch_point_t *tem, *last; | ||
| 21864 | #endif | ||
| 21865 | int c; | ||
| 21866 | #ifdef HAVE_XINPUT2_1 | ||
| 21867 | int i; | ||
| 21868 | #endif | ||
| 21869 | 22558 | ||
| 22559 | device_changed = (XIDeviceChangedEvent *) xi_event; | ||
| 21870 | device = xi_device_from_id (dpyinfo, device_changed->deviceid); | 22560 | device = xi_device_from_id (dpyinfo, device_changed->deviceid); |
| 21871 | 22561 | ||
| 21872 | if (!device) | 22562 | /* If the device isn't enabled, then stop handling this |
| 21873 | { | 22563 | event. A HierarchyChanged event will be sent if it |
| 21874 | /* An existing device might have been enabled. */ | 22564 | is enabled afterwards. */ |
| 21875 | x_cache_xi_devices (dpyinfo); | ||
| 21876 | |||
| 21877 | /* Now try to find the device again, in case it was | ||
| 21878 | just enabled. */ | ||
| 21879 | device = xi_device_from_id (dpyinfo, device_changed->deviceid); | ||
| 21880 | } | ||
| 21881 | |||
| 21882 | /* If it wasn't enabled, then stop handling this event. */ | ||
| 21883 | if (!device) | 22565 | if (!device) |
| 21884 | goto XI_OTHER; | 22566 | goto XI_OTHER; |
| 21885 | 22567 | ||
| 21886 | /* Free data that we will regenerate from new | 22568 | /* Now handle the event by retrieving scroll valuators |
| 21887 | information. */ | 22569 | and touch info. */ |
| 21888 | #ifdef HAVE_XINPUT2_1 | 22570 | xi_handle_device_changed (dpyinfo, device, device_changed); |
| 21889 | device->valuators = xrealloc (device->valuators, | ||
| 21890 | (device_changed->num_classes | ||
| 21891 | * sizeof *device->valuators)); | ||
| 21892 | device->scroll_valuator_count = 0; | ||
| 21893 | #endif | ||
| 21894 | #ifdef HAVE_XINPUT2_2 | ||
| 21895 | device->direct_p = false; | ||
| 21896 | #endif | ||
| 21897 | |||
| 21898 | for (c = 0; c < device_changed->num_classes; ++c) | ||
| 21899 | { | ||
| 21900 | switch (device_changed->classes[c]->type) | ||
| 21901 | { | ||
| 21902 | #ifdef HAVE_XINPUT2_1 | ||
| 21903 | case XIScrollClass: | ||
| 21904 | { | ||
| 21905 | XIScrollClassInfo *info; | ||
| 21906 | |||
| 21907 | info = (XIScrollClassInfo *) device_changed->classes[c]; | ||
| 21908 | struct xi_scroll_valuator_t *valuator; | ||
| 21909 | |||
| 21910 | valuator = &device->valuators[device->scroll_valuator_count++]; | ||
| 21911 | valuator->horizontal | ||
| 21912 | = (info->scroll_type == XIScrollTypeHorizontal); | ||
| 21913 | valuator->invalid_p = true; | ||
| 21914 | valuator->emacs_value = DBL_MIN; | ||
| 21915 | valuator->increment = info->increment; | ||
| 21916 | valuator->number = info->number; | ||
| 21917 | |||
| 21918 | break; | ||
| 21919 | } | ||
| 21920 | #endif | ||
| 21921 | |||
| 21922 | #ifdef HAVE_XINPUT2_2 | ||
| 21923 | case XITouchClass: | ||
| 21924 | { | ||
| 21925 | XITouchClassInfo *info; | ||
| 21926 | |||
| 21927 | info = (XITouchClassInfo *) device_changed->classes[c]; | ||
| 21928 | device->direct_p = info->mode == XIDirectTouch; | ||
| 21929 | } | ||
| 21930 | #endif | ||
| 21931 | default: | ||
| 21932 | break; | ||
| 21933 | } | ||
| 21934 | } | ||
| 21935 | |||
| 21936 | #ifdef HAVE_XINPUT2_1 | ||
| 21937 | for (c = 0; c < device_changed->num_classes; ++c) | ||
| 21938 | { | ||
| 21939 | if (device_changed->classes[c]->type == XIValuatorClass) | ||
| 21940 | { | ||
| 21941 | XIValuatorClassInfo *info; | ||
| 21942 | |||
| 21943 | info = (XIValuatorClassInfo *) device_changed->classes[c]; | ||
| 21944 | |||
| 21945 | for (i = 0; i < device->scroll_valuator_count; ++i) | ||
| 21946 | { | ||
| 21947 | if (device->valuators[i].number == info->number) | ||
| 21948 | { | ||
| 21949 | device->valuators[i].invalid_p = false; | ||
| 21950 | device->valuators[i].current_value = info->value; | ||
| 21951 | |||
| 21952 | /* Make sure that this is reset if the | ||
| 21953 | pointer moves into a window of ours. | ||
| 21954 | |||
| 21955 | Otherwise the valuator state could be | ||
| 21956 | left invalid if the DeviceChange | ||
| 21957 | event happened with the pointer | ||
| 21958 | outside any Emacs frame. */ | ||
| 21959 | device->valuators[i].pending_enter_reset = true; | ||
| 21960 | } | ||
| 21961 | } | ||
| 21962 | } | ||
| 21963 | } | ||
| 21964 | #endif | ||
| 21965 | |||
| 21966 | #ifdef HAVE_XINPUT2_2 | ||
| 21967 | /* The device is no longer a DirectTouch device, so | ||
| 21968 | remove any touchpoints that we might have | ||
| 21969 | recorded. */ | ||
| 21970 | if (!device->direct_p) | ||
| 21971 | { | ||
| 21972 | tem = device->touchpoints; | ||
| 21973 | |||
| 21974 | while (tem) | ||
| 21975 | { | ||
| 21976 | last = tem; | ||
| 21977 | tem = tem->next; | ||
| 21978 | xfree (last); | ||
| 21979 | } | ||
| 21980 | |||
| 21981 | device->touchpoints = NULL; | ||
| 21982 | } | ||
| 21983 | #endif | ||
| 21984 | |||
| 21985 | goto XI_OTHER; | 22571 | goto XI_OTHER; |
| 21986 | } | 22572 | } |
| 21987 | 22573 | ||
| @@ -22533,7 +23119,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 22533 | || event->type == (dpyinfo->xrandr_event_base | 23119 | || event->type == (dpyinfo->xrandr_event_base |
| 22534 | + RRNotify))) | 23120 | + RRNotify))) |
| 22535 | { | 23121 | { |
| 22536 | union buffered_input_event *ev; | ||
| 22537 | Time timestamp; | 23122 | Time timestamp; |
| 22538 | Lisp_Object current_monitors; | 23123 | Lisp_Object current_monitors; |
| 22539 | XRRScreenChangeNotifyEvent *notify; | 23124 | XRRScreenChangeNotifyEvent *notify; |
| @@ -22561,13 +23146,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 22561 | else | 23146 | else |
| 22562 | timestamp = 0; | 23147 | timestamp = 0; |
| 22563 | 23148 | ||
| 22564 | ev = (kbd_store_ptr == kbd_buffer | 23149 | if (x_find_monitors_changed_event (dpyinfo)) |
| 22565 | ? kbd_buffer + KBD_BUFFER_SIZE - 1 | ||
| 22566 | : kbd_store_ptr - 1); | ||
| 22567 | |||
| 22568 | if (kbd_store_ptr != kbd_fetch_ptr | ||
| 22569 | && ev->ie.kind == MONITORS_CHANGED_EVENT | ||
| 22570 | && XTERMINAL (ev->ie.arg) == dpyinfo->terminal) | ||
| 22571 | /* Don't store a MONITORS_CHANGED_EVENT if there is | 23150 | /* Don't store a MONITORS_CHANGED_EVENT if there is |
| 22572 | already an undelivered event on the queue. */ | 23151 | already an undelivered event on the queue. */ |
| 22573 | goto OTHER; | 23152 | goto OTHER; |
| @@ -22655,6 +23234,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 22655 | if (do_help > 0) | 23234 | if (do_help > 0) |
| 22656 | { | 23235 | { |
| 22657 | any_help_event_p = true; | 23236 | any_help_event_p = true; |
| 23237 | #ifdef HAVE_XINPUT2 | ||
| 23238 | if (gen_help_device) | ||
| 23239 | xi_handle_interaction (dpyinfo, f, | ||
| 23240 | gen_help_device, | ||
| 23241 | gen_help_time); | ||
| 23242 | #endif | ||
| 22658 | gen_help_event (help_echo_string, frame, help_echo_window, | 23243 | gen_help_event (help_echo_string, frame, help_echo_window, |
| 22659 | help_echo_object, help_echo_pos); | 23244 | help_echo_object, help_echo_pos); |
| 22660 | } | 23245 | } |
| @@ -23132,8 +23717,6 @@ x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x, | |||
| 23132 | xic_set_preeditarea (w, x, y); | 23717 | xic_set_preeditarea (w, x, y); |
| 23133 | #endif | 23718 | #endif |
| 23134 | } | 23719 | } |
| 23135 | |||
| 23136 | XFlush (FRAME_X_DISPLAY (f)); | ||
| 23137 | } | 23720 | } |
| 23138 | 23721 | ||
| 23139 | 23722 | ||
| @@ -25648,6 +26231,7 @@ x_make_frame_visible (struct frame *f) | |||
| 25648 | struct x_display_info *dpyinfo; | 26231 | struct x_display_info *dpyinfo; |
| 25649 | struct x_output *output; | 26232 | struct x_output *output; |
| 25650 | #endif | 26233 | #endif |
| 26234 | bool output_flushed; | ||
| 25651 | 26235 | ||
| 25652 | if (FRAME_PARENT_FRAME (f)) | 26236 | if (FRAME_PARENT_FRAME (f)) |
| 25653 | { | 26237 | { |
| @@ -25738,8 +26322,6 @@ x_make_frame_visible (struct frame *f) | |||
| 25738 | } | 26322 | } |
| 25739 | } | 26323 | } |
| 25740 | 26324 | ||
| 25741 | XFlush (FRAME_X_DISPLAY (f)); | ||
| 25742 | |||
| 25743 | /* Synchronize to ensure Emacs knows the frame is visible | 26325 | /* Synchronize to ensure Emacs knows the frame is visible |
| 25744 | before we do anything else. We do this loop with input not blocked | 26326 | before we do anything else. We do this loop with input not blocked |
| 25745 | so that incoming events are handled. */ | 26327 | so that incoming events are handled. */ |
| @@ -25758,6 +26340,10 @@ x_make_frame_visible (struct frame *f) | |||
| 25758 | /* This must come after we set COUNT. */ | 26340 | /* This must come after we set COUNT. */ |
| 25759 | unblock_input (); | 26341 | unblock_input (); |
| 25760 | 26342 | ||
| 26343 | /* Keep track of whether or not the output buffer was flushed, to | ||
| 26344 | avoid any extra flushes. */ | ||
| 26345 | output_flushed = false; | ||
| 26346 | |||
| 25761 | /* We unblock here so that arriving X events are processed. */ | 26347 | /* We unblock here so that arriving X events are processed. */ |
| 25762 | 26348 | ||
| 25763 | /* Now move the window back to where it was "supposed to be". | 26349 | /* Now move the window back to where it was "supposed to be". |
| @@ -25791,6 +26377,7 @@ x_make_frame_visible (struct frame *f) | |||
| 25791 | there, and take the potential window manager hit. */ | 26377 | there, and take the potential window manager hit. */ |
| 25792 | XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), | 26378 | XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), |
| 25793 | &rootw, &x, &y, &width, &height, &border, &depth); | 26379 | &rootw, &x, &y, &width, &height, &border, &depth); |
| 26380 | output_flushed = true; | ||
| 25794 | 26381 | ||
| 25795 | if (original_left != x || original_top != y) | 26382 | if (original_left != x || original_top != y) |
| 25796 | XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), | 26383 | XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), |
| @@ -25825,7 +26412,11 @@ x_make_frame_visible (struct frame *f) | |||
| 25825 | (f, build_string ("x_make_frame_visible")); | 26412 | (f, build_string ("x_make_frame_visible")); |
| 25826 | 26413 | ||
| 25827 | x_wait_for_event (f, MapNotify); | 26414 | x_wait_for_event (f, MapNotify); |
| 26415 | output_flushed = true; | ||
| 25828 | } | 26416 | } |
| 26417 | |||
| 26418 | if (!output_flushed) | ||
| 26419 | x_flush (f); | ||
| 25829 | } | 26420 | } |
| 25830 | } | 26421 | } |
| 25831 | 26422 | ||
| @@ -26045,6 +26636,11 @@ x_free_frame_resources (struct frame *f) | |||
| 26045 | 26636 | ||
| 26046 | block_input (); | 26637 | block_input (); |
| 26047 | 26638 | ||
| 26639 | #ifdef HAVE_XINPUT2 | ||
| 26640 | /* Remove any record of this frame being focused. */ | ||
| 26641 | xi_handle_delete_frame (dpyinfo, f); | ||
| 26642 | #endif | ||
| 26643 | |||
| 26048 | /* If a display connection is dead, don't try sending more | 26644 | /* If a display connection is dead, don't try sending more |
| 26049 | commands to the X server. */ | 26645 | commands to the X server. */ |
| 26050 | if (dpyinfo->display) | 26646 | if (dpyinfo->display) |
| @@ -26192,7 +26788,10 @@ x_free_frame_resources (struct frame *f) | |||
| 26192 | if (f->output_data.x->bottom_left_corner_cursor != 0) | 26788 | if (f->output_data.x->bottom_left_corner_cursor != 0) |
| 26193 | XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor); | 26789 | XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor); |
| 26194 | 26790 | ||
| 26195 | XFlush (FRAME_X_DISPLAY (f)); | 26791 | /* Free sync fences. */ |
| 26792 | #if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK | ||
| 26793 | x_sync_free_fences (f); | ||
| 26794 | #endif | ||
| 26196 | } | 26795 | } |
| 26197 | 26796 | ||
| 26198 | #ifdef HAVE_GTK3 | 26797 | #ifdef HAVE_GTK3 |
| @@ -27416,6 +28015,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) | |||
| 27416 | int minor = 0; | 28015 | int minor = 0; |
| 27417 | #endif | 28016 | #endif |
| 27418 | 28017 | ||
| 28018 | dpyinfo->client_pointer_device = -1; | ||
| 28019 | |||
| 27419 | if (XQueryExtension (dpyinfo->display, "XInputExtension", | 28020 | if (XQueryExtension (dpyinfo->display, "XInputExtension", |
| 27420 | &dpyinfo->xi2_opcode, &xi_first_event, | 28021 | &dpyinfo->xi2_opcode, &xi_first_event, |
| 27421 | &xi_first_error)) | 28022 | &xi_first_error)) |
diff --git a/src/xterm.h b/src/xterm.h index 2b8a2e5da49..e97f3d4c831 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -238,23 +238,54 @@ struct xi_touch_point_t | |||
| 238 | 238 | ||
| 239 | struct xi_device_t | 239 | struct xi_device_t |
| 240 | { | 240 | { |
| 241 | /* The numerical ID of this device. */ | ||
| 241 | int device_id; | 242 | int device_id; |
| 243 | |||
| 242 | #ifdef HAVE_XINPUT2_1 | 244 | #ifdef HAVE_XINPUT2_1 |
| 245 | /* The number of scroll valuators in `valuators'. */ | ||
| 243 | int scroll_valuator_count; | 246 | int scroll_valuator_count; |
| 244 | #endif | 247 | #endif |
| 248 | |||
| 249 | /* Whether or not the device is grabbed and its use. */ | ||
| 245 | int grab, use; | 250 | int grab, use; |
| 251 | |||
| 252 | /* The attached device. Only valid if USE is some kind of master | ||
| 253 | device. */ | ||
| 254 | int attachment; | ||
| 255 | |||
| 246 | #ifdef HAVE_XINPUT2_2 | 256 | #ifdef HAVE_XINPUT2_2 |
| 257 | /* Whether or not this device is a direct touch device. */ | ||
| 247 | bool direct_p; | 258 | bool direct_p; |
| 248 | #endif | 259 | #endif |
| 249 | 260 | ||
| 250 | #ifdef HAVE_XINPUT2_1 | 261 | #ifdef HAVE_XINPUT2_1 |
| 262 | /* An array of scroll valuators Emacs knows about. */ | ||
| 251 | struct xi_scroll_valuator_t *valuators; | 263 | struct xi_scroll_valuator_t *valuators; |
| 252 | #endif | 264 | #endif |
| 265 | |||
| 253 | #ifdef HAVE_XINPUT2_2 | 266 | #ifdef HAVE_XINPUT2_2 |
| 267 | /* An array of in-progress touchscreen events. */ | ||
| 254 | struct xi_touch_point_t *touchpoints; | 268 | struct xi_touch_point_t *touchpoints; |
| 255 | #endif | 269 | #endif |
| 256 | 270 | ||
| 271 | /* The name of this device. */ | ||
| 257 | Lisp_Object name; | 272 | Lisp_Object name; |
| 273 | |||
| 274 | /* The time at which `focus_frame' became the keyboard focus (only | ||
| 275 | applies to master devices). */ | ||
| 276 | Time focus_frame_time; | ||
| 277 | |||
| 278 | /* The frame that is currently this device's keyboard focus, or | ||
| 279 | NULL. */ | ||
| 280 | struct frame *focus_frame; | ||
| 281 | |||
| 282 | /* The time at which `focus_frame' became the implicit keyboard | ||
| 283 | focus. */ | ||
| 284 | Time focus_implicit_time; | ||
| 285 | |||
| 286 | /* The frame that is currently this device's implicit keyboard | ||
| 287 | focus, or NULL. */ | ||
| 288 | struct frame *focus_implicit_frame; | ||
| 258 | }; | 289 | }; |
| 259 | #endif | 290 | #endif |
| 260 | 291 | ||
| @@ -482,7 +513,10 @@ struct x_display_info | |||
| 482 | /* The last frame mentioned in a FocusIn or FocusOut event. This is | 513 | /* The last frame mentioned in a FocusIn or FocusOut event. This is |
| 483 | separate from x_focus_frame, because whether or not LeaveNotify | 514 | separate from x_focus_frame, because whether or not LeaveNotify |
| 484 | events cause us to lose focus depends on whether or not we have | 515 | events cause us to lose focus depends on whether or not we have |
| 485 | received a FocusIn event for it. */ | 516 | received a FocusIn event for it. |
| 517 | |||
| 518 | This field is not used when the input extension is being | ||
| 519 | utilized. */ | ||
| 486 | struct frame *x_focus_event_frame; | 520 | struct frame *x_focus_event_frame; |
| 487 | 521 | ||
| 488 | /* The frame which currently has the visual highlight, and should get | 522 | /* The frame which currently has the visual highlight, and should get |
| @@ -614,9 +648,9 @@ struct x_display_info | |||
| 614 | Xatom_net_wm_state_shaded, Xatom_net_frame_extents, Xatom_net_current_desktop, | 648 | Xatom_net_wm_state_shaded, Xatom_net_frame_extents, Xatom_net_current_desktop, |
| 615 | Xatom_net_workarea, Xatom_net_wm_opaque_region, Xatom_net_wm_ping, | 649 | Xatom_net_workarea, Xatom_net_wm_opaque_region, Xatom_net_wm_ping, |
| 616 | Xatom_net_wm_sync_request, Xatom_net_wm_sync_request_counter, | 650 | Xatom_net_wm_sync_request, Xatom_net_wm_sync_request_counter, |
| 617 | Xatom_net_wm_frame_drawn, Xatom_net_wm_frame_timings, Xatom_net_wm_user_time, | 651 | Xatom_net_wm_sync_fences, Xatom_net_wm_frame_drawn, Xatom_net_wm_frame_timings, |
| 618 | Xatom_net_wm_user_time_window, Xatom_net_client_list_stacking, | 652 | Xatom_net_wm_user_time, Xatom_net_wm_user_time_window, |
| 619 | Xatom_net_wm_pid; | 653 | Xatom_net_client_list_stacking, Xatom_net_wm_pid; |
| 620 | 654 | ||
| 621 | /* XSettings atoms and windows. */ | 655 | /* XSettings atoms and windows. */ |
| 622 | Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; | 656 | Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; |
| @@ -678,13 +712,27 @@ struct x_display_info | |||
| 678 | 712 | ||
| 679 | #ifdef HAVE_XINPUT2 | 713 | #ifdef HAVE_XINPUT2 |
| 680 | bool supports_xi2; | 714 | bool supports_xi2; |
| 715 | |||
| 716 | /* The minor version of the input extension. (Major is always | ||
| 717 | 2.x.) */ | ||
| 681 | int xi2_version; | 718 | int xi2_version; |
| 719 | |||
| 720 | /* The generic event opcode of XI2 events. */ | ||
| 682 | int xi2_opcode; | 721 | int xi2_opcode; |
| 683 | 722 | ||
| 723 | /* The number of devices on this display known to Emacs. */ | ||
| 684 | int num_devices; | 724 | int num_devices; |
| 725 | |||
| 726 | /* Array of all input extension devices on this display known to | ||
| 727 | Emacs. */ | ||
| 685 | struct xi_device_t *devices; | 728 | struct xi_device_t *devices; |
| 686 | 729 | ||
| 730 | /* Pending keystroke time. */ | ||
| 687 | Time pending_keystroke_time; | 731 | Time pending_keystroke_time; |
| 732 | |||
| 733 | /* Pending keystroke source. If a core KeyPress event arrives with | ||
| 734 | the same timestamp as pending_keystroke_time, it will be treated | ||
| 735 | as originating from this device. */ | ||
| 688 | int pending_keystroke_source; | 736 | int pending_keystroke_source; |
| 689 | 737 | ||
| 690 | #if defined USE_GTK && !defined HAVE_GTK3 | 738 | #if defined USE_GTK && !defined HAVE_GTK3 |
| @@ -694,6 +742,10 @@ struct x_display_info | |||
| 694 | input method) core key event. */ | 742 | input method) core key event. */ |
| 695 | bool pending_keystroke_time_special_p; | 743 | bool pending_keystroke_time_special_p; |
| 696 | #endif | 744 | #endif |
| 745 | |||
| 746 | /* The client pointer. We keep a record client-side to avoid | ||
| 747 | calling XISetClientPointer all the time. */ | ||
| 748 | int client_pointer_device; | ||
| 697 | #endif | 749 | #endif |
| 698 | 750 | ||
| 699 | #ifdef HAVE_XKB | 751 | #ifdef HAVE_XKB |
| @@ -769,6 +821,16 @@ struct x_display_info | |||
| 769 | /* The pending drag-and-drop time for middle-click based | 821 | /* The pending drag-and-drop time for middle-click based |
| 770 | drag-and-drop emulation. */ | 822 | drag-and-drop emulation. */ |
| 771 | Time pending_dnd_time; | 823 | Time pending_dnd_time; |
| 824 | |||
| 825 | #if defined HAVE_XSYNC && !defined USE_GTK | ||
| 826 | /* Whether or not the server time is probably the same as | ||
| 827 | "clock_gettime (CLOCK_MONOTONIC, ...)". */ | ||
| 828 | bool server_time_monotonic_p; | ||
| 829 | |||
| 830 | /* The time difference between the X server clock and the monotonic | ||
| 831 | clock. */ | ||
| 832 | int64_t server_time_offset; | ||
| 833 | #endif | ||
| 772 | }; | 834 | }; |
| 773 | 835 | ||
| 774 | #ifdef HAVE_X_I18N | 836 | #ifdef HAVE_X_I18N |
| @@ -1061,6 +1123,19 @@ struct x_output | |||
| 1061 | /* Whether or not Emacs should wait for the compositing manager to | 1123 | /* Whether or not Emacs should wait for the compositing manager to |
| 1062 | draw frames before starting a new frame. */ | 1124 | draw frames before starting a new frame. */ |
| 1063 | bool_bf use_vsync_p : 1; | 1125 | bool_bf use_vsync_p : 1; |
| 1126 | |||
| 1127 | /* The time (in microseconds) it took to draw the last frame. */ | ||
| 1128 | uint64_t last_frame_time; | ||
| 1129 | |||
| 1130 | /* A temporary time used to calculate that value. */ | ||
| 1131 | uint64_t temp_frame_time; | ||
| 1132 | |||
| 1133 | #ifdef HAVE_XSYNCTRIGGERFENCE | ||
| 1134 | /* An array of two sync fences that are triggered in order after a | ||
| 1135 | frame completes. Not initialized if the XSync extension is too | ||
| 1136 | old to support sync fences. */ | ||
| 1137 | XSyncFence sync_fences[2]; | ||
| 1138 | #endif | ||
| 1064 | #endif | 1139 | #endif |
| 1065 | #endif | 1140 | #endif |
| 1066 | 1141 | ||
| @@ -1078,7 +1153,9 @@ struct x_output | |||
| 1078 | 1153 | ||
| 1079 | /* Keep track of focus. May be EXPLICIT if we received a FocusIn for this | 1154 | /* Keep track of focus. May be EXPLICIT if we received a FocusIn for this |
| 1080 | frame, or IMPLICIT if we received an EnterNotify. | 1155 | frame, or IMPLICIT if we received an EnterNotify. |
| 1081 | FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */ | 1156 | FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. |
| 1157 | |||
| 1158 | Not used when the input extension is being utilized. */ | ||
| 1082 | int focus_state; | 1159 | int focus_state; |
| 1083 | 1160 | ||
| 1084 | /* The offset we need to add to compensate for type A WMs. */ | 1161 | /* The offset we need to add to compensate for type A WMs. */ |
| @@ -1500,6 +1577,9 @@ extern void x_make_frame_invisible (struct frame *); | |||
| 1500 | extern void x_iconify_frame (struct frame *); | 1577 | extern void x_iconify_frame (struct frame *); |
| 1501 | extern void x_free_frame_resources (struct frame *); | 1578 | extern void x_free_frame_resources (struct frame *); |
| 1502 | extern void x_wm_set_size_hint (struct frame *, long, bool); | 1579 | extern void x_wm_set_size_hint (struct frame *, long, bool); |
| 1580 | #if defined HAVE_XSYNCTRIGGERFENCE && !defined USE_GTK | ||
| 1581 | extern void x_sync_init_fences (struct frame *); | ||
| 1582 | #endif | ||
| 1503 | 1583 | ||
| 1504 | extern void x_delete_terminal (struct terminal *); | 1584 | extern void x_delete_terminal (struct terminal *); |
| 1505 | extern Cursor x_create_font_cursor (struct x_display_info *, int); | 1585 | extern Cursor x_create_font_cursor (struct x_display_info *, int); |
| @@ -1541,11 +1621,14 @@ extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t); | |||
| 1541 | #ifdef HAVE_XRENDER | 1621 | #ifdef HAVE_XRENDER |
| 1542 | extern void x_xrender_color_from_gc_background (struct frame *, GC, | 1622 | extern void x_xrender_color_from_gc_background (struct frame *, GC, |
| 1543 | XRenderColor *, bool); | 1623 | XRenderColor *, bool); |
| 1544 | extern void x_xr_ensure_picture (struct frame *f); | 1624 | extern void x_xr_ensure_picture (struct frame *); |
| 1545 | extern void x_xr_apply_ext_clip (struct frame *f, GC gc); | 1625 | extern void x_xr_apply_ext_clip (struct frame *, GC); |
| 1546 | extern void x_xr_reset_ext_clip (struct frame *f); | 1626 | extern void x_xr_reset_ext_clip (struct frame *); |
| 1547 | #endif | 1627 | #endif |
| 1548 | 1628 | ||
| 1629 | extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *, | ||
| 1630 | int *, int *, int *, unsigned int *); | ||
| 1631 | |||
| 1549 | #ifdef HAVE_GTK3 | 1632 | #ifdef HAVE_GTK3 |
| 1550 | extern void x_scroll_bar_configure (GdkEvent *); | 1633 | extern void x_scroll_bar_configure (GdkEvent *); |
| 1551 | #endif | 1634 | #endif |