unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Redisplay hook
@ 2016-07-02 19:24 Clément Pit--Claudel
  2016-07-03  3:27 ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-02 19:24 UTC (permalink / raw)
  To: Emacs developers


[-- Attachment #1.1: Type: text/plain, Size: 738 bytes --]

Hi Emacs,

Is there a standard way to run a function after each redisplay cycle? The best I could come up with is the following:

(defun my-redisplay-hook (&rest args)
  (message "Redisplayed; %S" args)
  (set-window-redisplay-end-trigger (selected-window) 1))

(setq redisplay-end-trigger-functions '(my-redisplay-hook))
(my-redisplay-hook)

It seems to work OK, but it relies on the obsolete set-window-redisplay-end-trigger, and the deprecated variable redisplay-end-trigger-functions:

  This variable is obsolete since 23.1;
  use ‘jit-lock-register’ instead.
  This variable may be risky if used as a file-local variable.

But I'm not sure how jit-lock-register-function can help here.

Thanks!
Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-02 19:24 Redisplay hook Clément Pit--Claudel
@ 2016-07-03  3:27 ` Eli Zaretskii
  2016-07-03  4:36   ` Clément Pit--Claudel
  2016-07-03 22:34   ` Richard Stallman
  0 siblings, 2 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-03  3:27 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: emacs-devel

> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Sat, 2 Jul 2016 15:24:36 -0400
> 
> Is there a standard way to run a function after each redisplay cycle?

No, not that I know of.

> The best I could come up with is the following:
> 
> (defun my-redisplay-hook (&rest args)
>   (message "Redisplayed; %S" args)
>   (set-window-redisplay-end-trigger (selected-window) 1))
> 
> (setq redisplay-end-trigger-functions '(my-redisplay-hook))
> (my-redisplay-hook)
> 
> It seems to work OK, but it relies on the obsolete set-window-redisplay-end-trigger, and the deprecated variable redisplay-end-trigger-functions:
> 
>   This variable is obsolete since 23.1;
>   use ‘jit-lock-register’ instead.
>   This variable may be risky if used as a file-local variable.
> 
> But I'm not sure how jit-lock-register-function can help here.

You don't say what do you want to accomplish with that hook, so it's
hard to give you advice.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03  3:27 ` Eli Zaretskii
@ 2016-07-03  4:36   ` Clément Pit--Claudel
  2016-07-03  7:45     ` Eli Zaretskii
  2016-07-03 22:34   ` Richard Stallman
  1 sibling, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-03  4:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 916 bytes --]

On 2016-07-02 23:27, Eli Zaretskii wrote:
> You don't say what do you want to accomplish with that hook, so it's
> hard to give you advice.

It's true :) I'd like to make screencasts (gifs) by saving a picture of an Emacs window or frame after each redisplay (I tried a number of programs that record screencasts, but they all gave disappointing results; by saving a picture (and a timestamp) after each redisplay, I might get much better results).

A post-command hook would almost work, but it doesn't work for, say, a compilation buffer showing new output.

Would it be hard to add a redisplay hook? Alternatively, is there a non-deprecated way to achieve what the snippet that I posted does?

Also, is there a way to save a bitmap copy of a frame, other than asking the system to take a screenshot? Could emacs do a redisplay cycle but write to a bitmap instead of the screen?

Cheers,
Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03  4:36   ` Clément Pit--Claudel
@ 2016-07-03  7:45     ` Eli Zaretskii
  2016-07-03 14:23       ` Clément Pit--Claudel
  2016-07-04  0:05       ` Clément Pit--Claudel
  0 siblings, 2 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-03  7:45 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: emacs-devel

> Cc: emacs-devel@gnu.org
> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Sun, 3 Jul 2016 00:36:07 -0400
> 
> It's true :) I'd like to make screencasts (gifs) by saving a picture of an Emacs window or frame after each redisplay (I tried a number of programs that record screencasts, but they all gave disappointing results; by saving a picture (and a timestamp) after each redisplay, I might get much better results).

I think such an application needs to hook into the GUI system, not
into Emacs.  That's because, at least on X, AFAIK Emacs doesn't
necessarily flush the queue of X commands each time it finishes
redisplay, so you may be disappointed by the results anyway.

As a temporary measure, try calling your code from the function
update_end (you will have to modify the C sources for that).



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03  7:45     ` Eli Zaretskii
@ 2016-07-03 14:23       ` Clément Pit--Claudel
  2016-07-03 14:51         ` Clément Pit--Claudel
  2016-07-03 15:37         ` Eli Zaretskii
  2016-07-04  0:05       ` Clément Pit--Claudel
  1 sibling, 2 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-03 14:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 3894 bytes --]

On 2016-07-03 03:45, Eli Zaretskii wrote:
> As a temporary measure, try calling your code from the function
> update_end (you will have to modify the C sources for that).

Thanks! Is there a trick to prevent code running in that section to cause a new redisplay cycle?
Calling #'format from there causes a segfault:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000577874 in print_object (obj=<optimized out>, printcharfun=printcharfun@entry=0, 
    escapeflag=escapeflag@entry=true) at print.c:1519
1519		if (p != end && (*p == '-' || *p == '+')) p++;
(gdb) bt
#0  0x0000000000577874 in print_object (obj=<optimized out>, printcharfun=printcharfun@entry=0, 
    escapeflag=escapeflag@entry=true) at print.c:1519
#1  0x0000000000577a82 in print_object (obj=<optimized out>, obj@entry=60247395, printcharfun=printcharfun@entry=0, 
    escapeflag=<optimized out>) at print.c:1662
#2  0x0000000000578e06 in print (obj=obj@entry=60247395, printcharfun=printcharfun@entry=0, 
    escapeflag=<optimized out>) at print.c:1143
#3  0x0000000000579749 in Fprin1_to_string (object=60247395, noescape=0) at print.c:672
#4  0x0000000000555725 in styled_format (nargs=2, args=0x7fffffffc0c0, message=<optimized out>) at editfns.c:4088
#5  0x000000000055d1a5 in eval_sub (form=<optimized out>) at eval.c:2145
#6  0x000000000055d33d in Fprogn (body=44976) at eval.c:427
#7  0x000000000055d6b5 in funcall_lambda (fun=53999395, nargs=nargs@entry=1, 
    arg_vector=arg_vector@entry=0x7fffffffc318) at eval.c:2922
#8  0x000000000055d8e3 in Ffuncall (nargs=2, args=0x7fffffffc310) at eval.c:2762
#9  0x000000000055db39 in funcall_nil (nargs=<optimized out>, args=<optimized out>) at eval.c:2340
#10 0x000000000055bd6c in run_hook_with_args (nargs=2, args=0x7fffffffc310, funcall=0x55db30 <funcall_nil>)
    at eval.c:2517
#11 0x000000000055bf6a in run_hook_with_args (funcall=<optimized out>, args=<optimized out>, nargs=<optimized out>)
    at eval.c:2383
#12 Frun_hook_with_args (nargs=<optimized out>, args=<optimized out>) at eval.c:2382
#13 0x00000000004bd421 in x_update_end (f=<optimized out>) at xterm.c:1234
#14 0x0000000000421c9a in update_frame (f=f@entry=0x12bed60, force_p=<optimized out>, force_p@entry=false, 
    inhibit_hairy_id_p=inhibit_hairy_id_p@entry=false) at dispnew.c:3109
#15 0x0000000000453b64 in redisplay_internal () at xdisp.c:14058
#16 0x00000000004557e5 in redisplay () at xdisp.c:13252
#17 0x00000000004f5e3b in read_char (commandflag=commandflag@entry=1, map=map@entry=60215251, prev_event=0, 
    used_mouse_menu=used_mouse_menu@entry=0x7fffffffdc9b, end_time=end_time@entry=0x0) at keyboard.c:2477
#18 0x00000000004f86d3 in read_key_sequence (keybuf=keybuf@entry=0x7fffffffdd70, prompt=prompt@entry=0, 
    dont_downcase_last=dont_downcase_last@entry=false, can_return_switch_frame=can_return_switch_frame@entry=true, 
    fix_current_buffer=fix_current_buffer@entry=true, prevent_redisplay=prevent_redisplay@entry=false, bufsize=30)
    at keyboard.c:9084
#19 0x00000000004fa1d6 in command_loop_1 () at keyboard.c:1365
#20 0x000000000055c2dd in internal_condition_case (bfun=bfun@entry=0x4f9fe0 <command_loop_1>, 
    handlers=handlers@entry=19488, hfun=hfun@entry=0x4f0f90 <cmd_error>) at eval.c:1310
#21 0x00000000004ec6ac in command_loop_2 (ignore=ignore@entry=0) at keyboard.c:1107
#22 0x000000000055c28b in internal_catch (tag=tag@entry=46368, func=func@entry=0x4ec690 <command_loop_2>, 
    arg=arg@entry=0) at eval.c:1075
#23 0x00000000004ec667 in command_loop () at keyboard.c:1086
#24 0x00000000004f0bc4 in recursive_edit_1 () at keyboard.c:692
#25 0x00000000004f0ee5 in Frecursive_edit () at keyboard.c:763
#26 0x00000000004198c8 in main (argc=1, argv=0x7fffffffe0e8) at emacs.c:1656

Lisp Backtrace:
"format" (0xffffc0c0)
"~/redisplay" (0xffffc318)
"redisplay_internal (C function)" (0x0) 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03 14:23       ` Clément Pit--Claudel
@ 2016-07-03 14:51         ` Clément Pit--Claudel
  2016-07-03 15:37         ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-03 14:51 UTC (permalink / raw)
  To: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 4128 bytes --]

Looks like wrapping the hook in block_input fixes this error :)

On 2016-07-03 10:23, Clément Pit--Claudel wrote:
> On 2016-07-03 03:45, Eli Zaretskii wrote:
>> As a temporary measure, try calling your code from the function
>> update_end (you will have to modify the C sources for that).
> 
> Thanks! Is there a trick to prevent code running in that section to cause a new redisplay cycle?
> Calling #'format from there causes a segfault:
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000000000577874 in print_object (obj=<optimized out>, printcharfun=printcharfun@entry=0, 
>     escapeflag=escapeflag@entry=true) at print.c:1519
> 1519		if (p != end && (*p == '-' || *p == '+')) p++;
> (gdb) bt
> #0  0x0000000000577874 in print_object (obj=<optimized out>, printcharfun=printcharfun@entry=0, 
>     escapeflag=escapeflag@entry=true) at print.c:1519
> #1  0x0000000000577a82 in print_object (obj=<optimized out>, obj@entry=60247395, printcharfun=printcharfun@entry=0, 
>     escapeflag=<optimized out>) at print.c:1662
> #2  0x0000000000578e06 in print (obj=obj@entry=60247395, printcharfun=printcharfun@entry=0, 
>     escapeflag=<optimized out>) at print.c:1143
> #3  0x0000000000579749 in Fprin1_to_string (object=60247395, noescape=0) at print.c:672
> #4  0x0000000000555725 in styled_format (nargs=2, args=0x7fffffffc0c0, message=<optimized out>) at editfns.c:4088
> #5  0x000000000055d1a5 in eval_sub (form=<optimized out>) at eval.c:2145
> #6  0x000000000055d33d in Fprogn (body=44976) at eval.c:427
> #7  0x000000000055d6b5 in funcall_lambda (fun=53999395, nargs=nargs@entry=1, 
>     arg_vector=arg_vector@entry=0x7fffffffc318) at eval.c:2922
> #8  0x000000000055d8e3 in Ffuncall (nargs=2, args=0x7fffffffc310) at eval.c:2762
> #9  0x000000000055db39 in funcall_nil (nargs=<optimized out>, args=<optimized out>) at eval.c:2340
> #10 0x000000000055bd6c in run_hook_with_args (nargs=2, args=0x7fffffffc310, funcall=0x55db30 <funcall_nil>)
>     at eval.c:2517
> #11 0x000000000055bf6a in run_hook_with_args (funcall=<optimized out>, args=<optimized out>, nargs=<optimized out>)
>     at eval.c:2383
> #12 Frun_hook_with_args (nargs=<optimized out>, args=<optimized out>) at eval.c:2382
> #13 0x00000000004bd421 in x_update_end (f=<optimized out>) at xterm.c:1234
> #14 0x0000000000421c9a in update_frame (f=f@entry=0x12bed60, force_p=<optimized out>, force_p@entry=false, 
>     inhibit_hairy_id_p=inhibit_hairy_id_p@entry=false) at dispnew.c:3109
> #15 0x0000000000453b64 in redisplay_internal () at xdisp.c:14058
> #16 0x00000000004557e5 in redisplay () at xdisp.c:13252
> #17 0x00000000004f5e3b in read_char (commandflag=commandflag@entry=1, map=map@entry=60215251, prev_event=0, 
>     used_mouse_menu=used_mouse_menu@entry=0x7fffffffdc9b, end_time=end_time@entry=0x0) at keyboard.c:2477
> #18 0x00000000004f86d3 in read_key_sequence (keybuf=keybuf@entry=0x7fffffffdd70, prompt=prompt@entry=0, 
>     dont_downcase_last=dont_downcase_last@entry=false, can_return_switch_frame=can_return_switch_frame@entry=true, 
>     fix_current_buffer=fix_current_buffer@entry=true, prevent_redisplay=prevent_redisplay@entry=false, bufsize=30)
>     at keyboard.c:9084
> #19 0x00000000004fa1d6 in command_loop_1 () at keyboard.c:1365
> #20 0x000000000055c2dd in internal_condition_case (bfun=bfun@entry=0x4f9fe0 <command_loop_1>, 
>     handlers=handlers@entry=19488, hfun=hfun@entry=0x4f0f90 <cmd_error>) at eval.c:1310
> #21 0x00000000004ec6ac in command_loop_2 (ignore=ignore@entry=0) at keyboard.c:1107
> #22 0x000000000055c28b in internal_catch (tag=tag@entry=46368, func=func@entry=0x4ec690 <command_loop_2>, 
>     arg=arg@entry=0) at eval.c:1075
> #23 0x00000000004ec667 in command_loop () at keyboard.c:1086
> #24 0x00000000004f0bc4 in recursive_edit_1 () at keyboard.c:692
> #25 0x00000000004f0ee5 in Frecursive_edit () at keyboard.c:763
> #26 0x00000000004198c8 in main (argc=1, argv=0x7fffffffe0e8) at emacs.c:1656
> 
> Lisp Backtrace:
> "format" (0xffffc0c0)
> "~/redisplay" (0xffffc318)
> "redisplay_internal (C function)" (0x0) 
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03 14:23       ` Clément Pit--Claudel
  2016-07-03 14:51         ` Clément Pit--Claudel
@ 2016-07-03 15:37         ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-03 15:37 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: emacs-devel

> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Sun, 3 Jul 2016 10:23:00 -0400
> Cc: emacs-devel@gnu.org
> 
> Is there a trick to prevent code running in that section to cause a new redisplay cycle?

Bind inhibit-redisplay to non-nil around the call.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03  3:27 ` Eli Zaretskii
  2016-07-03  4:36   ` Clément Pit--Claudel
@ 2016-07-03 22:34   ` Richard Stallman
  2016-07-04  0:09     ` Clément Pit--Claudel
  2016-07-04  0:22     ` Mark Oteiza
  1 sibling, 2 replies; 33+ messages in thread
From: Richard Stallman @ 2016-07-03 22:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: clement.pit, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > Is there a standard way to run a function after each redisplay cycle?

  > No, not that I know of.

It is asking for trouble, since if there is any bug in it or confusing
behavior, you will get totally screwed.

-- 
Dr Richard Stallman
President, Free Software Foundation (gnu.org, fsf.org)
Internet Hall-of-Famer (internethalloffame.org)
Skype: No way! See stallman.org/skype.html.




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03  7:45     ` Eli Zaretskii
  2016-07-03 14:23       ` Clément Pit--Claudel
@ 2016-07-04  0:05       ` Clément Pit--Claudel
  2016-07-04  2:41         ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04  0:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 1466 bytes --]

On 2016-07-03 03:45, Eli Zaretskii wrote:
>> Cc: emacs-devel@gnu.org
>> From: Clément Pit--Claudel <clement.pit@gmail.com>
>> Date: Sun, 3 Jul 2016 00:36:07 -0400
>>
>> It's true :) I'd like to make screencasts (gifs) by saving a picture of an Emacs window or frame after each redisplay (I tried a number of programs that record screencasts, but they all gave disappointing results; by saving a picture (and a timestamp) after each redisplay, I might get much better results).
> 
> As a temporary measure, try calling your code from the function
> update_end (you will have to modify the C sources for that).

Thanks for the pointer. I applied the attached patch, and it works very nicely. Could we refine it into a proper feature and apply it to master? Or are there reasons against a post-display hook?

> I think such an application needs to hook into the GUI system, not
> into Emacs.  That's because, at least on X, AFAIK Emacs doesn't
> necessarily flush the queue of X commands each time it finishes
> redisplay, so you may be disappointed by the results anyway.

It actually works very nicely :) Out of luck, maybe? In any case, I've uploaded a screencast generated by saving a screenshot at the end of each redisplay cycle to http://web.mit.edu/cpitcla/www/emacs-screencast.gif . Let me know what you think! It behaves nicely wrt, for example, the pulsing of xref-find-definition or the animations of M-x butterfly.

Cheers,
Clément.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.1.2: 0001-Add-a-post_display_hook.patch --]
[-- Type: text/x-diff; name="0001-Add-a-post_display_hook.patch", Size: 1234 bytes --]

From c9cfc3e17b5bddb3a19951344da8d1c947d56643 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Pit--Claudel?= <clement.pitclaudel@live.com>
Date: Sun, 3 Jul 2016 19:58:35 -0400
Subject: [PATCH] Add a post_display_hook

---
 src/xterm.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/xterm.c b/src/xterm.c
index 9fb19a1..f8e3ef0 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1230,8 +1230,11 @@ x_update_end (struct frame *f)
   XFlush (FRAME_X_DISPLAY (f));
   unblock_input ();
 #endif
-}
 
+  block_input ();
+  run_hook(Qpost_redisplay_hook);
+  unblock_input ();
+}
 
 /* This function is called from various places in xdisp.c
    whenever a complete update has been performed.  */
@@ -12739,6 +12742,12 @@ With MS Windows or Nextstep, the value is t.  */);
 #endif
 
   DEFSYM (Qmodifier_value, "modifier-value");
+  DEFSYM (Qpost_redisplay_hook, "post-redisplay-hook");
+
+  DEFVAR_LISP ("post-redisplay-hook", Vpost_redisplay_hook,
+    doc: /* Hook run at end of redisplay.  */);
+  Vpost_redisplay_hook = Qnil;
+
   DEFSYM (Qalt, "alt");
   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
   DEFSYM (Qhyper, "hyper");
-- 
2.9.0


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03 22:34   ` Richard Stallman
@ 2016-07-04  0:09     ` Clément Pit--Claudel
  2016-07-04  2:42       ` Eli Zaretskii
  2016-07-04  0:22     ` Mark Oteiza
  1 sibling, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04  0:09 UTC (permalink / raw)
  To: rms, Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 603 bytes --]

On 2016-07-03 18:34, Richard Stallman wrote:
> > > Is there a standard way to run a function after each redisplay cycle?
> 
> > No, not that I know of.
> 
> It is asking for trouble, since if there is any bug in it or confusing
> behavior, you will get totally screwed.

Much more than with a pre- or post-command-hook? We could have the same logic for errors:

    If an unhandled error happens in running this hook,
    the function in which the error occurred is unconditionally removed, since
    otherwise the error might happen repeatedly and make Emacs nonfunctional.

Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-03 22:34   ` Richard Stallman
  2016-07-04  0:09     ` Clément Pit--Claudel
@ 2016-07-04  0:22     ` Mark Oteiza
  2016-07-04  2:42       ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Mark Oteiza @ 2016-07-04  0:22 UTC (permalink / raw)
  To: emacs-devel; +Cc: Richard Stallman


Richard Stallman <rms@gnu.org> writes:
> > > Is there a standard way to run a function after each redisplay cycle?
> > No, not that I know of.
>
> It is asking for trouble, since if there is any bug in it or confusing
> behavior, you will get totally screwed.

Well, pre-redisplay-functions already exists, and it appears to be a hook
with equal potential for making trouble.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  0:05       ` Clément Pit--Claudel
@ 2016-07-04  2:41         ` Eli Zaretskii
  2016-07-04  4:31           ` Clément Pit--Claudel
  2016-07-04  7:55           ` Stefan Monnier
  0 siblings, 2 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04  2:41 UTC (permalink / raw)
  To: Clément Pit--Claudel, Stefan Monnier; +Cc: emacs-devel

> Cc: emacs-devel@gnu.org
> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Sun, 3 Jul 2016 20:05:17 -0400
> 
> > As a temporary measure, try calling your code from the function
> > update_end (you will have to modify the C sources for that).
> 
> Thanks for the pointer. I applied the attached patch, and it works very nicely. Could we refine it into a proper feature and apply it to master? Or are there reasons against a post-display hook?

Blocking input is not enough (and is just a workaround for problems
you had, anyway).  But before we discuss this seriously, I have a
feeling that such a hook was already discussed in the past, and we
found it unnecessary and/or dangerous.  Stefan, do you remember
something like that?

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  0:09     ` Clément Pit--Claudel
@ 2016-07-04  2:42       ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04  2:42 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: rms, emacs-devel

> Cc: emacs-devel@gnu.org
> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Sun, 3 Jul 2016 20:09:59 -0400
> 
> > It is asking for trouble, since if there is any bug in it or confusing
> > behavior, you will get totally screwed.
> 
> Much more than with a pre- or post-command-hook?

Yes, because those ones run outside of redisplay.

> We could have the same logic for errors:
> 
>     If an unhandled error happens in running this hook,
>     the function in which the error occurred is unconditionally removed, since
>     otherwise the error might happen repeatedly and make Emacs nonfunctional.

If we go this way, that's probably a good thing to do.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  0:22     ` Mark Oteiza
@ 2016-07-04  2:42       ` Eli Zaretskii
  2016-07-04  7:59         ` Andreas Schwab
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04  2:42 UTC (permalink / raw)
  To: Mark Oteiza; +Cc: rms, emacs-devel

> From: Mark Oteiza <mvoteiza@udel.edu>
> Date: Sun, 03 Jul 2016 20:22:06 -0400
> Cc: Richard Stallman <rms@gnu.org>
> 
> 
> Richard Stallman <rms@gnu.org> writes:
> > > > Is there a standard way to run a function after each redisplay cycle?
> > > No, not that I know of.
> >
> > It is asking for trouble, since if there is any bug in it or confusing
> > behavior, you will get totally screwed.
> 
> Well, pre-redisplay-functions already exists, and it appears to be a hook
> with equal potential for making trouble.

No, because it runs _before_ redisplay.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  2:41         ` Eli Zaretskii
@ 2016-07-04  4:31           ` Clément Pit--Claudel
  2016-07-04 14:47             ` Eli Zaretskii
  2016-07-04  7:55           ` Stefan Monnier
  1 sibling, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04  4:31 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1653 bytes --]

On 2016-07-03 22:41, Eli Zaretskii wrote:
> Blocking input is not enough (and is just a workaround for problems 
> you had, anyway).

Ok; thanks for clarifying!

> But before we discuss this seriously, I have a feeling that such a
> hook was already discussed in the past, and we found it unnecessary
> and/or dangerous.  Stefan, do you remember something like that?

Thanks.  My search-engine-fu was insufficient to dig up that discussion.  It could be around the time of the commit below, but none of Stefan's posts at the time mention that

    commit 379ec02c03febd0955b2c235c9e596db82fef8a0
    Author: Stefan Monnier <monnier@iro.umontreal.ca>
    Date:   Tue Mar 25 17:32:20 2008 +0000

        (redisplay-end-trigger-functions, window-redisplay-end-trigger)
        (set-window-redisplay-end-trigger, process-filter-multibyte-p)
        (set-process-filter-multibyte): Mark as obsolete.

Further digging points to:

- https://lists.gnu.org/archive/html/emacs-devel/2009-02/msg00785.html, in which Stefan mentioned a post-redisplay-hook in passing

- https://lists.gnu.org/archive/html/emacs-devel/2010-01/msg01313.html, which Alan started, and in which you mentioned (https://lists.gnu.org/archive/html/emacs-devel/2010-01/msg01428.html) such a hook.

- https://lists.gnu.org/archive/html/bug-gnu-emacs/2011-12/msg00785.html, where Stefan asked for a pre-redisplay-hook, and Richard expressed concerns about debugging display-related hooks.

- https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-01/msg01011.html, where you mentioned maybe needing a post-redisplay-hook.

That's all I could find :)
Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  2:41         ` Eli Zaretskii
  2016-07-04  4:31           ` Clément Pit--Claudel
@ 2016-07-04  7:55           ` Stefan Monnier
  2016-07-04 14:52             ` Eli Zaretskii
  2016-07-04 16:07             ` Clément Pit--Claudel
  1 sibling, 2 replies; 33+ messages in thread
From: Stefan Monnier @ 2016-07-04  7:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Clément Pit--Claudel, emacs-devel

> Blocking input is not enough (and is just a workaround for problems
> you had, anyway).  But before we discuss this seriously, I have a
> feeling that such a hook was already discussed in the past, and we
> found it unnecessary and/or dangerous.  Stefan, do you remember
> something like that?

I don't have a clear recollection either, sorry.

I guess part of the question is what would be the use of such a hook.
The difference between a pre-redisplay-hook and a
post-redisplay-hook is not very large since most of the result of
redisplay is "invisible" to Elisp.  The main differences I can think of
would be:
- jit-lock stuff, in case you want to see the buffer after jit-locking.
  but it seems you can just as well hook into jit-lock to get
  that result.
- scrolling, in case you want to react to changes in the user-visible
  window-start/end.

Of course the use could be fairly tricky, with risks of the
post-redisplay-hook causing further redisplay-cycle ad-nauseam, but we
already have this problem with the window-scroll-functions, IIRC.


        Stefan



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  2:42       ` Eli Zaretskii
@ 2016-07-04  7:59         ` Andreas Schwab
  2016-07-04 14:52           ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Andreas Schwab @ 2016-07-04  7:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Mark Oteiza, rms, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Mark Oteiza <mvoteiza@udel.edu>
>> Date: Sun, 03 Jul 2016 20:22:06 -0400
>> Cc: Richard Stallman <rms@gnu.org>
>> 
>> 
>> Richard Stallman <rms@gnu.org> writes:
>> > > > Is there a standard way to run a function after each redisplay cycle?
>> > > No, not that I know of.
>> >
>> > It is asking for trouble, since if there is any bug in it or confusing
>> > behavior, you will get totally screwed.
>> 
>> Well, pre-redisplay-functions already exists, and it appears to be a hook
>> with equal potential for making trouble.
>
> No, because it runs _before_ redisplay.

But a post-redisplay hook should not be any more dangerous than a
post-command hook.  Like the latter it could just be disabled
automatically if anything went wrong.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  4:31           ` Clément Pit--Claudel
@ 2016-07-04 14:47             ` Eli Zaretskii
  2016-07-04 16:14               ` Clément Pit--Claudel
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04 14:47 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: monnier, emacs-devel

> Cc: emacs-devel@gnu.org
> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Mon, 4 Jul 2016 00:31:15 -0400
> 
> > But before we discuss this seriously, I have a feeling that such a
> > hook was already discussed in the past, and we found it unnecessary
> > and/or dangerous.  Stefan, do you remember something like that?
> 
> Thanks.  My search-engine-fu was insufficient to dig up that discussion.  It 
> could be around the time of the commit below, but none of Stefan's posts at the 
> time mention that
> 
>     commit 379ec02c03febd0955b2c235c9e596db82fef8a0
>     Author: Stefan Monnier <address@hidden>
>     Date:   Tue Mar 25 17:32:20 2008 +0000
> 
>         (redisplay-end-trigger-functions, window-redisplay-end-trigger)
>         (set-window-redisplay-end-trigger, process-filter-multibyte-p)
>         (set-process-filter-multibyte): Mark as obsolete.

redisplay-end-trigger functions are not exactly what you need in this
context anyway: these functions are only called when the display
engine finishes to examine the specified buffer position.  So their
assumed use case is different from yours, and I'm quite sure they are
not easy to use in practice if the buffer position where they should
be invoked is indeed important (because knowing in advance when that
position will be traversed by the display engine requires an
unrealistically good knowledge of how the display engine works, and is
non-trivial even then).

> Further digging points to:
> 
> - https://lists.gnu.org/archive/html/emacs-devel/2009-02/msg00785.html, in 
> which Stefan mentioned a post-redisplay-hook in passing
> 
> - https://lists.gnu.org/archive/html/emacs-devel/2010-01/msg01313.html, which 
> Alan started, and in which you mentioned 
> (https://lists.gnu.org/archive/html/emacs-devel/2010-01/msg01428.html) such a 
> hook.
> 
> - https://lists.gnu.org/archive/html/bug-gnu-emacs/2011-12/msg00785.html, where 
> Stefan asked for a pre-redisplay-hook, and Richard expressed concerns about 
> debugging display-related hooks.
> 
> - https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-01/msg01011.html, where 
> you mentioned maybe needing a post-redisplay-hook.

Thanks.  Let me explain why this issue is not so simple.

The main problem is that "end of redisplay" is not well defined, and
can have quite different meanings for different use cases.  That's
because each redisplay cycle includes 2 distinct phases.  In the first
phase, the display engine builds data structures, called "desired
glyph matrices", which describe how the changed parts of the display
should look.  In the second phase, it actually updates the screen by
comparing the desired glyph matrices with the current glyph matrices
(the latter describe how the screen looks now), and writing to the
glass in the portions where the 2 sets of matrices differ.

Some use cases want to run the hook after the first phase, some (like
yours) after the second.  Moreover, redisplay can sometimes be
preempted half-way through (e.g., if some input arrives), in which
case it aborts the current cycle and doesn't update the screen.  For
some use cases, this means redisplay never happened, for others it did
(because some of the display code was run, and the corresponding side
effects happened, e.g., the fontification functions were called).  On
top of that, some legitimate use cases may wish to be able to abort
the redisplay cycle under some conditions.  Finally, the 2nd phase of
redisplay on GUI frames works by updating each window of the frame's
window tree separately, whereas text-mode frames are updated by first
building the frame-level desired glyph matrix, and then updating the
frame as a whole.  So hooks which are interested in only some windows
(e.g., the selected window) should be invoked differently for
different frame types.

The upshot of all this is that IMO if we decide to provide the
post-redisplay hook, we will need to figure out all of these use
cases, and perhaps provide separate hooks for some of them; otherwise,
I'm quite sure that soon enough someone files a bug report or posts a
message here complaining that the existing hooks don't work for
them...

Volunteers are welcome, as always.  Perhaps a useful first step would
be to collect the relevant use cases, filter out the non-relevant
ones, and then to classify the rest in some useful manner.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  7:55           ` Stefan Monnier
@ 2016-07-04 14:52             ` Eli Zaretskii
  2016-07-04 16:07             ` Clément Pit--Claudel
  1 sibling, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04 14:52 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: clement.pit, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Clément Pit--Claudel <clement.pit@gmail.com>,
>   emacs-devel@gnu.org
> Date: Mon, 04 Jul 2016 03:55:05 -0400
> 
> I don't have a clear recollection either, sorry.

It happens ;-)

> I guess part of the question is what would be the use of such a hook.
> The difference between a pre-redisplay-hook and a
> post-redisplay-hook is not very large since most of the result of
> redisplay is "invisible" to Elisp.  The main differences I can think of
> would be:
> - jit-lock stuff, in case you want to see the buffer after jit-locking.
>   but it seems you can just as well hook into jit-lock to get
>   that result.
> - scrolling, in case you want to react to changes in the user-visible
>   window-start/end.

The use case which started this thread is yet another use case which
definitely wants to run after a frame was updated.

> Of course the use could be fairly tricky, with risks of the
> post-redisplay-hook causing further redisplay-cycle ad-nauseam, but we
> already have this problem with the window-scroll-functions, IIRC.

Yes, getting this solved should be part of the job.

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  7:59         ` Andreas Schwab
@ 2016-07-04 14:52           ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04 14:52 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: mvoteiza, rms, emacs-devel

> From: Andreas Schwab <schwab@suse.de>
> Cc: Mark Oteiza <mvoteiza@udel.edu>,  rms@gnu.org,  emacs-devel@gnu.org
> Date: Mon, 04 Jul 2016 09:59:30 +0200
> 
> >> Well, pre-redisplay-functions already exists, and it appears to be a hook
> >> with equal potential for making trouble.
> >
> > No, because it runs _before_ redisplay.
> 
> But a post-redisplay hook should not be any more dangerous than a
> post-command hook.  Like the latter it could just be disabled
> automatically if anything went wrong.

It's not much more dangerous, by and large, but I think it's slightly
more dangerous, because it will most probably run from within the
display code, and thus runs the risk of triggering an infinite
redisplay loop.  By contrast, a post-command hook cannot trigger
another post-command hook (AFAIU).



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04  7:55           ` Stefan Monnier
  2016-07-04 14:52             ` Eli Zaretskii
@ 2016-07-04 16:07             ` Clément Pit--Claudel
  2016-07-04 20:37               ` Robert Weiner
  1 sibling, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 16:07 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1544 bytes --]

On 2016-07-04 03:55, Stefan Monnier wrote:
> I guess part of the question is what would be the use of such a hook.
> The difference between a pre-redisplay-hook and a
> post-redisplay-hook is not very large since most of the result of
> redisplay is "invisible" to Elisp.

Hi Stefan,

My main use case is described above in this thread; it's a very convenient way to generate relatively compact, but accurate, emacs screencasts. We don't currently have such a facility. Arthur's excellent https://github.com/Malabarba/camcorder.el comes close, but it still depends on recordmydesktop, an external application that records frames at a fixed rate. This means it sometimes misses frames, or captures too many, or shows intermediate display states.

With a post-redisplay hook, I can let emacs drive the capture process. Here's an example: http://web.mit.edu/cpitcla/www/emacs-screencast.gif (as I mentioned earlier in the thread, notice the xref pulsing and the M-x butterfly animation)

Additionally, since Emacs is driving, I can record plenty of per-frame data, such as which key is being pressed with each frame. Here's an example, which was fairly easy to assemble using this new hook and a bit of ImageMagick: http://web.mit.edu/cpitcla/www/emacs-screencast-annot.gif (it may take a bit of time to load). What do you think of the result?

I think a feature to generate such annotated screencasts would be very nice. I'll be happy to contribute the lisp code if we can find a nice way to add the necessary hooks.

Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 14:47             ` Eli Zaretskii
@ 2016-07-04 16:14               ` Clément Pit--Claudel
  2016-07-04 16:24                 ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 16:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 2843 bytes --]

On 2016-07-04 10:47, Eli Zaretskii wrote:
> redisplay-end-trigger functions are not exactly what you need in this
> context anyway (...)

Agreed; thanks for the details

> The main problem is that "end of redisplay" is not well defined, and
> can have quite different meanings for different use cases.  That's
> because each redisplay cycle includes 2 distinct phases.  In the first
> phase, the display engine builds data structures, called "desired
> glyph matrices", which describe how the changed parts of the display
> should look.  In the second phase, it actually updates the screen by
> comparing the desired glyph matrices with the current glyph matrices
> (the latter describe how the screen looks now), and writing to the
> glass in the portions where the 2 sets of matrices differ.

Thanks for taking the time to explain all of this.

> Some use cases want to run the hook after the first phase, some (like
> yours) after the second.  Moreover, redisplay can sometimes be
> preempted half-way through (e.g., if some input arrives), in which
> case it aborts the current cycle and doesn't update the screen.  For
> some use cases, this means redisplay never happened, for others it did
> (because some of the display code was run, and the corresponding side
> effects happened, e.g., the fontification functions were called).  On
> top of that, some legitimate use cases may wish to be able to abort
> the redisplay cycle under some conditions.  Finally, the 2nd phase of
> redisplay on GUI frames works by updating each window of the frame's
> window tree separately, whereas text-mode frames are updated by first
> building the frame-level desired glyph matrix, and then updating the
> frame as a whole.  So hooks which are interested in only some windows
> (e.g., the selected window) should be invoked differently for
> different frame types.

Ok. This is pretty involved :)

> The upshot of all this is that IMO if we decide to provide the
> post-redisplay hook, we will need to figure out all of these use
> cases, and perhaps provide separate hooks for some of them; otherwise,
> I'm quite sure that soon enough someone files a bug report or posts a
> message here complaining that the existing hooks don't work for
> them...

Yes, that makes a lot of sense.  On the other hand, we don't need to implement all of this at once.  As long as we're fairly sure that we understand the use cases well, we might be able to implement the parts that there is immediate demand for, leaving room for future extensions as needed. 

> Volunteers are welcome, as always.  Perhaps a useful first step would
> be to collect the relevant use cases, filter out the non-relevant
> ones, and then to classify the rest in some useful manner.

Ok. I'll start a new thread for this.

Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 16:14               ` Clément Pit--Claudel
@ 2016-07-04 16:24                 ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2016-07-04 16:24 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: monnier, emacs-devel

> Cc: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> From: Clément Pit--Claudel <clement.pit@gmail.com>
> Date: Mon, 4 Jul 2016 12:14:02 -0400
> 
> > The upshot of all this is that IMO if we decide to provide the
> > post-redisplay hook, we will need to figure out all of these use
> > cases, and perhaps provide separate hooks for some of them; otherwise,
> > I'm quite sure that soon enough someone files a bug report or posts a
> > message here complaining that the existing hooks don't work for
> > them...
> 
> Yes, that makes a lot of sense.  On the other hand, we don't need to implement all of this at once.  As long as we're fairly sure that we understand the use cases well, we might be able to implement the parts that there is immediate demand for, leaving room for future extensions as needed. 

I'd rather we implemented at least a few of the more important ones.
That's because by the time the issues are clear, the person who worked
on that knows enough to implement a few important hooks.  If we only
implement one, then the knowledge collected during the process goes
away, and the next person will have to do it all from scratch.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 16:07             ` Clément Pit--Claudel
@ 2016-07-04 20:37               ` Robert Weiner
  2016-07-04 21:00                 ` Clément Pit--Claudel
  0 siblings, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2016-07-04 20:37 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel




On Jul 4, 2016, at 12:07 PM, Clément Pit--Claudel <clement.pit@gmail.com> wrote:
> 
> Additionally, since Emacs is driving, I can record plenty of per-frame data, such as which key is being pressed with each frame. Here's an example, which was fairly easy to assemble using this new hook and a bit of ImageMagick: http://web.mit.edu/cpitcla/www/emacs-screencast-annot.gif (it may take a bit of time to load). What do you think of the result?

This is great and I would love to see this as a package and see it explained in more detail..  A simple way to capture Emacs screencasts, potentially with an audio overlay, would lead to many more demonstrations of Emacs packages leading to broader understanding and usage.

Bob


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 20:37               ` Robert Weiner
@ 2016-07-04 21:00                 ` Clément Pit--Claudel
  2016-07-04 21:28                   ` Robert Weiner
                                     ` (3 more replies)
  0 siblings, 4 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 21:00 UTC (permalink / raw)
  To: Robert Weiner; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 2319 bytes --]

On 2016-07-04 16:37, Robert Weiner wrote:
>> Additionally, since Emacs is driving, I can record plenty of
>> per-frame data, such as which key is being pressed with each frame.
>> Here's an example, which was fairly easy to assemble using this new
>> hook and a bit of ImageMagick:
>> http://web.mit.edu/cpitcla/www/emacs-screencast-annot.gif (it may
>> take a bit of time to load). What do you think of the result?
> 
> This is great and I would love to see this as a package and see it
> explained in more detail..  A simple way to capture Emacs
> screencasts, potentially with an audio overlay, would lead to many
> more demonstrations of Emacs packages leading to broader
> understanding and usage.

Thanks Bob :) Here's a quick outline of how it's done; hopefully we can
implement the necessary hook, and then I'll make an ELPA package out of it.

Essentially, my code adds two hooks:

- A pre-command-hook, to update a variable tracking (this-command-keys-vector)

- A post-display-hook, to capture screenshots.

The post-display hook records the current time and the current value of
(this-command-keys-vector), then synchronously calls ‘xwd’ to take a screenshot
(‘import’ would also work, but it is much slower). The resulting file name is
saved into a list of captured frames (annotated with the current time and value
of (this-command-keys-vector))

Finally, to finish the capture, I run a humongous ImageMagick command to stitch
together all frames and add text overlays.  The delay between consecutive frames
is computed using the timestamps recorded in each frame.

The implementation of the full thing is pretty short (about 200 lines), and it
works fairly well.  The one downside is that the temporary files that it
generates tend to take a lot of space (about 3.5MB per screenshot). Saving
compressed screenshots is possible, but it tends to slow Emacs down more
significantly.  Of course, one could imagine capturing uncompressed frames, and
compressing them in a separate thread; I have not investigated this option yet.
Alternatively, one could measure the time taken to capture the frame, and adjust
inter-frames delays in proportion when generating the movie.

I'll send the code once I have a bit of time to clean it up.

Cheers,
Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:00                 ` Clément Pit--Claudel
@ 2016-07-04 21:28                   ` Robert Weiner
  2016-07-04 21:50                     ` Clément Pit--Claudel
  2016-07-04 21:29                   ` Drew Adams
                                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2016-07-04 21:28 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 874 bytes --]

On Mon, Jul 4, 2016 at 5:00 PM, Clément Pit--Claudel <clement.pit@gmail.com>
wrote:

> The one downside is that the temporary files that it
> generates tend to take a lot of space (about 3.5MB per screenshot).
>

​Why can't you just generate a lower resolution screenshot?  There must be
a way to do so that would match the speed of capturing a higher resolution
shot.
​


> I'll send the code once I have a bit of time to clean it up.
>

​Great.  Ease of use and speed of generation would both help determine how
much it is used.  How long, for example, does it take to generate the last
video you showed with the annoations (after the frames have been captured)?

I also run Emacs natively on Mac OS X's display system, so I would have to
find an​other frame capture program or else just run it under X for this
use only.

Cheers,

Bob

[-- Attachment #2: Type: text/html, Size: 2415 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* RE: Redisplay hook
  2016-07-04 21:00                 ` Clément Pit--Claudel
  2016-07-04 21:28                   ` Robert Weiner
@ 2016-07-04 21:29                   ` Drew Adams
  2016-07-04 21:36                     ` Clément Pit--Claudel
  2016-07-04 21:57                   ` raman
  2016-07-05 22:59                   ` Richard Stallman
  3 siblings, 1 reply; 33+ messages in thread
From: Drew Adams @ 2016-07-04 21:29 UTC (permalink / raw)
  To: Clément Pit--Claudel, Robert Weiner
  Cc: Eli Zaretskii, Stefan Monnier, emacs-devel

> >> Additionally, since Emacs is driving, I can record plenty of
> >> per-frame data, such as which key is being pressed with each frame.
> >> Here's an example, which was fairly easy to assemble using this new
> >> hook and a bit of ImageMagick:
> >> http://web.mit.edu/cpitcla/www/emacs-screencast-annot.gif (it may
> >> take a bit of time to load). What do you think of the result?
> >
> > This is great and I would love to see this as a package and see it
> > explained in more detail..  A simple way to capture Emacs
> > screencasts, potentially with an audio overlay, would lead to many
> > more demonstrations of Emacs packages leading to broader
> > understanding and usage.
> 
> Thanks Bob :) Here's a quick outline of how it's done; hopefully we can
> implement the necessary hook, and then I'll make an ELPA package out of it.
> 
> Essentially, my code adds two hooks:
> - A pre-command-hook, to update a variable tracking (this-command-keys-
>   vector)
> - A post-display-hook, to capture screenshots.

Not at all related to the redisplay feature (hooks) being discussed,
but FWIW here is another key-showing approach.

By default it shows also the commands keys are bound to, but this is
controlled by option `showkey-key-only-flag'.  You can show keys using
a tooltip (`showkey-tooltip-mode') or log them in a separate frame
(`showkey-log-mode').

https://www.emacswiki.org/emacs/download/showkey.el



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:29                   ` Drew Adams
@ 2016-07-04 21:36                     ` Clément Pit--Claudel
  0 siblings, 0 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 21:36 UTC (permalink / raw)
  To: Drew Adams, Robert Weiner; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 364 bytes --]

On 2016-07-04 17:29, Drew Adams wrote:
> By default it shows also the commands keys are bound to, but this is
> controlled by option `showkey-key-only-flag'.  You can show keys using
> a tooltip (`showkey-tooltip-mode') or log them in a separate frame
> (`showkey-log-mode').
> 
> https://www.emacswiki.org/emacs/download/showkey.el

Thanks; very nice!


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:28                   ` Robert Weiner
@ 2016-07-04 21:50                     ` Clément Pit--Claudel
  0 siblings, 0 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 21:50 UTC (permalink / raw)
  To: rswgnu; +Cc: Eli Zaretskii, Stefan Monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1325 bytes --]

On 2016-07-04 17:28, Robert Weiner wrote:
> Why can't you just generate a lower resolution screenshot?  There
> must be a way to do so that would match the speed of capturing a
> higher resolution shot.
Possibly :) Lower resolution is not necessarily the best, though; for screenshots, things tend to become quite blurry when resizing. Instead, one can reduce the font size that emacs uses and make smaller screenshots.  See https://github.com/cpitclaudel/company-coq/ for examples of this (the https://github.com/cpitclaudel/company-coq/#snippets-and-smart-commands has auto-generated gifs, though they use a different technique).

> Great.  Ease of use and speed of generation would both help
> determine how much it is used.  How long, for example, does it take
> to generate the last video you showed with the annoations (after the
> frames have been captured)?

About 20 seconds, I think: ImageMagick's gif generation isn't the fastest. I hear that gifsicle is better; it could be worth exploring!

> I also run Emacs natively on Mac OS X's display system, so I would
> have to find another frame capture program or else just run it under
> X for this use only.

http://apple.stackexchange.com/questions/56561/how-do-i-find-the-windowid-to-pass-to-screencapture-l might be useful too :)

Clément.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:00                 ` Clément Pit--Claudel
  2016-07-04 21:28                   ` Robert Weiner
  2016-07-04 21:29                   ` Drew Adams
@ 2016-07-04 21:57                   ` raman
  2016-07-04 22:11                     ` Clément Pit--Claudel
  2016-07-05 22:59                   ` Richard Stallman
  3 siblings, 1 reply; 33+ messages in thread
From: raman @ 2016-07-04 21:57 UTC (permalink / raw)
  To: Clément Pit--Claudel
  Cc: Eli Zaretskii, Robert Weiner, Stefan Monnier, emacs-devel

Clément Pit--Claudel <clement.pit@gmail.com> writes:

Could you try capturing audio as well? Would help recording demos of emacspeak:-)> On 2016-07-04 16:37, Robert Weiner wrote:
>>> Additionally, since Emacs is driving, I can record plenty of
>>> per-frame data, such as which key is being pressed with each frame.
>>> Here's an example, which was fairly easy to assemble using this new
>>> hook and a bit of ImageMagick:
>>> http://web.mit.edu/cpitcla/www/emacs-screencast-annot.gif (it may
>>> take a bit of time to load). What do you think of the result?
>> 
>> This is great and I would love to see this as a package and see it
>> explained in more detail..  A simple way to capture Emacs
>> screencasts, potentially with an audio overlay, would lead to many
>> more demonstrations of Emacs packages leading to broader
>> understanding and usage.
>
> Thanks Bob :) Here's a quick outline of how it's done; hopefully we can
> implement the necessary hook, and then I'll make an ELPA package out of it.
>
> Essentially, my code adds two hooks:
>
> - A pre-command-hook, to update a variable tracking (this-command-keys-vector)
>
> - A post-display-hook, to capture screenshots.
>
> The post-display hook records the current time and the current value of
> (this-command-keys-vector), then synchronously calls ‘xwd’ to take a screenshot
> (‘import’ would also work, but it is much slower). The resulting file name is
> saved into a list of captured frames (annotated with the current time and value
> of (this-command-keys-vector))
>
> Finally, to finish the capture, I run a humongous ImageMagick command to stitch
> together all frames and add text overlays.  The delay between consecutive frames
> is computed using the timestamps recorded in each frame.
>
> The implementation of the full thing is pretty short (about 200 lines), and it
> works fairly well.  The one downside is that the temporary files that it
> generates tend to take a lot of space (about 3.5MB per screenshot). Saving
> compressed screenshots is possible, but it tends to slow Emacs down more
> significantly.  Of course, one could imagine capturing uncompressed frames, and
> compressing them in a separate thread; I have not investigated this option yet.
> Alternatively, one could measure the time taken to capture the frame, and adjust
> inter-frames delays in proportion when generating the movie.
>
> I'll send the code once I have a bit of time to clean it up.
>
> Cheers,
> Clément.
>

-- 



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:57                   ` raman
@ 2016-07-04 22:11                     ` Clément Pit--Claudel
  0 siblings, 0 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-04 22:11 UTC (permalink / raw)
  To: raman; +Cc: Eli Zaretskii, Robert Weiner, Stefan Monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 366 bytes --]

On 2016-07-04 17:57, raman wrote:
> Could you try capturing audio as well? Would help recording demos of emacspeak:-)

Audio should be easy: you just need to start an audio thread at the time when recording starts; of course gifs don't support audio, but ffmpeg works fine with sequences of images, so it should be possible to produce video relatively easily.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-04 21:00                 ` Clément Pit--Claudel
                                     ` (2 preceding siblings ...)
  2016-07-04 21:57                   ` raman
@ 2016-07-05 22:59                   ` Richard Stallman
  2016-07-05 23:47                     ` Clément Pit--Claudel
  3 siblings, 1 reply; 33+ messages in thread
From: Richard Stallman @ 2016-07-05 22:59 UTC (permalink / raw)
  To: Clément Pit--Claudel; +Cc: eliz, rswgnu, monnier, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I think it would be safer to add a feature to make a screenshot
whenever Emacs redisplays
than to add a hook that might do anything whatever.


-- 
Dr Richard Stallman
President, Free Software Foundation (gnu.org, fsf.org)
Internet Hall-of-Famer (internethalloffame.org)
Skype: No way! See stallman.org/skype.html.




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Redisplay hook
  2016-07-05 22:59                   ` Richard Stallman
@ 2016-07-05 23:47                     ` Clément Pit--Claudel
  0 siblings, 0 replies; 33+ messages in thread
From: Clément Pit--Claudel @ 2016-07-05 23:47 UTC (permalink / raw)
  To: rms; +Cc: eliz, rswgnu, monnier, emacs-devel


[-- Attachment #1.1: Type: text/plain, Size: 1169 bytes --]

On 2016-07-05 18:59, Richard Stallman wrote:
> I think it would be safer to add a feature to make a screenshot
> whenever Emacs redisplays than to add a hook that might do anything whatever.

I think a feature to make Emacs capture a screenshot of itself would be very nice (and hey, in the future, it could even be SVG instead pixel-based! That would be wonderful). 

And yet I'm not sure whether adding a flag to capture a screenshot after each redisplay cycle is the way to go. People often surprise me with the stuff they come up with Emacs, so adding a general post-redisplay-hook may enable plenty of things that we're not thinking about (and at worst, people won't use it much, just like the currently existing pre-redisplay-function).

Plus, it's not obvious that we could stretch such a capture-after-redisplay flag to cover all screencasting use cases. For example, since capturing and saving a screenshot takes time, we'd probably want to let Lisp code decide for each redisplay cycle whether to take a screenshot or not; it could decide this based on time elapsed since the last screenshot, or other factors.

What do you think?

Clément.



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2016-07-05 23:47 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-02 19:24 Redisplay hook Clément Pit--Claudel
2016-07-03  3:27 ` Eli Zaretskii
2016-07-03  4:36   ` Clément Pit--Claudel
2016-07-03  7:45     ` Eli Zaretskii
2016-07-03 14:23       ` Clément Pit--Claudel
2016-07-03 14:51         ` Clément Pit--Claudel
2016-07-03 15:37         ` Eli Zaretskii
2016-07-04  0:05       ` Clément Pit--Claudel
2016-07-04  2:41         ` Eli Zaretskii
2016-07-04  4:31           ` Clément Pit--Claudel
2016-07-04 14:47             ` Eli Zaretskii
2016-07-04 16:14               ` Clément Pit--Claudel
2016-07-04 16:24                 ` Eli Zaretskii
2016-07-04  7:55           ` Stefan Monnier
2016-07-04 14:52             ` Eli Zaretskii
2016-07-04 16:07             ` Clément Pit--Claudel
2016-07-04 20:37               ` Robert Weiner
2016-07-04 21:00                 ` Clément Pit--Claudel
2016-07-04 21:28                   ` Robert Weiner
2016-07-04 21:50                     ` Clément Pit--Claudel
2016-07-04 21:29                   ` Drew Adams
2016-07-04 21:36                     ` Clément Pit--Claudel
2016-07-04 21:57                   ` raman
2016-07-04 22:11                     ` Clément Pit--Claudel
2016-07-05 22:59                   ` Richard Stallman
2016-07-05 23:47                     ` Clément Pit--Claudel
2016-07-03 22:34   ` Richard Stallman
2016-07-04  0:09     ` Clément Pit--Claudel
2016-07-04  2:42       ` Eli Zaretskii
2016-07-04  0:22     ` Mark Oteiza
2016-07-04  2:42       ` Eli Zaretskii
2016-07-04  7:59         ` Andreas Schwab
2016-07-04 14:52           ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).