Appending something to the body of every frame

beamerbeamer-metropolis

Is it possible to append something to the body of every frame in beamer?

Specifically, I would like to include \par\unskip right before \end{frame} so that the bottom margin of full slides is the same regardless of whether the slide ends with text, an enumerate environment, or a displayed formula. I am using the metropolis theme, for which the difference is quite noticeable.

enter image description here enter image description here

My two ideas were to either use

\addtobeamertemplate{footline}{\par\unskip}{}

or the standard trick

\let\oldendframe\endframe
\def\endframe{\par\unskip\oldendframe}

The first one doesn't work because \lastskip has been forgotten at that point. The second doesn't' work because \endframe is never actually used. Where it is defined in beamerbaseframe.sty, there's a comment:

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

I don't quite understand plain TeX well enough to understand how the body of the frame is processed to figure out where I would need to include the \par\unskip. Does anybody know how one would achieve this? Here is an MWE:

\documentclass{beamer}
\usetheme{metropolis}
\usepackage{lipsum}

\begin{document}

\begin{frame}
\frametitle{This frame ends in text}

\begin{enumerate}
\item \lipsum[1][1]
\item \lipsum[1][2]
\item \lipsum[1][3]
\item \lipsum[1][4-5]
\item \lipsum[1][6]
\end{enumerate}

\lipsum[1][7-13] This is the bottom margin in metropolis.
%\par\unskip % it works if entered manually
\end{frame}

\begin{frame}
\frametitle{This frame ends in a formula}
\begin{enumerate}
\item \lipsum[1][1]
\item \lipsum[1][2]
\item \lipsum[1][3]
\item \lipsum[1][4-5]
\item \lipsum[1][6]
\end{enumerate}

\lipsum[1][7-12]
\[ a + b = c \]
%\par\unskip % it works if entered manually
\end{frame}
\end{document}

If \par\unskip is inserted manually, it looks better to my eyes.

enter image description here enter image description here

Best Answer

Patching the end part of internal environment beamer@frameslide seems to work. This environment is defined as (see beamerbaseframe.sty)

\newenvironment{beamer@frameslide}{%
  % ...
  \global\setbox\beamer@framebox=\vbox\bgroup
    % ...
    \begin{beamer@framepauses}%
      % ...
}{%
      \par
    \end{beamer@framepauses}%
  \egroup
  % ...
}

So we only need to append \unskip right after \par in \endbeamer@frameslide:

\documentclass{beamer}
\usetheme{metropolis}
\usepackage{lipsum}

\makeatletter
\patchcmd\endbeamer@frameslide
  {\par}
  {\par\unskip}
  {}{\PatchFailed}
\makeatother

\begin{document}

\begin{frame}
  \frametitle{This frame ends in text}
  
  \begin{enumerate}
    \item \lipsum[1][1]
    \item \lipsum[1][2]
    \item \lipsum[1][3]
    \item \lipsum[1][4-5]
    \item \lipsum[1][6]
  \end{enumerate}
  
  \lipsum[1][7-13] This is the bottom margin in metropolis.
  %\par\unskip % it works if entered manually
\end{frame}

\begin{frame}
  \frametitle{This frame ends in a formula}
  \begin{enumerate}
  \item \lipsum[1][1]
  \item \lipsum[1][2]
  \item \lipsum[1][3]
  \item \lipsum[1][4-5]
  \item \lipsum[1][6]
  \end{enumerate}
  
  \lipsum[1][7-12]
  \[ a + b = c \]
  %\par\unskip % it works if entered manually
\end{frame}
\end{document}

enter image description here

Related Question