1

For the geometry package, is it possible to \newgeometry{…} and fully \restoregeometry inside a group?

Minimal Example

In the following, the \restoregeometry inside the {…} restores frames, but still affects \stretch{…} on page 3.

Bad

\documentclass{article}

\usepackage[showframe]{geometry}
\geometry{
  paperwidth = 10cm,
  paperheight = 6cm,
  vmargin = 0.2cm,
}

\begin{document}

1 Top \par
\vspace{\stretch{1}}
1 Bottom

{
  \newgeometry{vmargin = 1cm}
  2 Top \par
  \vspace{\stretch{1}}
  2 Bottom
  \clearpage
  \restoregeometry % 👈 Here
}

3 Top \par
\vspace{\stretch{1}}
3 Bottom

\clearpage

4 Top \par
\vspace{\stretch{1}}
4 Bottom

\end{document}

I can get the following desired result by moving \restoregeometry outside the group (after the }).

Good

But is it possible to achieve the same thing and keep \restoregeometry inside the group?

Explanation of the phenomenon is also appreciated. Thanks in advance.

Background

I am developing a *.cls, and I want to provide a command to generate a page with specific texts and special vertical margins. Therefore, \newgeometry{…} and \restoregeometry will be put into a group.

Further Info

Versions:

  • Windows 10
  • XeTeX 3.141592653-2.6-0.999996 (TeX Live 2024)
  • geometry revision 61719

unexpected result with \newgeometry in curly brackets · Issue #14 · LaTeX-Package-Repositories/geometry:

\newgeometry is making settings in the pdf back end to set the page size (as well as TeX-level settings) TeX grouping doesn't really make sense at that level and the back end settings are not restored at the end of the group, you need an explicit restore.

5
  • 1
    no, you shouldn't use them inside a group. Normally the commands should only be used between pages and at the outer level. (And don't misuse them, in many cases there are easier ways to change some settings then to reset all page dimensions). Commented May 22 at 17:23
  • Thanks! Could you explain those easier ways? \setlength\topmargin{…}? @UlrikeFischer
    – Y.D.X.
    Commented May 22 at 17:29
  • You could use e.g. changepage instead. I don't know if there is anything newer. But it allows you to alter margins etc. for specific pages or for parts of pages. Don't set things like margins explicitly if you're using geometry unless you really know what you're doing. (I don't, so I wouldn't.)
    – cfr
    Commented May 22 at 17:29
  • I see… Would someone write it as an answer? I'll accept it. Thank you.
    – Y.D.X.
    Commented May 22 at 17:37
  • no, it is unclear what you actually want. E.g. if you really want the footer and header to move. Commented May 22 at 18:39

2 Answers 2

1

You can use changepage to alter the layout of pages or of parts of pages.

Note that your code produces warnings from geometry because the area for marginal notes does not fit the page. geometry suggests extending the right margin, but I've reduced the width of the area and the separation between the text block and the marginpar area.

  • \changepage{<text height>}{<text width>}{<evenside margin>}{<oddside margin>}{<column sep>}{<top margin>}{<head height>}{<head sep>}{<foot skip>} is a maxed-out macro in terms of arguments, since it dates (I guess) from before key-value interfaces became common. This makes keeping track of the arguments a bit tricky. However, once you figure out which argument to change, you can just set the others to 0pt as it uses the values to adjust the existing values rather than starting from scratch.
    • So here we want the first argument to be -1.6cm and the sixth 0.8cm.

Using \clearpage\restoregeometry then works to reinstate the original values.

\documentclass{article}

\usepackage[showframe,verbose]{geometry}
\geometry{
  paperwidth = 10cm,
  paperheight = 6cm,
  vmargin = 0.2cm,
  marginparwidth = 30pt,% to address geometry warning
  marginparsep=5pt,
}
\usepackage{changepage}
\pagestyle{empty}% because there is no room!
\begin{document}

1 Top \par
\vspace{\stretch{1}}
1 Bottom
\clearpage

\changepage{-1.6cm}{0pt}{0pt}{0pt}{0pt}{0.8cm}{0pt}{0pt}{0pt}
% changes to: text ht | text wd | evenside margin | oddside margin | column sep
% top margin | head height | head sep | foot skip
% current values can be read off the terminal output with verbose option for geometry
2 Top \par
\vspace{\stretch{1}}
2 Bottom
\clearpage
\restoregeometry % 👈 Here

3 Top \par
\vspace{\stretch{1}}
3 Bottom

\clearpage

4 Top \par
\vspace{\stretch{1}}
4 Bottom

\end{document}

OK multipage images are currently beyond me due to a bug in Okular-on-X. Single page images are getting better, but this answer exceeds my current capabilities.

0

All assignments can be made temporary global with \globaldefs=1:

\globaldefs=1
\restoregeometry
\globaldefs=0

but this may create arbitrary unexpected effects elsewhere (see David Carlisle's comments below or this answer).

It is then preferable to export globally the settings done by geometry. To get them all, you can define a new command \makegeometryglobal with

\makeatletter
\NewDocumentCommand{\makegeometryglobal}{ }
 {%
   %% lengths saved in \Gm@save and set by \Gm@restore
   \global\paperwidth=\paperwidth%
   \global\paperheight=\paperheight%
   \global\textwidth=\textwidth%
   \global\textheight=\textheight%
   \global\evensidemargin=\evensidemargin%
   \global\oddsidemargin=\oddsidemargin%
   \global\topmargin=\topmargin%
   \global\headheight=\headheight%
   \global\headsep=\headsep%
   \global\topskip=\topskip%
   \global\footskip=\footskip%
   \global\baselineskip=\baselineskip%
   \global\marginparsep=\marginparsep%
   \global\marginparwidth=\marginparwidth%
   \global\columnsep=\columnsep%
   \global\hoffset=\hoffset%
   \global\voffset=\voffset%
   \global\Gm@layoutwidth=\Gm@layoutwidth%
   \global\Gm@layoutheight=\Gm@layoutheight%
   \global\Gm@layouthoffset=\Gm@layouthoffset%
   \global\Gm@layoutvoffset=\Gm@layoutvoffset%
   %% booleans saved in \Gm@save and set by \Gm@restore
   \global\let\if@twocolumn\if@twocolumn%
   \global\let\if@twoside\if@twoside%
   \global\let\if@mparswitch\if@mparswitch%
   \global\let\if@reversemargin\if@reversemargin%
   %% lengths set in \Gm@changelayout
   \global\@colht=\@colht%
   \global\@colroom=\@colroom%
   \global\vsize=\vsize%
   \global\columnwidth=\columnwidth%
   \global\hsize=\hsize%
   \global\linewidth=\linewidth%
   %% boolean set in \Gm@changelayout
   \global\let\if@firstcolumn\if@firstcolumn%
  }
\makeatother

and use

\restoregeometry
\makegeometryglobal

Example:

\documentclass{article}

\usepackage[showframe]{geometry}
\geometry{
  paperwidth = 10cm,
  paperheight = 6cm,
  vmargin = 0.2cm,
}

\makeatletter
\NewDocumentCommand{\makegeometryglobal}{ }
 {%
   %% lengths saved in \Gm@save and set by \Gm@restore
   \global\paperwidth=\paperwidth%
   \global\paperheight=\paperheight%
   \global\textwidth=\textwidth%
   \global\textheight=\textheight%
   \global\evensidemargin=\evensidemargin%
   \global\oddsidemargin=\oddsidemargin%
   \global\topmargin=\topmargin%
   \global\headheight=\headheight%
   \global\headsep=\headsep%
   \global\topskip=\topskip%
   \global\footskip=\footskip%
   \global\baselineskip=\baselineskip%
   \global\marginparsep=\marginparsep%
   \global\marginparwidth=\marginparwidth%
   \global\columnsep=\columnsep%
   \global\hoffset=\hoffset%
   \global\voffset=\voffset%
   \global\Gm@layoutwidth=\Gm@layoutwidth%
   \global\Gm@layoutheight=\Gm@layoutheight%
   \global\Gm@layouthoffset=\Gm@layouthoffset%
   \global\Gm@layoutvoffset=\Gm@layoutvoffset%
   %% booleans saved in \Gm@save and set by \Gm@restore
   \global\let\if@twocolumn\if@twocolumn%
   \global\let\if@twoside\if@twoside%
   \global\let\if@mparswitch\if@mparswitch%
   \global\let\if@reversemargin\if@reversemargin%
   %% lengths set in \Gm@changelayout
   \global\@colht=\@colht%
   \global\@colroom=\@colroom%
   \global\vsize=\vsize%
   \global\columnwidth=\columnwidth%
   \global\hsize=\hsize%
   \global\linewidth=\linewidth%
   %% boolean set in \Gm@changelayout
   \global\let\if@firstcolumn\if@firstcolumn%
  }
\makeatother

\begin{document}

1 Top \par
\vspace{\stretch{1}}
1 Bottom

{
  \newgeometry{vmargin = 1cm}
  2 Top \par
  \vspace{\stretch{1}}
  2 Bottom
  \clearpage
  \restoregeometry
  \makegeometryglobal
}

3 Top \par
\vspace{\stretch{1}}
3 Bottom

\clearpage

4 Top \par
\vspace{\stretch{1}}
4 Bottom

\end{document}
7
  • 1
    virtually no latex declarations do anything sensible if globaldefs is 1. Commented May 22 at 18:04
  • I don't understand this answer. You say \globaldefs=0 is useless at the end of a group, but haven't you placed it at the end of a group?
    – cfr
    Commented May 22 at 18:08
  • @DavidCarlisle I just discover the parameter \globaldefs, and I understand changing its value is rather dangerous. But it's the solution I found to make global \newgeometry settings when set, for example, with \AddToHook (like in this answer).
    – jlab
    Commented May 22 at 19:26
  • 2
    well newgeometry executes \newpage and (sometimes) that locally sets \everypar to empty so if you set this then \everypar is globally set empty, are you sure that is safe or intended here? Commented May 22 at 19:40
  • 2
    if for example any code called within the scope of globadefs did \newcommand\foo{...} then it wouldn't just make \foo globally defined. \newcommand looks for an optional argument so calls \@ifnextchar which is \long\def\@ifnextchar#1#2#3{% \let\reserved@d=#1% \def\reserved@a{#2}% \def\reserved@b{#3}% \futurelet\@let@token\@ifnch} so \[email protected] and \@let@token are all then given global definitions which may have arbitrary unexpected effects elsewhere. Commented May 22 at 19:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .