2

I need to execute a function every time a window scrolls. I mean the function to be executed at point "after" the window has been scrolled (with C-v, M-v or with the <down> key). I tried:

(add-hook 'window-scroll-functions 'my-function)

but it didn't work (emacs froze until C-g). How can I achieve it?

Additional details. My goal is to sync the Emacs window that contains some LaTeX code with the PDF viewer (Okular). I know I can do it with AUCTeX but, for some reasons, I can't use it.

I imagined a solution like:

(defun my-sync-scroll-up ()
  (interactive)
  (scroll-up-command)
  (my-function))

(global-set-key (kbd "C-v") 'my-sync-scroll-up)

rebinding the C-v shortcut to my new function but I'd prefer something more generalized and automatic.

The function I want to run after window scrolls is:

(defun okular-forward-search-mod ()
  (interactive)
  (setq PID (number-to-string (emacs-pid)))
  (call-process-shell-command
   (concat "okular --unique file:"
       (concat (file-name-sans-extension (buffer-file-name)) ".pdf")
       "#src:"
       (number-to-string (line-number-at-pos (point)))
       (buffer-file-name))
   )
  (call-process-shell-command (concat "wmctrl -ia $(wmctrl -lp | awk -vpid=$PID '$3=="
                      PID
                      " {print $1; exit}')"))
)
(add-hook 'window-scroll-functions 'okular-forward-search-mod)

On Ubuntu 16.04, Emacs 25.3.2.

Gabriele Nicolardi
  • 1,199
  • 8
  • 17
  • 3
    If you provide additional details to explain the goal of `my-function`/`forward-search` and a minimal working example, then it may be easier for forum participants to suggest a better approach. Be aware that the `window-scroll-functions` hook may be called more than once per command loop, depending upon what is happening in the buffer and the user settings of where point should be when the command loop ends. E.g, a use may have customized `scroll-conservatively` to a number greater than 100; etc. Emacs scrolls and redisplay asks itself whether that is good enough; if not, Emacs scrolls ... – lawlist Nov 26 '18 at 22:13
  • @lawlist I added the additional details you requested. I hope it can help. – Gabriele Nicolardi Nov 27 '18 at 14:42
  • Does `my-function` attempt to scroll the window? The doc-string for the variable `window-scroll-functions` says: "*Warning: Do not use this feature to alter the way the window is scrolled. It is not designed for that, and such use probably won’t work.*" – lawlist Nov 27 '18 at 16:51
  • @lawlist no it does not attempt to scroll the window. – Gabriele Nicolardi Nov 27 '18 at 22:09
  • Given your goal, I suggest using a timer that fires up after 1 second and only does something if the window has scrolled, plus a hook on window visibility changes. This way you won't slow down repeated scrolling commands. – Gilles 'SO- stop being evil' Dec 05 '18 at 20:18
  • @Gilles, using a timer could be indeed a better solution but I have no idea how to do that. Can you give me some hints, please? – Gabriele Nicolardi Dec 06 '18 at 13:02

1 Answers1

0

Following the Gilles' suggestions I solved using an idle timer (see also Toggle timer function).

Here's the code I tested:

You need to run this command on the terminal:

okular --unique file.pdf ; emacs file.tex 

This is the elisp stuff:

(defun okular-forward-search-mod ()
  (interactive)
  (setq PID (number-to-string (emacs-pid)))
  (call-process-shell-command
   (concat "okular --unique file:"
       (concat (file-name-sans-extension (buffer-file-name)) ".pdf")
       "#src:"
       (number-to-string (line-number-at-pos (point)))
       (buffer-file-name))
   )
  (call-process-shell-command (concat "wmctrl -ia $(wmctrl -lp | awk -vpid=$PID '$3=="
                      PID
                      " {print $1; exit}')"))
  )

(defun sync-viewer-when-window-scrolls ()
   (interactive)
   (when (string= latex-contents-buffer-name (buffer-name))
     (unless (= latex-contents-window-start (window-start))
        (setq latex-contents-window-start (window-start))
    (okular-forward-search-mod)))
   )

(defvar forward-search-timer nil)

(defun toggle-sync-with-viewer () 
  (interactive)
  (unless (boundp 'latex-contents-window-start)
    (defvar latex-contents-window-start (window-start)))
  (unless (boundp 'latex-contents-buffer-name)
    (defvar latex-contents-buffer-name (buffer-name)))

  (if (not (timerp forward-search-timer))
      (progn
    (okular-forward-search-mod)    
    (setq forward-search-timer 
          (run-with-idle-timer 1 1 'sync-viewer-when-window-scrolls)))
    (cancel-timer forward-search-timer)
    (setq forward-search-timer nil)))
Gabriele Nicolardi
  • 1,199
  • 8
  • 17