* Show: Presenter View only with a second display
With one display the presenter window opened on the same screen as the show. Under Hyprland's
focus-follows-mouse, whichever window the pointer was over took full screen, and the hidden one
stalled every frame: the show lagged, dropped key presses or froze.
One display now shows only the slides, as in PowerPoint. The host counts displays through winit's
monitor list when a show starts; hosts that can't tell keep Presenter View.
* Show: count displays by MonitorHandle
Wayland lists one output twice under the same wl_output id, so comparing handles counts it once, and two separate displays with the same name and geometry still count as two.
* Show: docs for Presenter View with a second display
slideshow-parity and hardware-parity note that on Linux one display shows only the slides, with status lines and revision history; ROADMAP progress log. display_count collects into a BTreeSet (MonitorHandle's Ord matches its Eq).
* Show: docs state the one-display rule exactly
Presenter View stays off when winit lists exactly one display; if it lists none, the setting is kept. The host callback covers Unix other than macOS, so the docs say Linux and the BSDs.
* Apply review fixes
- docs/slideshow-parity.md
---------
Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
Review follow-up on #1658:
- The drag duplicate cleared `ph` without detaching, so a title or body
dragged off with Alt lost its size and bullets. Copy, Duplicate and the
drag now share `detach_on_slide`.
- Detaching at copy time turned a slide placeholder pasted in Slide Master
view into a regular shape. The clipboard keeps the originals, and a paste
there takes them, so it stays a placeholder as before this PR. Keep
Source Formatting bakes them too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Ogg: include recovered tail packets in Opus duration
Keep the existing missing-granule recovery cursor in step with the packet ends it assigns. Add a regression for a partially and entirely unanchored stream; existing valid end-trimming coverage remains unchanged.
Validation: rustc --edition=2024 --test crates/ogg/src/lib.rs: all 12 tests pass. Scoped rustfmt check passes. Full cargo --offline xtask ci is blocked before build by the uncached pinned egui checkout.
* Ogg: record recovery duration correction
A same-origin page that frames DeckCraft's web build with ?host=parent
sends a file with deckcraft:open and gets every save back as
deckcraft:save {name, saveAs, bytes} instead of a download, with
deckcraft:ready, deckcraft:dirty and deckcraft:failed, as GridCraft,
WordCraft and PdfCraft do. Without ?host=parent nothing changes.
Save follows the desktop app. Every file from the page opens through
file.adopt like File > Open on the desktop; a presentation sent with a
presentation name keeps that name as its file, so Save (Ctrl+S, the
File tab, the Close prompt or the command palette) writes it back under
that name and format with saveAs: false. Anything else (no name, an
outline, a damaged file opened as a repaired copy, a dropped file) is
untitled, and its first Save is a new <title>.deckcraft with saveAs:
true, as is Save As. Exports and Print are copies (saveAs: false).
Host mode starts with an empty presentation that gives way to the first
file while untouched, &author= signs comments, and the URL flags are
read as whole parameters so a free-text author can't set ?show.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1693 found that cast_effects built the picture content that a shadow,
a glow and a reflection are drawn from without converting a tiled fill to
points, so inside a scaled group the reflection of a tiled picture showed
child-space tiles while its face showed the right ones.
The content now goes through paint::tiled_picture_per_point with per_point_xy,
as the face does.
Test: a tiled picture's reflection in groups scaled 0.25, 1600 and 2x0.5 shows
the same colours as in an unscaled group; it fails without the change.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review of #1693 found two more places that drew a tiled picture fill in the
shape's own (child-space) units inside a scaled group.
A group nested in a scaled group stored its own tiled fill unconverted, so the
members that take it (grpFill) got oversized tiles. The owning group now
converts the fill with per_point_xy when it stores it, so inheriting members,
directly or through a chain of grpFill groups, get the converted tile.
A picture shape (p:pic) whose blip fill is a tile passed its own fill straight
to paint::picture. It now goes through paint::tiled_picture_per_point, which
tiled_per_point also uses.
Tests: a group's tile passed to its members and a picture shape's own tile, each
in outer groups scaled 1, 0.25, 1600 and 2x0.5; both fail without the change.
Docs: the Picture and texture fill checklist row is re-assessed (remains P) with
its status line and revision history, and the ROADMAP progress log row mentions
both cases.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A tiled picture fill (a:blipFill with a:tile) was sized in the shape's own
units. Inside a group whose child space differs from its box (old decks write
child spaces ~1800 times smaller) one tile covered hundreds of boxes, so the
fill showed a single flat texel instead of the texture.
PowerPoint's own PNG export of a synthetic probe deck shows the tile keeps its
size, offset, anchor and mirroring in slide points whatever the group's scale,
uniform or stretched unevenly, nested or flipped. The tile is now converted
from points to shape units per axis (Renderer::per_point_xy, paint::
tiled_per_point), and snapped to whole device pixels per axis.
Tiles with rotWithShape="0" are drawn in device pixels and were sized in
pixels, ignoring the zoom (even outside groups); they are now sized to pixels
first.
Tests: a tile in groups of seven scales (uniform and uneven, wide and tall
tile), and an upright tile in a turned shape at zoom 1 and 2.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A browser's Copy Image puts the picture on the clipboard together with
text that only names it (the address and alt text, or Firefox's UTF-16
text/x-moz-url read as UTF-8) and an <img> HTML fragment. Ctrl+V only
looked for a picture when the text was empty, so it pasted a text box
with the link. When the text or HTML only names a picture, paste the
picture; with no picture on the clipboard the link still pastes as text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A placeholder copied or duplicated on a slide became a regular shape by
clearing `ph`, which also dropped everything it inherited from its layout
and master: the title's 44 pt heading font, the body's bullets and indent
levels, autofit and the box. Without `ph` the text fell back to the
presentation's default style (18 pt, no bullets), on Ctrl+V and the
context menu alike.
`resolve::detach_placeholder` makes the inherited box, fill, line,
effects, body properties and every level's text style the shape's own
before `ph` is cleared. Theme references stay references, so the default
paste still follows the destination theme. Copy (so Cut and pasting into
another deck work after the source is gone) and Duplicate use it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #1350 (v0.11.1) the desktop build listed eframe features without
`clipboard`, so egui-winit simulated a clipboard inside the app: Ctrl+V
never read text or pictures from other apps, and Ctrl+C of text (sent out
as HTML through arboard) never reached egui's clipboard, so Ctrl+V pasted
nothing or stale text. The context menu kept working because it only uses
the session clipboard.
Turn the feature back on. On native Wayland, egui-winit owns the clipboard
through winit's data device (text and PNG); leave the X11-only arboard
pasteboard (HTML, pictures) off there so copies are claimed on the Wayland
selection. Regression tests guard the feature list and the Wayland switch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>