From 3ea1b31f46f21ecfb089628e63187970fdb58d5a Mon Sep 17 00:00:00 2001 From: Daniel Koning Date: Wed, 21 Jan 2015 09:01:30 +0100 Subject: [PATCH] Prevent artist-mode from creating runaway timers (Bug#6130). * subr.el (posnp): Correct docstring of `posnp'. (posn-col-row): Make it work with all mouse position objects. * textmodes/artist.el (artist-mouse-draw-continously): Cancel timers if an error occurs during continuous drawing. (Bug#6130) * commands.texi (Drag Events, Motion Events, Event Examples) (Accessing Mouse): Describe actual range of values that mouse position objects can have. --- doc/lispref/ChangeLog | 6 +++ doc/lispref/commands.texi | 23 ++++++++-- lisp/ChangeLog | 7 +++ lisp/subr.el | 33 +++++++++----- lisp/textmodes/artist.el | 95 ++++++++++++++++++++------------------- 5 files changed, 102 insertions(+), 62 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 11a6f32718c..52c621c1fa5 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,9 @@ +2015-01-21 Daniel Koning (tiny change) + + * commands.texi (Drag Events, Motion Events, Event Examples) + (Accessing Mouse): Describe actual range of values that mouse + position objects can have. + 2015-01-20 Eli Zaretskii * display.texi (Manipulating Buttons): Explain more about the diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index a503e3f117b..5ea1a48b262 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -1485,8 +1485,10 @@ prefix @samp{drag-}. For example, dragging the mouse with button 2 held down generates a @code{drag-mouse-2} event. The second and third elements of the event give the starting and ending position of the drag, as mouse position lists (@pxref{Click Events}). You can access -the second element of any mouse event in the same way, with no need to -distinguish drag events from others. +the second element of any mouse event in the same way. However, the +drag event may end outside the boundaries of the frame that was +initially selected. In that case, the third element's position list +contains that frame in place of a window. The @samp{drag-} prefix follows the modifier key prefixes such as @samp{C-} and @samp{M-}. @@ -1631,7 +1633,10 @@ represented by lists that look like this: @noindent @var{position} is a mouse position list (@pxref{Click Events}), -specifying the current position of the mouse cursor. +specifying the current position of the mouse cursor. As with the +end-position of a drag event, this position list may represent a +location outside the boundaries of the initially selected frame, in +which case the list contains that frame in place of a window. The special form @code{track-mouse} enables generation of motion events within its body. Outside of @code{track-mouse} forms, Emacs @@ -1846,6 +1851,14 @@ into another window. That produces a pair of events like these: -453816)) @end smallexample +The frame with input focus might not take up the entire screen, and +the user might move the mouse outside the scope of the frame. Inside +the @code{track-mouse} special form, that produces an event like this: + +@smallexample +(mouse-movement (# nil (563 . 205) 532301936)) +@end smallexample + To handle a SIGUSR1 signal, define an interactive function, and bind it to the @code{signal usr1} event sequence: @@ -2010,7 +2023,9 @@ Events}); and @code{nil} otherwise. various parts of it: @defun posn-window position -Return the window that @var{position} is in. +Return the window that @var{position} is in. If @var{position} +represents a location outside the frame where the event was initiated, +return that frame instead. @end defun @defun posn-area position diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 20efe68bff6..280f6022007 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2015-01-21 Daniel Koning (tiny change) + + * subr.el (posnp): Correct docstring of `posnp'. + (posn-col-row): Make it work with all mouse position objects. + * textmodes/artist.el (artist-mouse-draw-continously): Cancel + timers if an error occurs during continuous drawing. (Bug#6130) + 2015-01-20 Eli Zaretskii * button.el (button-activate, push-button): Doc fix. (Bug#19628) diff --git a/lisp/subr.el b/lisp/subr.el index d71de87b42c..a48038fa12b 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1062,7 +1062,12 @@ The return value is a positive integer." ;;;; Extracting fields of the positions in an event. (defun posnp (obj) - "Return non-nil if OBJ appears to be a valid `posn' object." + "Return non-nil if OBJ appears to be a valid `posn' object specifying a window. +If OBJ is a valid `posn' object, but specifies a frame rather +than a window, return nil." + ;; FIXME: Correct the behavior of this function so that all valid + ;; `posn' objects are recognized, after updating other code that + ;; depends on its present behavior. (and (windowp (car-safe obj)) (atom (car-safe (setq obj (cdr obj)))) ;AREA-OR-POS. (integerp (car-safe (car-safe (setq obj (cdr obj))))) ;XOFFSET. @@ -1122,24 +1127,28 @@ For a scroll-bar event, the result column is 0, and the row corresponds to the vertical position of the click in the scroll bar. POSITION should be a list of the form returned by the `event-start' and `event-end' functions." - (let* ((pair (posn-x-y position)) - (window (posn-window position)) - (area (posn-area position))) + (let* ((pair (posn-x-y position)) + (frame-or-window (posn-window position)) + (frame (if (framep frame-or-window) + frame-or-window + (window-frame frame-or-window))) + (window (when (windowp frame-or-window) frame-or-window)) + (area (posn-area position))) (cond - ((null window) + ((null frame-or-window) '(0 . 0)) ((eq area 'vertical-scroll-bar) (cons 0 (scroll-bar-scale pair (1- (window-height window))))) ((eq area 'horizontal-scroll-bar) (cons (scroll-bar-scale pair (window-width window)) 0)) (t - (let* ((frame (if (framep window) window (window-frame window))) - ;; FIXME: This should take line-spacing properties on - ;; newlines into account. - (spacing (when (display-graphic-p frame) - (or (with-current-buffer (window-buffer window) - line-spacing) - (frame-parameter frame 'line-spacing))))) + ;; FIXME: This should take line-spacing properties on + ;; newlines into account. + (let* ((spacing (when (display-graphic-p frame) + (or (with-current-buffer + (window-buffer (frame-selected-window frame)) + line-spacing) + (frame-parameter frame 'line-spacing))))) (cond ((floatp spacing) (setq spacing (truncate (* spacing (frame-char-height frame))))) diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el index 8a2383c12ff..85d9410868a 100644 --- a/lisp/textmodes/artist.el +++ b/lisp/textmodes/artist.el @@ -4963,52 +4963,55 @@ The event, EV, is the mouse event." (artist-funcall init-fn x1 y1) (if (not artist-rubber-banding) (artist-no-rb-set-point1 x1 y1)) - (track-mouse - (while (or (mouse-movement-p ev) - (member 'down (event-modifiers ev))) - (setq ev-start-pos (artist-coord-win-to-buf - (posn-col-row (event-start ev)))) - (setq x1 (car ev-start-pos)) - (setq y1 (cdr ev-start-pos)) - - ;; Cancel previous timer - (if timer - (cancel-timer timer)) - - (if (not (eq initial-win (posn-window (event-start ev)))) - ;; If we moved outside the window, do nothing - nil - - ;; Still in same window: - ;; - ;; Check if user presses or releases shift key - (if (artist-shift-has-changed shift-state ev) - - ;; First check that the draw-how is the same as we - ;; already have. Otherwise, ignore the changed shift-state. - (if (not (eq draw-how - (artist-go-get-draw-how-from-symbol - (if (not shift-state) shifted unshifted)))) - (message "Cannot switch to shifted operation") - - ;; progn is "implicit" since this is the else-part - (setq shift-state (not shift-state)) - (setq op (if shift-state shifted unshifted)) - (setq draw-how (artist-go-get-draw-how-from-symbol op)) - (setq draw-fn (artist-go-get-draw-fn-from-symbol op)))) - - ;; Draw the new shape - (setq shape (artist-funcall draw-fn x1 y1)) - (artist-move-to-xy x1 y1) - - ;; Start the timer to call `draw-fn' repeatedly every - ;; `interval' second - (if (and interval draw-fn) - (setq timer (run-at-time interval interval draw-fn x1 y1)))) - - ;; Read next event - (setq ev (read-event)))) - + (unwind-protect + (track-mouse + (while (or (mouse-movement-p ev) + (member 'down (event-modifiers ev))) + (setq ev-start-pos (artist-coord-win-to-buf + (posn-col-row (event-start ev)))) + (setq x1 (car ev-start-pos)) + (setq y1 (cdr ev-start-pos)) + + ;; Cancel previous timer + (if timer + (cancel-timer timer)) + + (if (not (eq initial-win (posn-window (event-start ev)))) + ;; If we moved outside the window, do nothing + nil + + ;; Still in same window: + ;; + ;; Check if user presses or releases shift key + (if (artist-shift-has-changed shift-state ev) + + ;; First check that the draw-how is the same as we + ;; already have. Otherwise, ignore the changed shift-state. + (if (not (eq draw-how + (artist-go-get-draw-how-from-symbol + (if (not shift-state) shifted unshifted)))) + (message "Cannot switch to shifted operation") + + ;; progn is "implicit" since this is the else-part + (setq shift-state (not shift-state)) + (setq op (if shift-state shifted unshifted)) + (setq draw-how (artist-go-get-draw-how-from-symbol op)) + (setq draw-fn (artist-go-get-draw-fn-from-symbol op)))) + + ;; Draw the new shape + (setq shape (artist-funcall draw-fn x1 y1)) + (artist-move-to-xy x1 y1) + + ;; Start the timer to call `draw-fn' repeatedly every + ;; `interval' second + (if (and interval draw-fn) + (setq timer (run-at-time interval interval draw-fn x1 y1)))) + + ;; Read next event + (setq ev (read-event)))) + ;; Cleanup: get rid of any active timer. + (if timer + (cancel-timer timer))) ;; Cancel any timers (if timer (cancel-timer timer)) -- 2.39.2