# Run a command at end of each Frame

I want to run a command (writing page ranges to a file) at the end of each frame.

I can capture the page the frame started with at the beginning with \AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}.

But if I try to write the page range at the end of the frame, it does not work: It seems that \AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}} doesn't get executed.

Is there anything I can do instead?

MMWE:

\documentclass{beamer}

\usepackage{etoolbox}

\newwrite\notesfile
\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}
\AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}}

\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{frame}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}
\end{frame}

\begin{frame}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}
\end{frame}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile
\end{document}


This is what the beamer base frame template - beamerbaseframe.sty - says about the frame "environment":

% Normally not executed; only in containsverbatim context:
\def\endframe{\egroup\begingroup\def\@currenvir{frame}}


So, if you try to tap into \end{frame}, it might not end up as expected. Instead, you have to dig into some of the beamer bowels to find a location where you can write content out to your file. The following patch grabs on to an appropriate location:

\documentclass{beamer}

\usepackage{etoolbox}

\newwrite\notesfile
\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\arabic{page}}}
\makeatletter
\patchcmd{\beamer@doseveralframes}% <cmd>
{\beamer@reseteecodes}% <search>
{\beamer@reseteecodes\immediate\write\notesfile{\framebeginpage-\number\numexpr\value{page}-1\relax}}% <replace>
{}{}% <success><failure>
\makeatother

\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{frame}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}
\end{frame}

\begin{frame}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}
\end{frame}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile

\end{document}


The output file frames.txt displays

Begin
1-3
4-6
End


You could create a wframe environment to do the writing. EDITED to correct \thepage representation by one.

\documentclass{beamer}
\usepackage{etoolbox}

\newcounter{tmpcnt}
\newwrite\notesfile
%\AtBeginEnvironment{frame}{\global\edef\framebeginpage{\thepage}}
%\AtEndEnvironment{frame}{\immediate\write\notesfile{\framebeginpage-\thepage}}
\newenvironment{wframe}{\global\edef\framebeginpage{\thepage}\begin{frame}}
\immediate\write\notesfile{\framebeginpage-\thetmpcnt}}

\begin{document}
\immediate\openout\notesfile=frames.txt
\immediate\write\notesfile{Begin}

\begin{wframe}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}
\end{wframe}

\begin{wframe}
\begin{itemize}[<+->]
\item foo
\item bar
\item baz
\end{itemize}

\end{wframe}

\immediate\write\notesfile{End}
\immediate\closeout\notesfile
\end{document}


The contents of frames.txt that results is

Begin
1-3
4-6
End

• Will wframe behave as frame with respect to the optional and "mandatory" arguments? Feb 3 '15 at 19:30
• @GonzaloMedina I think it will, since 1) it is the last item in the \begin{wframe} definition AND 2) wframe is defined with 0 arguments. Thus, when \begin{frame} is called at the end of \begin{wframe}, I think its arguments will be waiting for it in the input stream. Feb 3 '15 at 19:34
• Thanks! But I'd rather not use a different environment.
– moi
Feb 3 '15 at 21:39
• @moi I understand that rationale. Hats off to Werner for decoding the problem. Feb 3 '15 at 21:41