1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-09 08:21:30 -07:00

Merge remote-tracking branch 'origin/master' into feature/pgtk

This commit is contained in:
Po Lu 2021-12-17 14:23:07 +08:00
commit 5e5cde55e5
31 changed files with 670 additions and 365 deletions

View file

@ -1175,6 +1175,7 @@ intended by Lisp code to be used as an event.
* Button-Down Events:: A button was pushed and not yet released.
* Repeat Events:: Double and triple click (or drag, or down).
* Motion Events:: Just moving the mouse, not pushing a button.
* Touchscreen Events:: Tapping and moving fingers on a touchscreen.
* Focus Events:: Moving the mouse between frames.
* Xwidget Events:: Events generated by xwidgets.
* Misc Events:: Other events the system can generate.
@ -1835,6 +1836,60 @@ small movements. Otherwise, motion events are not generated as long
as the mouse cursor remains pointing to the same glyph in the text.
@end defvar
@node Touchscreen Events
@subsection Touchscreen Events
@cindex touchscreen events
@cindex support for touchscreens
Some window systems provide support for input devices that react to
the user's finger, and translate those finger movements into points at
an on-screen position. These input devices are known as touchscreens,
and Emacs reports the movements they generate as @dfn{touchscreen
events}.
Most individual events generated by a touchscreen only have meaning as
part of a larger sequence of other events: for instance, the simple
operation of tapping the touchscreen involves the user placing and
releasing a finger on the touchscreen, and swiping the display to
scroll it involves placing a finger, moving it many times upwards or
downwards, and then releasing the finger.
While a simplistic model consisting of one finger is adequate for taps
and scrolling, more complicated gestures require support for keeping
track of multiple fingers, where the position of each finger is
represented by a @dfn{touch point}. For example, a ``pinch to zoom''
gesture might consist of the user placing two fingers and moving them
individually in opposite directions, where the distance between the
positions of their individual points determine the amount by which to
zoom the display, and the center of an imaginary line between those
positions determines where to pan the display after zooming.
@cindex touch point representation
The low-level touchscreen events described below can be used to
implement all the touch sequences described above. In those events,
each point is represented by a cons of an arbitrary number identifying
the point and a mouse position list (@pxref{Click Events}) specifying
the position of the finger when the event occurred.
@table @code
@cindex @code{touchscreen-begin} event
@item (touchscreen-begin @var{point})
This event is sent when @var{point} is created by the user pressing a
finger against the touchscreen.
@cindex @code{touchscreen-update} event
@item (touchscreen-update @var{points})
This event is sent when an point on the touchscreen has changed
position. @var{points} is a list of touchpoints containing the
up-to-date positions of each touchpoint currently on the touchscreen.
@cindex @code{touchscreen-end} event
@item (touchscreen-end @var{point})
This event is sent when @var{point} is no longer present on the
display, because another program took the grab, or because the user
released the finger.
@end table
@node Focus Events
@subsection Focus Events
@cindex focus event

View file

@ -1352,7 +1352,7 @@ may change as higher-resolution clocks become available.
@cindex time value
Function arguments, e.g., the @var{time} argument to
@code{current-time-string}, accept a more-general @dfn{time value}
@code{format-time-string}, accept a more-general @dfn{time value}
format, which can be a Lisp timestamp, @code{nil} for the current
time, a single floating-point number for seconds, or a list
@code{(@var{high} @var{low} @var{micro})} or @code{(@var{high}
@ -1507,10 +1507,7 @@ The optional @var{form} argument specifies the timestamp form to be
returned. If @var{form} is the symbol @code{integer}, this function
returns an integer count of seconds. If @var{form} is a positive
integer, it specifies a clock frequency and this function returns an
integer-pair timestamp @code{(@var{ticks}
. @var{form})}.@footnote{Currently a positive integer @var{form}
should be at least 65536 if the returned value is intended to be given
to standard functions expecting Lisp timestamps.} If @var{form} is
integer-pair timestamp @code{(@var{ticks} . @var{form})}. If @var{form} is
@code{t}, this function treats it as a positive integer suitable for
representing the timestamp; for example, it is treated as 1000000000
if @var{time} is nil and the platform timestamp has nanosecond

View file

@ -1151,11 +1151,23 @@ cookies set by web pages on disk.
** New variable 'help-buffer-under-preparation'.
This variable is bound to t during the preparation of a "*Help*" buffer.
+++
** Timestamps like (1 . 1000) now work without warnings being generated.
For example, (time-add nil '(1 . 1000)) no longer warns that the
(1 . 1000) acts like (1000 . 1000000). This warning, which was a
temporary transition aid for Emacs 27, has served its purpose.
+++
** 'date-to-time' now assumes earliest values if its argument lacks
month, day, or time. For example, (date-to-time "2021-12-04") now
assumes a time of 00:00 instead of signaling an error.
+++
** New events for taking advantage of touchscreen devices.
The events 'touchscreen-down', 'touchscreen-update' and
'touchscreen-end' have been added to take better advantage of
touch-capable display panels.
* Changes in Emacs 29.1 on Non-Free Operating Systems

View file

@ -617,12 +617,8 @@ OLDMODE will be modified accordingly just like chmod(2) would have done."
(defun archive-unixdate (low high)
"Stringify Unix (LOW HIGH) date."
(let* ((time (list high low))
(str (current-time-string time)))
(format "%s-%s-%s"
(substring str 8 10)
(substring str 4 7)
(format-time-string "%Y" time))))
(let ((system-time-locale "C"))
(format-time-string "%e-%b-%Y" (list high low))))
(defun archive-unixtime (low high)
"Stringify Unix (LOW HIGH) time."

View file

@ -645,10 +645,10 @@ FIXME: multiple comma-separated values should be allowed!"
(setq second (read (substring isodatetimestring 13 15))))
;; FIXME: Support subseconds.
(when (> (length isodatetimestring) 15)
(cl-case (aref isodatetimestring 15)
(pcase (aref isodatetimestring 15)
(?Z
(setq source-zone t))
((?- ?+)
((or ?- ?+)
(setq source-zone
(concat "UTC" (substring isodatetimestring 15))))))
;; shift if necessary

View file

@ -295,12 +295,12 @@ enough, since keyservers have strict timeout settings."
:created
(and (match-string 4)
(not (string-empty-p (match-string 4)))
(seconds-to-time
(time-convert
(string-to-number (match-string 4))))
:expires
(and (match-string 5)
(not (string-empty-p (match-string 5)))
(seconds-to-time
(time-convert
(string-to-number (match-string 5))))
:flags
(mapcar (lambda (flag)
@ -319,15 +319,11 @@ enough, since keyservers have strict timeout settings."
:created
(and (match-string 2)
(not (string-empty-p (match-string 2)))
(decode-time (seconds-to-time
(string-to-number
(match-string 2)))))
(decode-time (string-to-number (match-string 2))))
:expires
(and (match-string 3)
(not (string-empty-p (match-string 3)))
(decode-time (seconds-to-time
(string-to-number
(match-string 3)))))
(decode-time (string-to-number (match-string 3))))
:flags
(mapcar (lambda (flag)
(cdr (assq flag '((?r revoked)

View file

@ -578,7 +578,7 @@ REL-DATE, or (current-time) if REL-DATE is nil."
(seq-subseq
(decode-time
(time-subtract
(apply #'encode-time now)
(encode-time now)
(days-to-time
(* (string-to-number (match-string 1 value))
(cdr (assoc (match-string 2 value)
@ -597,7 +597,7 @@ REL-DATE, or (current-time) if REL-DATE is nil."
;; If DOW is given, handle that specially.
(if (and (seq-elt d-time 6) (null (seq-elt d-time 3)))
(decode-time
(time-subtract (apply #'encode-time now)
(time-subtract (encode-time now)
(days-to-time
(+ (if (> (seq-elt d-time 6)
(seq-elt now 6))
@ -1257,9 +1257,7 @@ elements are present."
(setq dmonth 1))))
(format-time-string
"%e-%b-%Y"
(apply #'encode-time
(append '(0 0 0)
(list dday dmonth dyear))))))
(encode-time 0 0 0 dday dmonth dyear))))
(cl-defmethod gnus-search-imap-handle-string ((engine gnus-search-imap)
(str string))

View file

@ -1308,7 +1308,7 @@ all. This may very well take some time.")
(let ((minute (nndiary-max (nth 0 sched)))
(hour (nndiary-max (nth 1 sched)))
(year (nndiary-max (nth 4 sched)))
(time-zone (or (and (nth 6 sched) (car (nth 6 sched)))
(time-zone (or (car (nth 6 sched))
(current-time-zone))))
(when year
(or minute (setq minute 59))
@ -1405,7 +1405,7 @@ all. This may very well take some time.")
t))
(dow-list (nth 5 sched))
(year (1- this-year))
(time-zone (or (and (nth 6 sched) (car (nth 6 sched)))
(time-zone (or (car (nth 6 sched))
(current-time-zone))))
;; Special case: an asterisk in one of the days specifications means that
;; only the other should be taken into account. If both are unspecified,

View file

@ -450,7 +450,7 @@ nnrss: %s: Not valid XML %s and libxml-parse-html-region doesn't work %s"
This function handles the ISO 8601 date format described in
URL `https://www.w3.org/TR/NOTE-datetime', and also the RFC 822 style
which RSS 2.0 allows."
(let (case-fold-search vector year month day time zone cts given)
(let (case-fold-search vector year month day time zone given)
(cond ((null date)) ; do nothing for this case
;; if the date is just digits (unix time stamp):
((string-match "^[0-9]+$" date)
@ -481,13 +481,13 @@ which RSS 2.0 allows."
0
(decoded-time-zone decoded))))))
(if month
(progn
(setq cts (current-time-string (encode-time 0 0 0 day month year)))
(format "%s, %02d %s %04d %s%s"
(substring cts 0 3) day (substring cts 4 7) year time
(if zone
(concat " " (format-time-string "%z" nil zone))
"")))
(concat (let ((system-time-locale "C"))
(format-time-string "%a, %d %b %Y "
(encode-time 0 0 0 day month year)))
time
(if zone
(format-time-string " %z" nil zone)
""))
(message-make-date given))))
;;; data functions

View file

@ -718,10 +718,9 @@ representing leap seconds."
second)
minute hour day month year second-fraction datatype time-zone)
(let ((time
(apply
#'encode-time (list
(if new-decode-time new-decode-time-second second)
minute hour day month year nil nil time-zone))))
(encode-time (list
(if new-decode-time new-decode-time-second second)
minute hour day month year nil nil time-zone))))
(if new-decode-time
(with-no-warnings (decode-time time nil t))
(decode-time time))))))

View file

@ -416,9 +416,9 @@ Emacs dired can't find files."
"Sort \"ls\" output by time, descending."
(let (time-a time-b)
(string-match tramp-adb-ls-date-regexp a)
(setq time-a (apply #'encode-time (parse-time-string (match-string 0 a))))
(setq time-a (encode-time (parse-time-string (match-string 0 a))))
(string-match tramp-adb-ls-date-regexp b)
(setq time-b (apply #'encode-time (parse-time-string (match-string 0 b))))
(setq time-b (encode-time (parse-time-string (match-string 0 b))))
(time-less-p time-b time-a)))
(defun tramp-adb-ls-output-name-less-p (a b)

View file

@ -1575,7 +1575,7 @@ non-nil."
(setq link
(format-time-string
(car org-time-stamp-formats)
(apply 'encode-time
(encode-time
(list 0 0 0 (nth 1 cd) (nth 0 cd) (nth 2 cd)
nil nil nil))))
(org-link-store-props :type "calendar" :date cd)))

View file

@ -1904,11 +1904,11 @@ PROPNAME lets you set a custom text property instead of :org-clock-minutes."
((match-end 2)
;; Two time stamps.
(let* ((ts (float-time
(apply #'encode-time
(encode-time
(save-match-data
(org-parse-time-string (match-string 2))))))
(te (float-time
(apply #'encode-time
(encode-time
(org-parse-time-string (match-string 3)))))
(dt (- (if tend (min te tend) te)
(if tstart (max ts tstart) ts))))
@ -2837,7 +2837,7 @@ a number of clock tables."
(pcase (if range (car range) (plist-get params :tstart))
((and (pred numberp) n)
(pcase-let ((`(,m ,d ,y) (calendar-gregorian-from-absolute n)))
(apply #'encode-time (list 0 0 org-extend-today-until d m y))))
(encode-time 0 0 org-extend-today-until d m y)))
(timestamp
(seconds-to-time
(org-matcher-time (or timestamp
@ -2847,7 +2847,7 @@ a number of clock tables."
(pcase (if range (nth 1 range) (plist-get params :tend))
((and (pred numberp) n)
(pcase-let ((`(,m ,d ,y) (calendar-gregorian-from-absolute n)))
(apply #'encode-time (list 0 0 org-extend-today-until d m y))))
(encode-time 0 0 org-extend-today-until d m y)))
(timestamp (seconds-to-time (org-matcher-time timestamp))))))
(while (time-less-p start end)
(unless (bolp) (insert "\n"))
@ -3042,9 +3042,9 @@ Otherwise, return nil."
(setq ts (match-string 1)
te (match-string 3))
(setq s (- (float-time
(apply #'encode-time (org-parse-time-string te)))
(encode-time (org-parse-time-string te)))
(float-time
(apply #'encode-time (org-parse-time-string ts))))
(encode-time (org-parse-time-string ts))))
neg (< s 0)
s (abs s)
h (floor (/ s 3600))

View file

@ -782,7 +782,7 @@ around it."
(setq time-after (copy-sequence time))
(setf (nth 3 time-before) (1- (nth 3 time)))
(setf (nth 3 time-after) (1+ (nth 3 time)))
(mapcar (lambda (x) (format-time-string fmt (apply #'encode-time x)))
(mapcar (lambda (x) (format-time-string fmt (encode-time x)))
(list time-before time time-after)))))
(defun org-columns-open-link (&optional arg)

View file

@ -378,7 +378,7 @@ Return value as a string."
(buffer-substring
(point) (line-end-position)))))
(when (cl-some #'identity time)
(setq date (apply #'encode-time time))))))))
(setq date (encode-time time))))))))
(let ((proc (get-buffer-process buf)))
(while (and proc (accept-process-output proc .5 nil t)))))
(kill-buffer buf))

View file

@ -1185,7 +1185,7 @@ nil, just return 0."
((numberp s) s)
((stringp s)
(condition-case nil
(float-time (apply #'encode-time (org-parse-time-string s)))
(float-time (encode-time (org-parse-time-string s)))
(error 0)))
(t 0)))
@ -1252,7 +1252,7 @@ following special strings: \"<now>\", \"<today>\",
\"<tomorrow>\", and \"<yesterday>\".
Return 0. if S is not recognized as a valid value."
(let ((today (float-time (apply #'encode-time
(let ((today (float-time (encode-time
(append '(0 0 0) (nthcdr 3 (decode-time)))))))
(save-match-data
(cond

View file

@ -2606,7 +2606,7 @@ location of point."
(format-time-string
(org-time-stamp-format
(string-match-p "[0-9]\\{1,2\\}:[0-9]\\{2\\}" ts))
(apply #'encode-time
(encode-time
(save-match-data (org-parse-time-string ts))))))
form t t))

View file

@ -13987,7 +13987,7 @@ user."
(when (< (nth 2 org-defdecode) org-extend-today-until)
(setf (nth 2 org-defdecode) -1)
(setf (nth 1 org-defdecode) 59)
(setq org-def (apply #'encode-time org-defdecode))
(setq org-def (encode-time org-defdecode))
(setq org-defdecode (decode-time org-def)))
(let* ((timestr (format-time-string
(if org-with-time "%Y-%m-%d %H:%M" "%Y-%m-%d")
@ -14471,7 +14471,7 @@ The command returns the inserted time stamp."
time (org-fix-decoded-time t1)
str (org-add-props
(format-time-string
(substring tf 1 -1) (apply 'encode-time time))
(substring tf 1 -1) (encode-time time))
nil 'mouse-face 'highlight))
(put-text-property beg end 'display str)))
@ -14726,7 +14726,7 @@ days in order to avoid rounding problems."
(defun org-time-string-to-time (s)
"Convert timestamp string S into internal time."
(apply #'encode-time (org-parse-time-string s)))
(encode-time (org-parse-time-string s)))
(defun org-time-string-to-seconds (s)
"Convert a timestamp string S into a number of seconds."
@ -15156,7 +15156,7 @@ When SUPPRESS-TMP-DELAY is non-nil, suppress delays like
(setcar time0 (or (car time0) 0))
(setcar (nthcdr 1 time0) (or (nth 1 time0) 0))
(setcar (nthcdr 2 time0) (or (nth 2 time0) 0))
(setq time (apply 'encode-time time0))))
(setq time (encode-time time0))))
;; Insert the new time-stamp, and ensure point stays in the same
;; category as before (i.e. not after the last position in that
;; category).

View file

@ -824,8 +824,7 @@ as a communication channel."
(if (not (plist-get info :with-author)) ""
(org-export-data (plist-get info :author) info))
;; Timezone.
(if (org-string-nw-p org-icalendar-timezone) org-icalendar-timezone
(cadr (current-time-zone)))
(or (org-string-nw-p org-icalendar-timezone) (format-time-string "%Z"))
;; Description.
(org-export-data (plist-get info :title) info)
contents))
@ -972,7 +971,7 @@ This function assumes major mode for current buffer is
(org-icalendar--vcalendar
org-icalendar-combined-name
user-full-name
(or (org-string-nw-p org-icalendar-timezone) (cadr (current-time-zone)))
(or (org-string-nw-p org-icalendar-timezone) (format-time-string "%Z"))
org-icalendar-combined-description
contents)))
(run-hook-with-args 'org-icalendar-after-save-hook file)))
@ -995,7 +994,7 @@ FILES is a list of files to build the calendar from."
user-full-name
;; Timezone.
(or (org-string-nw-p org-icalendar-timezone)
(cadr (current-time-zone)))
(format-time-string "Z"))
;; Description.
org-icalendar-combined-description
;; Contents.

View file

@ -1175,6 +1175,7 @@ displayed."
(derived-mode . dired-mode)
(derived-mode . diff-mode)
(derived-mode . comint-mode)
(derived-mode . eshell-mode)
(derived-mode . change-log-mode))
"List of conditions to kill buffers related to a project.
This list is used by `project-kill-buffers'.

View file

@ -467,8 +467,8 @@ checksum before doing the check."
(defun tar-clip-time-string (time)
(declare (obsolete format-time-string "27.1"))
(let ((str (current-time-string time)))
(concat " " (substring str 4 16) (format-time-string " %Y" time))))
(let ((system-time-locale "C"))
(format-time-string " %b %e %H:%M %Y" time)))
(defun tar-grind-file-mode (mode)
"Construct a `rw-r--r--' string indicating MODE.

View file

@ -355,7 +355,7 @@ update which can wait for the next redisplay."
(am-pm (if (>= hour 12) "pm" "am"))
(minutes (substring time 14 16))
(seconds (substring time 17 19))
(time-zone (car (cdr (current-time-zone now))))
(time-zone (format-time-string "%Z" now))
(day (substring time 8 10))
(year (format-time-string "%Y" now))
(monthname (substring time 4 7))

View file

@ -299,11 +299,10 @@ Return a list in the same format as `current-time-zone's result,
or nil if the local time zone could not be computed.
DATE is the number of days elapsed since the (imaginary)
Gregorian date Sunday, December 31, 1 BC."
(and (fboundp 'current-time-zone)
(let ((utc-time (timezone-time-from-absolute date seconds)))
(and utc-time
(let ((zone (current-time-zone utc-time)))
(and (car zone) zone))))))
(let ((utc-time (timezone-time-from-absolute date seconds)))
(and utc-time
(let ((zone (current-time-zone utc-time)))
(and (car zone) zone)))))
(defun timezone-fix-time (date local timezone)
"Convert DATE (default timezone LOCAL) to YYYY-MM-DD-HH-MM-SS-ZONE vector.

View file

@ -127,8 +127,12 @@ preserve the setting."
:group 'vc)
(defcustom vc-command-messages nil
"If non-nil, display run messages from back-end commands."
:type 'boolean
"If non-nil, display and log messages about running back-end commands.
If the value is `log', messages about running VC back-end commands are
logged in the *Messages* buffer, but not displayed."
:type '(choice (const :tag "No messages" nil)
(const :tag "Display and log messages" t)
(const :tag "Log messages, but don't display" log))
:group 'vc)
(defcustom vc-suppress-confirm nil
@ -311,7 +315,10 @@ case, and the process object in the asynchronous case."
(substring command 0 -1)
command)
" " (vc-delistify flags)
" " (vc-delistify files))))
" " (vc-delistify files)))
(vc-inhibit-message
(or (eq vc-command-messages 'log)
(eq (selected-window) (active-minibuffer-window)))))
(save-current-buffer
(unless (or (eq buffer t)
(and (stringp buffer)
@ -335,7 +342,7 @@ case, and the process object in the asynchronous case."
(apply #'start-file-process command (current-buffer)
command squeezed))))
(when vc-command-messages
(let ((inhibit-message (eq (selected-window) (active-minibuffer-window))))
(let ((inhibit-message vc-inhibit-message))
(message "Running in background: %s" full-command)))
;; Get rid of the default message insertion, in case we don't
;; set a sentinel explicitly.
@ -345,11 +352,11 @@ case, and the process object in the asynchronous case."
(when vc-command-messages
(vc-run-delayed
(let ((message-truncate-lines t)
(inhibit-message (eq (selected-window) (active-minibuffer-window))))
(inhibit-message vc-inhibit-message))
(message "Done in background: %s" full-command)))))
;; Run synchronously
(when vc-command-messages
(let ((inhibit-message (eq (selected-window) (active-minibuffer-window))))
(let ((inhibit-message vc-inhibit-message))
(message "Running in foreground: %s" full-command)))
(let ((buffer-undo-list t))
(setq status (apply #'process-file command nil t nil squeezed)))
@ -364,7 +371,7 @@ case, and the process object in the asynchronous case."
(if (integerp status) (format "status %d" status) status)
full-command))
(when vc-command-messages
(let ((inhibit-message (eq (selected-window) (active-minibuffer-window))))
(let ((inhibit-message vc-inhibit-message))
(message "Done (status=%d): %s" status full-command)))))
(vc-run-delayed
(run-hook-with-args 'vc-post-command-functions

View file

@ -6013,6 +6013,46 @@ make_lispy_event (struct input_event *event)
return list2 (Qtouch_end, position);
}
case TOUCHSCREEN_BEGIN_EVENT:
case TOUCHSCREEN_END_EVENT:
{
Lisp_Object x, y, id, position;
struct frame *f = XFRAME (event->frame_or_window);
id = event->arg;
x = event->x;
y = event->y;
position = make_lispy_position (f, x, y, event->timestamp);
return list2 (((event->kind
== TOUCHSCREEN_BEGIN_EVENT)
? Qtouchscreen_begin
: Qtouchscreen_end),
Fcons (id, position));
}
case TOUCHSCREEN_UPDATE_EVENT:
{
Lisp_Object x, y, id, position, tem, it, evt;
struct frame *f = XFRAME (event->frame_or_window);
evt = Qnil;
for (tem = event->arg; CONSP (tem); tem = XCDR (tem))
{
it = XCAR (tem);
x = XCAR (it);
y = XCAR (XCDR (it));
id = XCAR (XCDR (XCDR (it)));
position = make_lispy_position (f, x, y, event->timestamp);
evt = Fcons (Fcons (id, position), evt);
}
return list2 (Qtouchscreen_update, evt);
}
#ifdef USE_TOOLKIT_SCROLL_BARS
/* We don't have down and up events if using toolkit scroll bars,
@ -12266,6 +12306,9 @@ See also `pre-command-hook'. */);
doc: /* Normal hook run when clearing the echo area. */);
#endif
DEFSYM (Qecho_area_clear_hook, "echo-area-clear-hook");
DEFSYM (Qtouchscreen_begin, "touchscreen-begin");
DEFSYM (Qtouchscreen_end, "touchscreen-end");
DEFSYM (Qtouchscreen_update, "touchscreen-update");
Fset (Qecho_area_clear_hook, Qnil);
DEFVAR_LISP ("lucid-menu-bar-dirty-flag", Vlucid_menu_bar_dirty_flag,

View file

@ -80,8 +80,7 @@ struct lisp_time
/* Clock count as a Lisp integer. */
Lisp_Object ticks;
/* Clock frequency (ticks per second) as a positive Lisp integer.
(TICKS . HZ) is a valid Lisp timestamp unless HZ < 65536. */
/* Clock frequency (ticks per second) as a positive Lisp integer. */
Lisp_Object hz;
};

View file

@ -280,6 +280,19 @@ enum event_kind
In the future, this may take into account other multi-touch
events generated from touchscreens and such. */
, TOUCH_END_EVENT
/* In a TOUCHSCREEN_UPDATE_EVENT, ARG is a list of elements of the
form (X Y ID), where X and Y are the coordinates of the
touchpoint relative to the top-left corner of the frame, and ID
is a unique number identifying the touchpoint.
In TOUCHSCREEN_BEGIN_EVENT and TOUCHSCREEN_END_EVENT, ARG is the
unique ID of the touchpoint, and X and Y are the frame-relative
positions of the touchpoint. */
, TOUCHSCREEN_UPDATE_EVENT
, TOUCHSCREEN_BEGIN_EVENT
, TOUCHSCREEN_END_EVENT
};
/* Bit width of an enum event_kind tag at the start of structs and unions. */

View file

@ -69,16 +69,6 @@ enum { TM_YEAR_BASE = 1900 };
# define FASTER_TIMEFNS 1
#endif
/* Whether to warn about Lisp timestamps (TICKS . HZ) that may be
instances of obsolete-format timestamps (HI . LO) where HI is
the high-order bits and LO the low-order 16 bits. Currently this
is true, but it should change to false in a future version of
Emacs. Compile with -DWARN_OBSOLETE_TIMESTAMPS=0 to see what the
future will be like. */
#ifndef WARN_OBSOLETE_TIMESTAMPS
enum { WARN_OBSOLETE_TIMESTAMPS = true };
#endif
/* Although current-time etc. generate list-format timestamps
(HI LO US PS), the plan is to change these functions to generate
frequency-based timestamps (TICKS . HZ) in a future release.
@ -817,14 +807,10 @@ decode_time_components (enum timeform form,
return decode_ticks_hz (make_integer_mpz (), hz, result, dresult);
}
enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 };
/* Decode a Lisp timestamp SPECIFIED_TIME that represents a time.
FLAGS specifies conversion flags. If FLAGS & DECODE_SECS_ONLY,
ignore and do not validate any sub-second components of an
old-format SPECIFIED_TIME. If FLAGS & WARN_OBSOLETE_TIMESTAMPS,
diagnose what could be obsolete (HIGH . LOW) timestamps.
If DECODE_SECS_ONLY, ignore and do not validate any sub-second
components of an old-format SPECIFIED_TIME.
If RESULT is not null, store into *RESULT the converted time;
otherwise, store into *DRESULT the number of seconds since the
@ -833,7 +819,7 @@ enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 };
Return the form of SPECIFIED-TIME. Signal an error if unsuccessful. */
static enum timeform
decode_lisp_time (Lisp_Object specified_time, int flags,
decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only,
struct lisp_time *result, double *dresult)
{
Lisp_Object high = make_fixnum (0);
@ -854,7 +840,7 @@ decode_lisp_time (Lisp_Object specified_time, int flags,
{
Lisp_Object low_tail = XCDR (low);
low = XCAR (low);
if (! (flags & DECODE_SECS_ONLY))
if (! decode_secs_only)
{
if (CONSP (low_tail))
{
@ -877,9 +863,6 @@ decode_lisp_time (Lisp_Object specified_time, int flags,
}
else
{
if (flags & WARN_OBSOLETE_TIMESTAMPS
&& RANGED_FIXNUMP (0, low, (1 << LO_TIME_BITS) - 1))
message ("obsolete timestamp with cdr %"pI"d", XFIXNUM (low));
form = TIMEFORM_TICKS_HZ;
}
@ -1008,8 +991,7 @@ static struct lisp_time
lisp_time_struct (Lisp_Object specified_time, enum timeform *pform)
{
struct lisp_time t;
enum timeform form
= decode_lisp_time (specified_time, WARN_OBSOLETE_TIMESTAMPS, &t, 0);
enum timeform form = decode_lisp_time (specified_time, false, &t, 0);
if (pform)
*pform = form;
return t;
@ -1034,9 +1016,8 @@ lisp_time_argument (Lisp_Object specified_time)
static time_t
lisp_seconds_argument (Lisp_Object specified_time)
{
int flags = WARN_OBSOLETE_TIMESTAMPS | DECODE_SECS_ONLY;
struct lisp_time lt;
decode_lisp_time (specified_time, flags, &lt, 0);
decode_lisp_time (specified_time, true, &lt, 0);
struct timespec t = lisp_to_timespec (lt);
if (! timespec_valid_p (t))
time_overflow ();
@ -1138,24 +1119,6 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
mpz_t *ihz = &mpz[0];
mpz_mul (*ihz, *fa, *db);
/* When warning about obsolete timestamps, if the smaller
denominator comes from a non-(TICKS . HZ) timestamp and could
generate a (TICKS . HZ) timestamp that would look obsolete,
arrange for the result to have a higher HZ to avoid a
spurious warning by a later consumer of this function's
returned value. */
verify (1 << LO_TIME_BITS <= ULONG_MAX);
if (WARN_OBSOLETE_TIMESTAMPS
&& (da_lt_db ? aform : bform) == TIMEFORM_FLOAT
&& (da_lt_db ? bform : aform) != TIMEFORM_TICKS_HZ
&& mpz_cmp_ui (*hzmin, 1) > 0
&& mpz_cmp_ui (*hzmin, 1 << LO_TIME_BITS) < 0)
{
mpz_t *hzmin1 = &mpz[2 - da_lt_db];
mpz_set_ui (*hzmin1, 1 << LO_TIME_BITS);
hzmin = hzmin1;
}
/* iticks = (fb * na) OP (fa * nb), where OP is + or -. */
mpz_t const *na = bignum_integer (iticks, ta.ticks);
mpz_mul (*iticks, *fb, *na);
@ -1177,8 +1140,7 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
upwards by multiplying the normalized numerator and denominator
so that the resulting denominator becomes at least hzmin.
This rescaling avoids returning a timestamp that is less precise
than both a and b, or a timestamp that looks obsolete when that
might be a problem. */
than both a and b. */
if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0)
{
/* Rescale straightforwardly. Although this might not
@ -1303,7 +1265,7 @@ or (if you need time as a string) `format-time-string'. */)
(Lisp_Object specified_time)
{
double t;
decode_lisp_time (specified_time, 0, 0, &t);
decode_lisp_time (specified_time, false, 0, &t);
return make_float (t);
}
@ -1651,12 +1613,11 @@ saving flag to be guessed.
As an obsolescent calling convention, if this function is called with
6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR,
DAY, MONTH, and YEAR, and specify the components of a decoded time,
where DST assumed to be -1 and FORM is omitted. If there are more
than 6 arguments the *last* argument is used as ZONE and any other
extra arguments are ignored, so that (apply #\\='encode-time
(decode-time ...)) works. In this obsolescent convention, DST and
ZONE default to -1 and nil respectively.
DAY, MONTH, and YEAR, and specify the components of a decoded time.
If there are more than 6 arguments the *last* argument is used as ZONE
and any other extra arguments are ignored, so that (apply
#\\='encode-time (decode-time ...)) works. In this obsolescent
convention, DST and ZONE default to -1 and nil respectively.
Years before 1970 are not guaranteed to work. On some systems,
year values as low as 1901 do work.
@ -1703,7 +1664,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
/* Let SEC = floor (LT.ticks / HZ), with SUBSECTICKS the remainder. */
struct lisp_time lt;
decode_lisp_time (secarg, 0, &lt, 0);
decode_lisp_time (secarg, false, &lt, 0);
Lisp_Object hz = lt.hz, sec, subsecticks;
if (FASTER_TIMEFNS && EQ (hz, make_fixnum (1)))
{
@ -1756,9 +1717,7 @@ Truncate the returned value toward minus infinity.
If FORM is nil (the default), return the same form as `current-time'.
If FORM is a positive integer, return a pair of integers (TICKS . FORM),
where TICKS is the number of clock ticks and FORM is the clock frequency
in ticks per second. (Currently the positive integer should be at least
65536 if the returned value is expected to be given to standard functions
expecting Lisp timestamps.) If FORM is t, return (TICKS . PHZ), where
in ticks per second. If FORM is t, return (TICKS . PHZ), where
PHZ is a suitable clock frequency in ticks per second. If FORM is
`integer', return an integer count of seconds. If FORM is `list',
return an integer list (HIGH LOW USEC PSEC), where HIGH has the most
@ -1767,7 +1726,7 @@ bits, and USEC and PSEC are the microsecond and picosecond counts. */)
(Lisp_Object time, Lisp_Object form)
{
struct lisp_time t;
enum timeform input_form = decode_lisp_time (time, 0, &t, 0);
enum timeform input_form = decode_lisp_time (time, false, &t, 0);
if (NILP (form))
form = CURRENT_TIME_LIST ? Qlist : Qt;
if (EQ (form, Qlist))

View file

@ -2916,7 +2916,7 @@ initial_set_up_x_back_buffer (struct frame *f)
unblock_input ();
}
#if defined HAVE_XINPUT2 && !defined USE_GTK
#if defined HAVE_XINPUT2
static void
setup_xi_event_mask (struct frame *f)
{
@ -2927,6 +2927,9 @@ setup_xi_event_mask (struct frame *f)
mask.mask = m = alloca (l);
memset (m, 0, l);
mask.mask_len = l;
block_input ();
#ifndef USE_GTK
mask.deviceid = XIAllMasterDevices;
XISetMask (m, XI_ButtonPress);
@ -2945,14 +2948,25 @@ setup_xi_event_mask (struct frame *f)
&mask, 1);
memset (m, 0, l);
#endif /* !USE_GTK */
mask.deviceid = XIAllDevices;
XISetMask (m, XI_PropertyEvent);
XISetMask (m, XI_HierarchyChanged);
XISetMask (m, XI_DeviceChanged);
#ifdef XI_TouchBegin
if (FRAME_DISPLAY_INFO (f)->xi2_version >= 2)
{
XISetMask (m, XI_TouchBegin);
XISetMask (m, XI_TouchUpdate);
XISetMask (m, XI_TouchEnd);
}
#endif
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
&mask, 1);
unblock_input ();
}
#endif
@ -3249,6 +3263,11 @@ x_window (struct frame *f)
unblock_input ();
}
#endif
#ifdef HAVE_XINPUT2
if (FRAME_DISPLAY_INFO (f)->supports_xi2)
setup_xi_event_mask (f);
#endif
}
#else /*! USE_GTK */

View file

@ -353,6 +353,8 @@ x_extension_initialize (struct x_display_info *dpyinfo)
static void
x_free_xi_devices (struct x_display_info *dpyinfo)
{
struct xi_touch_point_t *tem, *last;
block_input ();
if (dpyinfo->num_devices)
@ -362,6 +364,14 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
CurrentTime);
xfree (dpyinfo->devices[i].valuators);
tem = dpyinfo->devices[i].touchpoints;
while (tem)
{
last = tem;
tem = tem->next;
xfree (last);
}
}
xfree (dpyinfo->devices);
@ -407,7 +417,7 @@ x_init_master_valuators (struct x_display_info *dpyinfo)
block_input ();
x_free_xi_devices (dpyinfo);
infos = XIQueryDevice (dpyinfo->display,
XIAllMasterDevices,
XIAllDevices,
&ndevices);
if (!ndevices)
@ -432,6 +442,10 @@ x_init_master_valuators (struct x_display_info *dpyinfo)
xi_device->grab = 0;
xi_device->valuators =
xmalloc (sizeof *xi_device->valuators * device->num_classes);
xi_device->touchpoints = NULL;
xi_device->master_p = (device->use == XIMasterKeyboard
|| device->use == XIMasterPointer);
xi_device->direct_p = false;
for (int c = 0; c < device->num_classes; ++c)
{
@ -442,22 +456,36 @@ x_init_master_valuators (struct x_display_info *dpyinfo)
{
XIScrollClassInfo *info =
(XIScrollClassInfo *) device->classes[c];
struct xi_scroll_valuator_t *valuator =
&xi_device->valuators[actual_valuator_count++];
struct xi_scroll_valuator_t *valuator;
if (xi_device->master_p)
{
valuator = &xi_device->valuators[actual_valuator_count++];
valuator->horizontal
= (info->scroll_type == XIScrollTypeHorizontal);
valuator->invalid_p = true;
valuator->emacs_value = DBL_MIN;
valuator->increment = info->increment;
valuator->number = info->number;
}
valuator->horizontal
= (info->scroll_type == XIScrollTypeHorizontal);
valuator->invalid_p = true;
valuator->emacs_value = DBL_MIN;
valuator->increment = info->increment;
valuator->number = info->number;
break;
}
#endif
#ifdef XITouchClass /* XInput 2.2 */
case XITouchClass:
{
XITouchClassInfo *info;
info = (XITouchClassInfo *) device->classes[c];
xi_device->direct_p = info->mode == XIDirectTouch;
}
#endif
default:
break;
}
}
xi_device->scroll_valuator_count = actual_valuator_count;
}
}
@ -484,7 +512,7 @@ x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id,
{
struct xi_device_t *device = &dpyinfo->devices[i];
if (device->device_id == device_id)
if (device->device_id == device_id && device->master_p)
{
for (int j = 0; j < device->scroll_valuator_count; ++j)
{
@ -534,6 +562,61 @@ xi_device_from_id (struct x_display_info *dpyinfo, int deviceid)
return NULL;
}
#ifdef XI_TouchBegin
static void
xi_link_touch_point (struct xi_device_t *device,
int detail, double x, double y)
{
struct xi_touch_point_t *touchpoint;
touchpoint = xmalloc (sizeof *touchpoint);
touchpoint->next = device->touchpoints;
touchpoint->x = x;
touchpoint->y = y;
touchpoint->number = detail;
device->touchpoints = touchpoint;
}
static void
xi_unlink_touch_point (int detail,
struct xi_device_t *device)
{
struct xi_touch_point_t *last, *tem;
for (last = NULL, tem = device->touchpoints; tem;
last = tem, tem = tem->next)
{
if (tem->number == detail)
{
if (!last)
device->touchpoints = tem->next;
else
last->next = tem->next;
xfree (tem);
return;
}
}
}
static struct xi_touch_point_t *
xi_find_touch_point (struct xi_device_t *device, int detail)
{
struct xi_touch_point_t *point;
for (point = device->touchpoints; point; point = point->next)
{
if (point->number == detail)
return point;
}
return NULL;
}
#endif /* XI_TouchBegin */
static void
xi_grab_or_ungrab_device (struct xi_device_t *device,
struct x_display_info *dpyinfo,
@ -570,7 +653,7 @@ xi_reset_scroll_valuators_for_device_id (struct x_display_info *dpyinfo, int id)
struct xi_device_t *device = xi_device_from_id (dpyinfo, id);
struct xi_scroll_valuator_t *valuator;
if (!device)
if (!device || !device->master_p)
return;
if (!device->scroll_valuator_count)
@ -9981,242 +10064,250 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
goto XI_OTHER;
case XI_Motion:
states = &xev->valuators;
values = states->values;
{
struct xi_device_t *device;
x_display_set_last_user_time (dpyinfo, xi_event->time);
#ifdef HAVE_XWIDGETS
struct xwidget_view *xv = xwidget_view_from_window (xev->event);
double xv_total_x = 0.0;
double xv_total_y = 0.0;
#endif
for (int i = 0; i < states->mask_len * 8; i++)
{
if (XIMaskIsSet (states->mask, i))
{
struct xi_scroll_valuator_t *val;
double delta, scroll_unit;
int scroll_height;
Lisp_Object window;
/* See the comment on top of
x_init_master_valuators for more details on how
scroll wheel movement is reported on XInput 2. */
delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
i, *values, &val);
if (delta != DBL_MAX)
{
#ifdef HAVE_XWIDGETS
if (xv)
{
if (val->horizontal)
xv_total_x += delta;
else
xv_total_y += delta;
found_valuator = true;
if (delta == 0.0)
any_stop_p = true;
continue;
}
#endif
if (!f)
{
f = x_any_window_to_frame (dpyinfo, xev->event);
if (!f)
goto XI_OTHER;
}
found_valuator = true;
if (signbit (delta) != signbit (val->emacs_value))
val->emacs_value = 0;
val->emacs_value += delta;
if (mwheel_coalesce_scroll_events
&& (fabs (val->emacs_value) < 1)
&& (fabs (delta) > 0))
continue;
bool s = signbit (val->emacs_value);
inev.ie.kind = (fabs (delta) > 0
? (val->horizontal
? HORIZ_WHEEL_EVENT
: WHEEL_EVENT)
: TOUCH_END_EVENT);
inev.ie.timestamp = xev->time;
XSETINT (inev.ie.x, lrint (xev->event_x));
XSETINT (inev.ie.y, lrint (xev->event_y));
XSETFRAME (inev.ie.frame_or_window, f);
if (fabs (delta) > 0)
{
inev.ie.modifiers = !s ? up_modifier : down_modifier;
inev.ie.modifiers
|= x_x_to_emacs_modifiers (dpyinfo,
xev->mods.effective);
}
window = window_from_coordinates (f, xev->event_x,
xev->event_y, NULL,
false, false);
if (WINDOWP (window))
scroll_height = XWINDOW (window)->pixel_height;
else
/* EVENT_X and EVENT_Y can be outside the
frame if F holds the input grab, so fall
back to the height of the frame instead. */
scroll_height = FRAME_PIXEL_HEIGHT (f);
scroll_unit = pow (scroll_height, 2.0 / 3.0);
if (NUMBERP (Vx_scroll_event_delta_factor))
scroll_unit *= XFLOATINT (Vx_scroll_event_delta_factor);
if (fabs (delta) > 0)
{
if (val->horizontal)
{
inev.ie.arg
= list3 (Qnil,
make_float (val->emacs_value
* scroll_unit),
make_float (0));
}
else
{
inev.ie.arg = list3 (Qnil, make_float (0),
make_float (val->emacs_value
* scroll_unit));
}
}
else
{
inev.ie.arg = Qnil;
}
kbd_buffer_store_event_hold (&inev.ie, hold_quit);
val->emacs_value = 0;
}
values++;
}
inev.ie.kind = NO_EVENT;
}
#ifdef HAVE_XWIDGETS
if (xv)
{
if (found_valuator)
xwidget_scroll (xv, xev->event_x, xev->event_y,
xv_total_x, xv_total_y, xev->mods.effective,
xev->time, any_stop_p);
else
xwidget_motion_notify (xv, xev->event_x, xev->event_y,
xev->mods.effective, xev->time);
states = &xev->valuators;
values = states->values;
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device || !device->master_p)
goto XI_OTHER;
}
x_display_set_last_user_time (dpyinfo, xi_event->time);
#ifdef HAVE_XWIDGETS
struct xwidget_view *xv = xwidget_view_from_window (xev->event);
double xv_total_x = 0.0;
double xv_total_y = 0.0;
#endif
if (found_valuator)
goto XI_OTHER;
ev.x = lrint (xev->event_x);
ev.y = lrint (xev->event_y);
ev.window = xev->event;
ev.time = xev->time;
for (int i = 0; i < states->mask_len * 8; i++)
{
if (XIMaskIsSet (states->mask, i))
{
struct xi_scroll_valuator_t *val;
double delta, scroll_unit;
int scroll_height;
Lisp_Object window;
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
if (hlinfo->mouse_face_hidden)
{
hlinfo->mouse_face_hidden = false;
clear_mouse_face (hlinfo);
}
/* See the comment on top of
x_init_master_valuators for more details on how
scroll wheel movement is reported on XInput 2. */
delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
i, *values, &val);
f = mouse_or_wdesc_frame (dpyinfo, xev->event);
if (delta != DBL_MAX)
{
#ifdef HAVE_XWIDGETS
if (xv)
{
if (val->horizontal)
xv_total_x += delta;
else
xv_total_y += delta;
found_valuator = true;
if (delta == 0.0)
any_stop_p = true;
continue;
}
#endif
if (!f)
{
f = x_any_window_to_frame (dpyinfo, xev->event);
if (!f)
goto XI_OTHER;
}
found_valuator = true;
if (signbit (delta) != signbit (val->emacs_value))
val->emacs_value = 0;
val->emacs_value += delta;
if (mwheel_coalesce_scroll_events
&& (fabs (val->emacs_value) < 1)
&& (fabs (delta) > 0))
continue;
bool s = signbit (val->emacs_value);
inev.ie.kind = (fabs (delta) > 0
? (val->horizontal
? HORIZ_WHEEL_EVENT
: WHEEL_EVENT)
: TOUCH_END_EVENT);
inev.ie.timestamp = xev->time;
XSETINT (inev.ie.x, lrint (xev->event_x));
XSETINT (inev.ie.y, lrint (xev->event_y));
XSETFRAME (inev.ie.frame_or_window, f);
if (fabs (delta) > 0)
{
inev.ie.modifiers = !s ? up_modifier : down_modifier;
inev.ie.modifiers
|= x_x_to_emacs_modifiers (dpyinfo,
xev->mods.effective);
}
window = window_from_coordinates (f, xev->event_x,
xev->event_y, NULL,
false, false);
if (WINDOWP (window))
scroll_height = XWINDOW (window)->pixel_height;
else
/* EVENT_X and EVENT_Y can be outside the
frame if F holds the input grab, so fall
back to the height of the frame instead. */
scroll_height = FRAME_PIXEL_HEIGHT (f);
scroll_unit = pow (scroll_height, 2.0 / 3.0);
if (NUMBERP (Vx_scroll_event_delta_factor))
scroll_unit *= XFLOATINT (Vx_scroll_event_delta_factor);
if (fabs (delta) > 0)
{
if (val->horizontal)
{
inev.ie.arg
= list3 (Qnil,
make_float (val->emacs_value
* scroll_unit),
make_float (0));
}
else
{
inev.ie.arg = list3 (Qnil, make_float (0),
make_float (val->emacs_value
* scroll_unit));
}
}
else
{
inev.ie.arg = Qnil;
}
kbd_buffer_store_event_hold (&inev.ie, hold_quit);
val->emacs_value = 0;
}
values++;
}
inev.ie.kind = NO_EVENT;
}
#ifdef HAVE_XWIDGETS
if (xv)
{
if (found_valuator)
xwidget_scroll (xv, xev->event_x, xev->event_y,
xv_total_x, xv_total_y, xev->mods.effective,
xev->time, any_stop_p);
else
xwidget_motion_notify (xv, xev->event_x, xev->event_y,
xev->mods.effective, xev->time);
goto XI_OTHER;
}
#endif
if (found_valuator)
goto XI_OTHER;
ev.x = lrint (xev->event_x);
ev.y = lrint (xev->event_y);
ev.window = xev->event;
ev.time = xev->time;
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
if (hlinfo->mouse_face_hidden)
{
hlinfo->mouse_face_hidden = false;
clear_mouse_face (hlinfo);
}
f = mouse_or_wdesc_frame (dpyinfo, xev->event);
#ifdef USE_GTK
if (f && xg_event_is_for_scrollbar (f, event))
f = 0;
if (f && xg_event_is_for_scrollbar (f, event))
f = 0;
#endif
if (f)
{
/* Maybe generate a SELECT_WINDOW_EVENT for
`mouse-autoselect-window' but don't let popup menus
interfere with this (Bug#1261). */
if (!NILP (Vmouse_autoselect_window)
&& !popup_activated ()
/* Don't switch if we're currently in the minibuffer.
This tries to work around problems where the
minibuffer gets unselected unexpectedly, and where
you then have to move your mouse all the way down to
the minibuffer to select it. */
&& !MINI_WINDOW_P (XWINDOW (selected_window))
/* With `focus-follows-mouse' non-nil create an event
also when the target window is on another frame. */
&& (f == XFRAME (selected_frame)
|| !NILP (focus_follows_mouse)))
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates (f, ev.x, ev.y, 0, false, false);
if (f)
{
/* Maybe generate a SELECT_WINDOW_EVENT for
`mouse-autoselect-window' but don't let popup menus
interfere with this (Bug#1261). */
if (!NILP (Vmouse_autoselect_window)
&& !popup_activated ()
/* Don't switch if we're currently in the minibuffer.
This tries to work around problems where the
minibuffer gets unselected unexpectedly, and where
you then have to move your mouse all the way down to
the minibuffer to select it. */
&& !MINI_WINDOW_P (XWINDOW (selected_window))
/* With `focus-follows-mouse' non-nil create an event
also when the target window is on another frame. */
&& (f == XFRAME (selected_frame)
|| !NILP (focus_follows_mouse)))
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates (f, ev.x, ev.y, 0, false, false);
/* A window will be autoselected only when it is not
selected now and the last mouse movement event was
not in it. The remainder of the code is a bit vague
wrt what a "window" is. For immediate autoselection,
the window is usually the entire window but for GTK
where the scroll bars don't count. For delayed
autoselection the window is usually the window's text
area including the margins. */
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
&& !EQ (window, selected_window))
{
inev.ie.kind = SELECT_WINDOW_EVENT;
inev.ie.frame_or_window = window;
}
/* A window will be autoselected only when it is not
selected now and the last mouse movement event was
not in it. The remainder of the code is a bit vague
wrt what a "window" is. For immediate autoselection,
the window is usually the entire window but for GTK
where the scroll bars don't count. For delayed
autoselection the window is usually the window's text
area including the margins. */
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
&& !EQ (window, selected_window))
{
inev.ie.kind = SELECT_WINDOW_EVENT;
inev.ie.frame_or_window = window;
}
/* Remember the last window where we saw the mouse. */
last_mouse_window = window;
}
/* Remember the last window where we saw the mouse. */
last_mouse_window = window;
}
if (!x_note_mouse_movement (f, &ev))
help_echo_string = previous_help_echo_string;
}
else
{
if (!x_note_mouse_movement (f, &ev))
help_echo_string = previous_help_echo_string;
}
else
{
#ifndef USE_TOOLKIT_SCROLL_BARS
struct scroll_bar *bar
= x_window_to_scroll_bar (xi_event->display, xev->event, 2);
struct scroll_bar *bar
= x_window_to_scroll_bar (xi_event->display, xev->event, 2);
if (bar)
x_scroll_bar_note_movement (bar, &ev);
if (bar)
x_scroll_bar_note_movement (bar, &ev);
#endif /* USE_TOOLKIT_SCROLL_BARS */
/* If we move outside the frame, then we're
certainly no longer on any text in the frame. */
clear_mouse_face (hlinfo);
}
/* If we move outside the frame, then we're
certainly no longer on any text in the frame. */
clear_mouse_face (hlinfo);
}
/* If the contents of the global variable help_echo_string
has changed, generate a HELP_EVENT. */
if (!NILP (help_echo_string)
|| !NILP (previous_help_echo_string))
do_help = 1;
goto XI_OTHER;
/* If the contents of the global variable help_echo_string
has changed, generate a HELP_EVENT. */
if (!NILP (help_echo_string)
|| !NILP (previous_help_echo_string))
do_help = 1;
goto XI_OTHER;
}
case XI_ButtonRelease:
case XI_ButtonPress:
{
@ -10242,6 +10333,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device || !device->master_p)
goto XI_OTHER;
bv.button = xev->detail;
bv.type = xev->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
bv.x = lrint (xev->event_x);
@ -10408,6 +10502,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
int copy_bufsiz = sizeof (copy_buffer);
ptrdiff_t i;
int nchars, len;
struct xi_device_t *device;
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device || !device->master_p)
goto XI_OTHER;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Dispatch XI_KeyPress events when in menu. */
@ -10765,6 +10865,108 @@ handle_one_xevent (struct x_display_info *dpyinfo,
case XI_DeviceChanged:
x_init_master_valuators (dpyinfo);
goto XI_OTHER;
#ifdef XI_TouchBegin
case XI_TouchBegin:
{
struct xi_device_t *device;
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device)
goto XI_OTHER;
if (xi_find_touch_point (device, xev->detail))
emacs_abort ();
f = x_any_window_to_frame (dpyinfo, xev->event);
if (f && device->direct_p)
{
xi_link_touch_point (device, xev->detail, xev->event_x,
xev->event_y);
inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT;
inev.ie.timestamp = xev->time;
XSETFRAME (inev.ie.frame_or_window, f);
XSETINT (inev.ie.x, lrint (xev->event_x));
XSETINT (inev.ie.y, lrint (xev->event_y));
XSETINT (inev.ie.arg, xev->detail);
XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
xev->detail, xev->event, XIAcceptTouch);
}
else
XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
xev->detail, xev->event, XIRejectTouch);
goto XI_OTHER;
}
case XI_TouchUpdate:
{
struct xi_device_t *device;
struct xi_touch_point_t *touchpoint;
Lisp_Object arg = Qnil;
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device)
goto XI_OTHER;
touchpoint = xi_find_touch_point (device, xev->detail);
if (!touchpoint)
emacs_abort ();
touchpoint->x = xev->event_x;
touchpoint->y = xev->event_y;
f = x_any_window_to_frame (dpyinfo, xev->event);
if (f && device->direct_p)
{
inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT;
inev.ie.timestamp = xev->time;
XSETFRAME (inev.ie.frame_or_window, f);
for (touchpoint = device->touchpoints;
touchpoint; touchpoint = touchpoint->next)
{
arg = Fcons (list3i (lrint (touchpoint->x),
lrint (touchpoint->y),
lrint (touchpoint->number)),
arg);
}
inev.ie.arg = arg;
}
goto XI_OTHER;
}
case XI_TouchEnd:
{
struct xi_device_t *device;
device = xi_device_from_id (dpyinfo, xev->deviceid);
if (!device)
goto XI_OTHER;
xi_unlink_touch_point (xev->detail, device);
f = x_any_window_to_frame (dpyinfo, xev->event);
if (f && device->direct_p)
{
inev.ie.kind = TOUCHSCREEN_END_EVENT;
inev.ie.timestamp = xev->time;
XSETFRAME (inev.ie.frame_or_window, f);
XSETINT (inev.ie.x, lrint (xev->event_x));
XSETINT (inev.ie.y, lrint (xev->event_y));
XSETINT (inev.ie.arg, xev->detail);
}
goto XI_OTHER;
}
#endif
default:
goto XI_OTHER;
}

View file

@ -179,13 +179,24 @@ struct xi_scroll_valuator_t
int horizontal;
};
struct xi_touch_point_t
{
struct xi_touch_point_t *next;
int number;
double x, y;
};
struct xi_device_t
{
int device_id;
int scroll_valuator_count;
int grab;
bool master_p;
bool direct_p;
struct xi_scroll_valuator_t *valuators;
struct xi_touch_point_t *touchpoints;
};
#endif