Hi...

On Sun, 5 Jul 2026 at 12:02, Ihor Radchenko <[email protected]> wrote:

> Pedro Andres Aranda Gutierrez <[email protected]> writes:
>
> >> Also, I have no clue "please test this stuff!" is asking to do.
> >>
> > Then, you should have the same problem with the Beamer example I didn't
> > write ;|
>
> Hmm. Yeah. Ok then. (I still do not like it, but let it be)
>
ACK

> >> > \texttt should not make a frame fragile, while \verb@@ should. So why
> >> use
> >> > frame* instead of frame in ltx-talk.
> >> > Side effect, we don't mark Beamer frames as fragile if they really
> aren't
> >>
> >> Ok, but can you make it a separate commit?
> >
> > Keep it here. If someone knowing ltx-talk sees a frame* that has nothing
> > fragile in it, that *will* raise questions.
>
> My point is that it changes beamer export as well, not just ltx-talk.
> If this change turns out to be a problem later, it will be very
> confusing that adding ltx-talk breaks beamer.
>
> My suggestion is simple: (1) change the beamer first; (2) apply ltx-talk
> support /after/ that change.
>
Since ltx-talk doesn't break with frame* not really needing *, I have
removed this.
Keep it for the future...

> >> > +                   (list
> >> > +                    (and (not (member "allowframebreaks" options))
> >> > +                         (not (cl-some (lambda (s) (string-match-p
> >> "^label=" s))
> >> > +                                       options))
> >>
> >> You did not address my comment here.
> >> We do not auto-generate label when it is provided in options, but what
> >> if name=... is given?
> >>
> > allowframebreaks is never mentioned in the ltx-talk manual. So this case
> > just doesn't apply.
>
> Consider a frame like
>
> ** Frame
> :PROPERTIES:
> :BEAMER_OPT: label=mylabel
> :END:
>
> This has nothing to do with allowframebreaks, I only meant


> >> > +                         (not (cl-some (lambda (s) (string-match-p
> >>> "^label=" s))
>

Sigh... I didn't get what you were after. I have changed this to search for
label or name depending on the class...

> >
> >> +popular display formats. Additionally, the Beamer exporter also
> supports
> >
> > "Additionally, ... also" sounds strange. Again, this is minor.
>
> You did not address this comment.
>
You said is was minor, so I ignored it... Anyhow, I've rewritten the
sentence...

>
> > +Added to check that the ltx-talk adaptation doesn't break anything in
> Beamaer."
>
> *Beamer
>
Done

>
> --
> Ihor Radchenko // yantar92,
> Org mode maintainer,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>


-- 
Fragen sind nicht da, um beantwortet zu werden,
Fragen sind da um gestellt zu werden
Georg Kreisler

"Sagen's Paradeiser" (ORF: Als Radiohören gefährlich war) => write BE!
Year 2 of the New Koprocracy

This was produced by a human (implied virtues and weaknesses acknowledged)
I'd hate this being fed to any form of AS (sorry AI)...
From 969d8f99729e8258410b5a005c2de7f74c78b20a Mon Sep 17 00:00:00 2001
From: "Pedro A. Aranda" <[email protected]>
Date: Sun, 05 Jul 2026 14:07:18 +0200
Subject: ox-beamer.el: add ltx-talk support

* etc/ORG-NEWS: Announce ltx-talk support in Beamer
* doc/org-manual.org: Beamer exporter section: explain what accesibility
means; add a link to the ltx-talk documentation in CTAN.
Beamer export commands: mention that theme-related Beamer keywords don't
apply for ltx-talk and will be ignored.
Add explicitly LATEX_CLASS: ltx-talk as an example
ltx-talk example: derive it from the Beamer example to highlight
differences.  Add obervations and a table with blocks and if they are
supported or not.
* lisp/ox-beamer.el top level: add ltx-class to org-latex-classes.
(org-beamer--format-frame):  Fragile frames use the frame* environment
with ltx-talk.
Labels in ltx-talk are passed as 'name=xxx'.
Frame title needs an explicit \frametitle{} for ltx-talk (could also be
used for beamer and __greatly__ simplify the code!!)
(org-beamer-template): bail out with error if ltx-talk doesn't see
lualatex as the compiler.
Suppress beamer theme for ltx-talk.
* testing/lisp/test-ox-beamer.el (test-ox-beamer/ltx-talk-class): Basic
test for ltx-talk code.
(test-ox-beamer/ltx-talk-multi-line-metadata): Document metadata can be
 multiline.
(test-ox-beamer/ltx-talk-multi-verb-frame): Frame with example is
frame*.
(test-ox-beamer/beamer-verb-frame): Make sure fragile frames continue to
work as expected -fragile in the options- with the Beamer class.
---
 doc/org-manual.org             |  87 ++++++++++++++++++++-
 etc/ORG-NEWS                   |  10 +++
 lisp/ox-beamer.el              |  69 ++++++++++-------
 testing/lisp/test-ox-beamer.el | 169 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 305 insertions(+), 30 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 96de73975..63eba83f8 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -13104,11 +13104,20 @@ It's just a jump to the left...
 Org uses Beamer export to convert an Org file tree structure into
 high-quality interactive slides for presentations.  Beamer is a LaTeX
 document class for creating presentations in PDF, HTML, and other
-popular display formats.
+popular display formats. In addition to the =beamer= class, the
+exporter can also handle documents using the =ltx-talk= class to
+produce accessible presentations that can be handled, for example, by
+screen readers for people with visual impairments. [fn:: The
+=ltx-class= needs a recent *LuaLaTeX* compiler.] Section [[*An example
+of a presentation using =ltx-talk=]] discusses the main differences
+between both classes.

 We strongly recommend familiarizing yourself with Beamer terminology
 before reading the rest of this chapter.  See
 <https://en.wikipedia.org/wiki/Beamer_(LaTeX)> and references therein.
+If you plan to use =ltx-talk=, consult the
+[[https://mirrors.ctan.org//macros/latex/contrib/ltx-talk.tds.zip/ltx-talk.pdf][=ltx-talk=
+documentation]].

 *** Beamer export commands
 :PROPERTIES:
@@ -13147,7 +13156,8 @@ before reading the rest of this chapter.  See

 Beamer export backend has several additional keywords for customizing
 Beamer output.  These keywords work similar to the general options
-settings (see [[*Export Settings]]).
+settings (see [[*Export Settings]]). *Note:* =BEAMER_..._THEME=
+keywords do not apply to =ltx-talk= and will be ignored.

 - =BEAMER_THEME= ::

@@ -13206,6 +13216,16 @@ settings (see [[*Export Settings]]).
   ~org-latex-title-command~ to configure typesetting of subtitle as
   part of front matter.

+- =LATEX_CLASS= ::
+
+  #+cindex: @samp{SUBTITLE}, keyword
+  The LaTeX class to use. Implicitly set to =beamer=. Set it
+  explicitly to =ltx-talk= to use this class:
+
+  #+BEGIN_SRC org
+,#+LATEX_CLASS: ltx-talk
+  #+END_SRC
+
 *** Frames and Blocks in Beamer
 :PROPERTIES:
 :DESCRIPTION: For composing Beamer slides.
@@ -13280,6 +13300,7 @@ should in principle be exportable as a Beamer presentation.
   headlines.  To manually adjust them for any unique configurations
   needs, use the =BEAMER_ENV= property.

+
 *** Beamer specific syntax
 :PROPERTIES:
 :DESCRIPTION: For using in Org documents.
@@ -13403,6 +13424,68 @@ Here is an example of an Org document ready for Beamer export.
     Please test this stuff!
 #+end_example

+*** An example of a presentation using =ltx-talk=
+
+=ltx-talk= is an alternative to the =beamer= class. It depends on
+LuaLaTeX and produces tagged PDF files with enhanced accessibility
+features for screen readers and similar applications. The Beamer
+exporter can produce presentations for this class, too. The following
+is the version of the Beamer example above adapted to ~ltx-talk:~
+
+#+BEGIN_SRC org
+,#+STARTUP: beamer
+,#+OPTIONS: toc:nil H:2 title:t
+,#+LATEX_COMPILER: lualatex
+,#+LATEX_CLASS: ltx-talk
+,#+LATEX_DOC_METADATA: tagging=on
+
+,#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col)
+,* This is the first structural section
+
+,** Frame 1
+,*** Thanks to Eric Fraga                                           :B_block:
+    :PROPERTIES:
+    :BEAMER_COL: 0.48
+    :BEAMER_ENV: block
+    :END:
+    for the first viable Beamer setup in Org, which also works for =ltx-class=
+,*** Thanks to everyone else                                        :B_block:
+    :PROPERTIES:
+    :BEAMER_COL: 0.48
+    :BEAMER_ACT: <2->
+    :BEAMER_ENV: block
+    :END:
+    for contributing to the discussion.
+
+,** Frame 2 (where we will not use columns)
+,*** Request
+
+1. Please read the notes, because not all Beamer environments are supported.
+2. Please test this stuff!
+
+#+END_SRC
+
+**** Differences between Beamer and =ltx-talk=
+     :PROPERTIES:
+     :UNNUMBERED: notoc
+     :END:
+
+1. You need to add document metadata to your document. ~tagging=on~ is
+   the minimum to produce a usable presentation.
+2. ~#+BEAMER_..._THEME~ keywords will be silently ignored.
+3. Beamer environments not supported in =ltx-talk= are:
+
+   | Beamer environment | Support | Comment         |
+   |--------------------+---------+-----------------|
+   | =alertblock=       | Partial | Only =alertenv= |
+   | =theorem=          | No      |                 |
+   | =definition=       | No      |                 |
+   | =proof=            | No      |                 |
+   | =beamercolorbox=   | No      |                 |
+   | =exampleblock=     | No      |                 |
+   | =note=             | No      |                 |
+   |--------------------+---------+-----------------|
+
 ** HTML Export
 :PROPERTIES:
 :DESCRIPTION: Exporting to HTML.
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 22cc760d8..f5bc3a908 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -144,6 +144,16 @@ A current limitation is that export blocks and keywords are only
 implemented for events and todos, and not yet for calendar-wide
 properties.

+*** ox-beamer.el now supports the ltx-talk class
+
+ltx-talk is an alternative document class for presentations that can
+produce PDFs with extra information for on-screen reader
+applications. It will only work with LuaLaTeX.
+
+Presentations written with Beamer and ltx-talk are mostly portable,
+except that Beamer theme information is ignored when using ltx-talk
+and some environments listed in the manual are not supported.
+
 ** New and changed options

 # Changes dealing with changing default values of customizations,
diff --git a/lisp/ox-beamer.el b/lisp/ox-beamer.el
index 4ebfca1f9..b7b5aacb5 100644
--- a/lisp/ox-beamer.el
+++ b/lisp/ox-beamer.el
@@ -44,7 +44,11 @@ (unless (assoc "beamer" org-latex-classes)
 		 ("\\section{%s}" . "\\section*{%s}")
 		 ("\\subsection{%s}" . "\\subsection*{%s}")
 		 ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))))
-
+(unless (assoc "ltx-talk" org-latex-classes)
+  (add-to-list 'org-latex-classes
+	       '("ltx-talk"
+		 "\\documentclass{ltx-talk}"
+		 ("\\section{%s}" . "\\section*{%s}"))))

 
 ;;; User-Configurable Variables
@@ -77,7 +81,7 @@ (defcustom org-beamer-frame-level 1

 (defcustom org-beamer-frame-default-options ""
   "Default options string to use for frames.
-For example, it could be set to \"allowframebreaks\"."
+For example, it could be set to \"allowframebreaks\" for Beamer."
   :group 'org-export-beamer
   :type '(string :tag "[options]"))

@@ -136,7 +140,7 @@ (defcustom org-beamer-outline-frame-title "Outline"

 (defcustom org-beamer-outline-frame-options ""
   "Outline frame options appended after \\begin{frame}.
-You might want to put e.g. \"allowframebreaks=0.9\" here."
+You might want to put e.g. \"allowframebreaks=0.9\" for Beamer here."
   :group 'org-export-beamer
   :safe #'stringp
   :type '(string :tag "Outline frame options"))
@@ -476,26 +480,30 @@ (defun org-beamer--format-frame (headline contents info)
 				                  (match-string 1 beamer-opt))
 			                     ",")))))
 		   (fragile
-		    ;; Add "fragile" option if necessary.
-		    (and fragilep
+		    ;; Add "fragile" option if necessary for beamer.
+		    (and (equal latex-class "beamer")
+                         fragilep
 			 (not (member "fragile" options))
 			 (list "fragile")))
+                   ;; ltx-talk uses name instead of label
+                   (label-str (or (and (equal latex-class "beamer") "label")
+                                  "name"))
 		   (label
 		    ;; Provide an automatic label for the frame unless
 		    ;; the user specified one.  Also refrain from
 		    ;; labeling `allowframebreaks' frames; this is not
 		    ;; allowed by Beamer.
 		    (and (not (member "allowframebreaks" options))
-			 (not (cl-some (lambda (s) (string-match-p "^label=" s))
+			 (not (cl-some (lambda (s) (string-match-p (concat "^" label-str "=" s)))
 				       options))
 			 (list
 			  (let ((label (org-beamer--get-label headline info)))
 			    ;; Labels containing colons need to be
 			    ;; wrapped within braces.
 			    (format (if (string-match-p ":" label)
-					"label={%s}"
-				      "label=%s")
-				    label))))))
+					"%s={%s}"
+				      "%s=%s")
+                                    label-str label))))))
 	      ;; Change options list into a string.
 	      (org-beamer--normalize-argument
 	       (mapconcat #'identity (append label fragile options) ",")
@@ -869,7 +877,11 @@ (defun org-beamer-template (contents info)
 CONTENTS is the transcoded contents string.  INFO is a plist
 holding export options."
   (let ((title (org-export-data (plist-get info :title) info))
-	(subtitle (org-export-data (plist-get info :subtitle) info)))
+	(subtitle (org-export-data (plist-get info :subtitle) info))
+        (beamer-class (plist-get info :latex-class)))
+    (when (equal beamer-class "ltx-talk")
+      (unless (equal "lualatex" (plist-get info :latex-compiler))
+        (error "ox-beamer: `ltx-talk' needs LuaLaTeX!")))
     (concat
      ;; Timestamp.
      (and (plist-get info :time-stamp-file)
@@ -883,24 +895,25 @@ (defun org-beamer-template (contents info)
        (format "\\newenvironment<>{%s}[1][]{\\begin{frame}#2[environment=%1$s,#1]}{\\end{frame}}\n"
                org-beamer-frame-environment))
      ;; Insert themes.
-     (let ((format-theme
-	    (lambda (prop command)
-	      (let ((theme (plist-get info prop)))
-		(when theme
-		  (concat command
-			  (if (not (string-match "\\[.*\\]" theme))
-			      (format "{%s}\n" theme)
-			    (format "%s{%s}\n"
-				    (match-string 0 theme)
-				    (org-trim
-				     (replace-match "" nil nil theme))))))))))
-       (mapconcat (lambda (args) (apply format-theme args))
-		  '((:beamer-theme "\\usetheme")
-		    (:beamer-color-theme "\\usecolortheme")
-		    (:beamer-font-theme "\\usefonttheme")
-		    (:beamer-inner-theme "\\useinnertheme")
-		    (:beamer-outer-theme "\\useoutertheme"))
-		  ""))
+     (unless (equal beamer-class "ltx-talk")
+       (let ((format-theme
+	      (lambda (prop command)
+	        (let ((theme (plist-get info prop)))
+		  (when theme
+		    (concat command
+			    (if (not (string-match "\\[.*\\]" theme))
+			        (format "{%s}\n" theme)
+			      (format "%s{%s}\n"
+				      (match-string 0 theme)
+				      (org-trim
+				       (replace-match "" nil nil theme))))))))))
+         (mapconcat (lambda (args) (apply format-theme args))
+		    '((:beamer-theme "\\usetheme")
+		      (:beamer-color-theme "\\usecolortheme")
+		      (:beamer-font-theme "\\usefonttheme")
+		      (:beamer-inner-theme "\\useinnertheme")
+		      (:beamer-outer-theme "\\useoutertheme"))
+		    "")))
      ;; Possibly limit depth for headline numbering.
      (let ((sec-num (plist-get info :section-numbers)))
        (when (integerp sec-num)
diff --git a/testing/lisp/test-ox-beamer.el b/testing/lisp/test-ox-beamer.el
index 482f22c8f..fc775dfc7 100644
--- a/testing/lisp/test-ox-beamer.el
+++ b/testing/lisp/test-ox-beamer.el
@@ -111,5 +111,174 @@ (ert-deftest test-ox-beamer/orgframe-in-one-example ()
      (should (search-forward (concat "\\end{frame}") nil t))
      (should (search-forward (concat "\\end{" org-beamer-frame-environment "}"))))))

+(ert-deftest test-ox-beamer/ltx-talk-class ()
+  "Initial test for a simple ltx-talk example.
+1. Default Metadata is inserted
+2. Sectioning is supported
+3. Labels and Beamer theme stuff are ignored"
+
+  (let ((org-latex-compiler "lualatex")
+        (org-latex-hyperref-template nil)
+        (org-latex-packages-alist nil)
+        (org-latex-default-packages-alist nil))
+    (org-test-with-exported-text
+     'beamer
+     "#+STARTUP: beamer
+#+OPTIONS: toc:nil H:2
+#+LATEX_CLASS: ltx-talk
+#+LATEX_CLASS_OPTIONS:
+#+LATEX_CLASS_PRE: \\DocumentMetadata{tagging = on}
+#+TITLE: Testing =ltx-talk=
+#+BEAMER_THEME: Boadilla
+
+* A section
+** A frame
+- First
+- Second
+- Third
+"
+     ;; (message "--> \n%s" (buffer-string))
+     (goto-char (point-min))
+     ;; ltx-talk ignores theme info
+     (save-excursion (should-not (search-forward "\\usetheme{" nil t)))
+     ;; ltx-talk doesn't generate labels
+     (save-excursion (should-not (search-forward "[label=]" nil t)))
+     (save-excursion
+       (should (search-forward "\\DocumentMetadata{tagging = on}\n" nil t))
+       (should (search-forward "\\documentclass{ltx-talk}\n" nil t))
+       (should (search-forward "\\section{A section}" nil t))
+       (should (search-forward "\\frametitle{A frame}" nil t))))))
+
+(ert-deftest test-ox-beamer/ltx-talk-multi-line-metadata ()
+  "Initial test for a simple ltx-talk example.
+1. Default Metadata is inserted
+2. Sectioning is supported
+3. Labels are supppressed."
+  (let ((org-latex-compiler "lualatex")
+        (org-latex-hyperref-template nil)
+        (org-latex-packages-alist nil)
+        (org-latex-default-packages-alist nil))
+    (org-test-with-exported-text
+     'beamer
+     "#+STARTUP: beamer
+#+OPTIONS: toc:nil H:2
+#+LATEX_CLASS: ltx-talk
+#+LATEX_CLASS_OPTIONS:
+#+LATEX_CLASS_PRE: \\DocumentMetadata{lang=en,
+#+LATEX_CLASS_PRE:   pdfstandard = ua-2,
+#+LATEX_CLASS_PRE:   pdfstandard = a-4f,
+#+LATEX_CLASS_PRE:   pdfversion = 2.0,
+#+LATEX_CLASS_PRE:   tagging=on}
+#+LATEX_CLASS_PRE: \\tagpdfsetup{table/header-rows={1},role / new-tag = frametitle / H2}
+#+TITLE: Testing =ltx-talk=
+#+BEAMER_THEME:
+
+* A section
+** A frame
+- First
+- Second
+- Third
+"
+     ;; (message "--> \n%s" (buffer-string))
+     (goto-char (point-min))
+     (save-excursion (should-not (search-forward "\\usetheme{" nil t)))
+     (save-excursion (should-not (search-forward "[label=]" nil t)))
+     (save-excursion
+       (should (search-forward "\\DocumentMetadata{lang=en," nil t))
+       (should (search-forward "pdfversion = 2.0," nil t))
+       (should (search-forward "tagging=on}" nil t))
+       (should (search-forward "\\tagpdfsetup{table" nil t))
+       (should (search-forward "\\section{A section}" nil t))
+       (should (search-forward "\\frametitle{A frame}" nil t))))))
+
+(ert-deftest test-ox-beamer/ltx-talk-frame-subtitle ()
+  "Test that a frame with verbatim elements uses \"frame*\"."
+  (let ((org-latex-compiler "lualatex")
+        (org-latex-hyperref-template nil)
+        (org-latex-packages-alist nil)
+        (org-latex-default-packages-alist nil))
+    (org-test-with-exported-text
+     'beamer
+     "#+STARTUP: beamer
+#+OPTIONS: toc:nil H:2 title:t
+#+LATEX_CLASS: ltx-talk
+#+LATEX_DOC_METADATA: tagging=on
+#+LATEX_CLASS_OPTIONS: handout
+#+TITLE: Testing =ltx-talk= verbatims
+#+BEAMER_THEME:
+
+* A section
+** A frame
+- First
+- Second
+- Third
+** A second frame with a subtitle
+   :properties:
+   :beamer_subtitle: Testing listings
+   :end:
+- This is a listing:
+  #+BEGIN_SRC python
+import sys
+
+print(\"Hello, ltx-talk!\", file=sys.stderr)
+  #+END_SRC
+"
+     ;; (message "--> \n%s" (buffer-string))
+     (goto-char (point-min))
+     (save-excursion (should-not (search-forward "\\usetheme{" nil t)))
+     (save-excursion (should-not (search-forward "[label=]" nil t)))
+     (save-excursion
+       (should (search-forward "\\DocumentMetadata{tagging=on}" nil t))
+       (should (search-forward "\\documentclass[handout]{ltx-talk}" nil t))
+       (should (search-forward "\\section{A section}\n" nil t))
+       (should (search-forward "\\begin{frame}" nil t))
+       (should (search-forward "\\frametitle{A frame}\n" nil t))
+       (should (search-forward "\\end{frame}" nil t))
+       (should (search-forward "\\begin{frame*}" nil t))
+       (should (search-forward "\\frametitle{A second frame with a subtitle}\n" nil t))
+       (should (search-forward "\\framesubtitle{Testing listings}\n" nil t))
+       (should (search-forward "\\end{frame*}" nil t))))))
+
+(ert-deftest test-ox-beamer/beamer-verb-frame ()
+  "Test that a frame with verbatim elements sets fragile in beamer.
+Added to check that the ltx-talk adaptation doesn't break anything in Beamer."
+  (let ((org-latex-compiler "lualatex")
+        (org-latex-hyperref-template nil)
+        (org-latex-packages-alist nil)
+        (org-latex-default-packages-alist nil))
+    (org-test-with-exported-text
+     'beamer
+     "#+STARTUP: beamer
+#+OPTIONS: toc:nil H:2 title:t
+#+LATEX_CLASS_OPTIONS: [presentation,11pt,t]
+#+TITLE: Testing =beamer= verbatims
+#+BEAMER_THEME: Boadilla
+
+* A section
+** A frame
+- First
+- Second
+- Third
+** A frame with a listing
+- This is a listing:
+  #+BEGIN_SRC python
+import sys
+
+print(\"Hello, beamer!\", file=sys.stderr)
+  #+END_SRC
+"
+     ;; (message "--> \n%s" (buffer-string))
+     (goto-char (point-min))
+     (save-excursion
+       (should-not (search-forward "\\DocumentMetadata{tagging=on}" nil t)))
+     (save-excursion
+       (should (search-forward "\\documentclass[presentation,11pt,t]{beamer}" nil t))
+       (should (search-forward "\\usetheme{" nil t)))
+       (should (search-forward "\\section{A section}\n" nil t))
+       (should (search-forward-regexp "^\\\\begin{frame}\\[.+?]{A frame}$" nil t))
+       (should (search-forward "\\end{frame}\n" nil t))
+       (should (search-forward-regexp "^\\\\begin{frame}\\[.+?\\,fragile]{A frame with a listing}$" nil t))
+       (should (search-forward "\\end{frame}\n" nil t)))))
+
 (provide 'test-ox-beamer)
 ;;; test-ox-beamer.el ends here

Reply via email to