On the core Wayland clipboard, a read waited for the app that copied to
close its pipe, and a send wrote until the app that pastes took all of
the data. An app that left its pipe open and stopped held the one read
worker, so later pastes failed at once, or held one of the eight send
threads until it closed its end.
Reads and sends now use the pipe nonblocking and wait for it with poll.
When no byte moves for 2 s (VectorCraft's own limit, the existing text
wait) the read fails without pasting partial data and the send stops;
both close their pipe. The wait starts again after each byte that moves,
so a large transfer that keeps going is not cut short.
On Linux and the BSDs, the desktop draws the window's frame on X11, on
Wayland compositors that draw server-side decorations and in a window
opened through XWayland. There, with VectorCraft Title Bar on Every
Desktop off, the window has the desktop's title bar with System Title
Bar on or off, and the dialog showed nothing about it under System
Title Bar.
- The desktop app records at startup whether VECTORCRAFT_TITLEBAR is
unset and the desktop would draw the frame without VectorCraft Title
Bar on Every Desktop (VectorcraftApp::desktop_keeps_frame), from the
frame probe and the launch path's XWayland choice.
- Preferences shows a note under System Title Bar in that case while
VectorCraft Title Bar on Every Desktop is off, with rows in the 27
catalogs that carry the neighboring title bar notes. The value is
worked out at startup, so a Linux Display Server change shows in the
note from the next start.
Docs: docs/control-protocol.md, docs/target-app-parity.md.
docs/control-protocol.md said the window has no OS decorations on
Windows and Linux. On Linux and the BSDs the app bar is the title bar by
default only on a Wayland session without server-side decorations, such
as GNOME, in a window not opened through XWayland; elsewhere the desktop
draws the frame unless VectorCraft Title Bar on Every Desktop or
VECTORCRAFT_TITLEBAR=app turns the app frame on. The paragraph now says
so.
docs/development.md said the custom title bar is the Linux default. It
now says where the app bar is the default title bar. The comment on
CUSTOM_TITLEBAR in apps/vectorcraft/src/titlebar.rs made the same
Windows and Linux claim and now names Windows only.
On Linux and the BSDs, craft-window reads the desktop's window-button
layout (`button-layout` in `org.gnome.desktop.wm.preferences`) into
`Frame::App` when the desktop leaves the window's frame to the app, but
the app bar ignored it and always drew Minimize, Maximize and Close at
its right end.
- `CaptionLayout` lists the buttons at each end of the bar;
`caption_buttons` draws them there in the listed order, first one
leftmost, and the bar's other controls keep clear of both groups.
- The desktop app copies the layout of an app frame the desktop left to
it. An app frame turned on by `VECTORCRAFT_TITLEBAR=app` or by
VectorCraft Title Bar on Every Desktop, a window opened through
XWayland, macOS and Windows keep all three at the right.
Docs: docs/control-protocol.md, docs/target-app-parity.md.
When the desktop portal's process exited while its save dialog was
open, no Response came. The stream that save_file read does not end
while the session bus stays up, so the save waited forever on the
calling thread and rfd's dialog never showed.
save_file now waits with the screen color sampler's Responses, which
moves from linux_screen_color/request.rs to portal_request.rs and is
built on Linux and the BSDs. Before the call it listens for the
Response and for the bus's NameOwnerChanged for the portal's name, so
the wait ends with an error when the connection that replied leaves
the bus, and the caller shows rfd's dialog, as for other portal errors.
When the bus reports the portal gone, the wait first reads the
Responses already queued, so an answer the portal sent before it left
is still the answer. Before, the sampler's wait could take the bus's
report while that answer was queued and end with an error.
The mock portal gains three modes that close its connection after the
reply: 300 ms later without a Response, at once without a Response,
and at once after the Response. The private bus helper of the
sampler's tests moves to portal_request.rs, and the save dialog's
tests use it, so a failing test also stops its bus.
Preferences > Performance > Use Monitor Profile for Canvas (on by default,
`monitorProfileDisplay`) converts the canvas's art, artboard paper and
transparency grid from sRGB into the ICC profile of the display that shows
most of the main window, after any proof. Arranged panes and the render
worker's frames are converted too; the worker keeps its frame in sRGB.
- Windows: the display's default profile for its standard color mode
(ColorProfileGetDisplayDefault, GetICMProfileW where it is missing). A
display with Advanced Color on is left to Windows.
- X11: colord's profile for the RandR output, then the output's
`_ICC_PROFILE`, then the screen's when only one output is active.
- A Wayland session stays sRGB; macOS converts the window itself.
- A profile that is missing, larger than 1 MiB, not an RGB display
profile or unreadable leaves the canvas sRGB, with the reason in
`ui.inspect`'s `displayProfile`.
The conversion is sampled into a 33x33x33 table when a profile is read, on
a background thread. Exports, `ui.render` and the document are unchanged.
On Linux the Paste menu's background check holds its own clipboard
handle. When the app quit while that check's X11 text read was still
unanswered, quitting stopped waiting for the check's thread after 5 s,
but the handle's read worker holds arboard's handle until 25 s after the
read was sent. The app's own handle was then dropped first, so it was
not the last one alive to hand what was copied to a clipboard manager.
- CLIPBOARD_PROBE_STOP_WAIT (27 s, exported from vectorcraft-ui-egui)
replaces the 5 s bound: the 25 s X11 read limit plus LOAD_WAIT, the
2 s limit on waiting for a reader to stop. Quitting still ends after
it when a host's handle never lets go.
- On Linux and the BSDs, on_exit hides the main window before eframe
drops the app, so the window closes at once while the process waits
for the clipboard handles. The window is hidden, not closed, and the
connection the clipboards use stays open. winit hides X11 windows,
XWayland ones included; it cannot hide a native Wayland window, which
stays on screen until the wait ends. macOS and Windows are unchanged.
- Probe's Drop waits through an injectable function, so a test drives
the wait with a controllable clock while the probe's handle is still
being dropped and checks that it is dropped before the app's.
- A Linux test in the app checks the bound against X11_READ_LIMIT and
LOAD_WAIT, so raising either fails it.
- Comments and docs/development.md describe the wait.
Where arboard has neither data-control nor X11 (the Flatpak on a GNOME
Wayland session), Copy and Paste used smithay-clipboard on the window's
connection, which carries text only. They now use a core wl_data_device
client on that connection.
- One Copy offers the PNG as image/png, the SVG as image/svg+xml (with
Include SVG Code on) and the text as text/plain;charset=utf-8,
UTF8_STRING and text/plain. A format with no data is not offered.
- Paste reads SVG, then text, then PNG. Blank text, or text that only
names a picture, gives way to the PNG, and a failed or empty SVG read
falls back to the types after it. The Paste menu item is enabled by the
types offered, without reading any data.
- The clipboard holds VectorCraft's Copy while its data source is not
canceled and the offer has the Copy's types.
- A read takes 64 MiB at most. Text waits 2 s, SVG and PNG 10 s off the
UI thread. Another app's paste is sent on its own thread, 8 at once.
smithay-clipboard is no longer a dependency of the app.
The AppKit cursor adapter set its cursor again only when
NSCursor.currentCursor differed from it. But that is the app's last set
cursor, not the one on screen: when the pointer moves, AppKit can put
the system arrow back while currentCursor still reads as ours, so the
adapter kept the arrow. Pressing V over the canvas showed the Selection
tool's arrow, and the first move replaced it with the system pointer.
While it owns the cursor, the adapter now sets it on every pass. That
costs nothing when it is already showing.
Each built-in category (Mobile, Web, Print, Film & Video, Art &
Illustration, Branding, Social) has a New Document profile, a native
document in the New Document Profiles folder next to the preferences.
file.new copies the profile's swatches, graphic styles, brushes, symbols,
patterns, character and paragraph styles, rulers, Document Setup options,
assigned color profiles and print settings into the new document. The
preset's size, units, artboards, bleed, background, color mode and
resolution still apply, and the profile's art and layers are not copied.
- file.newProfiles lists the profiles, file.newProfiles.edit opens one
as a document (writing the shipped profile first), and
file.newProfiles.reset deletes its file. file.new takes `profile`.
- Saved and Recent presets keep the profile of the preset they came from.
- A profile that cannot be read, is larger than 64 MiB or is not a native
document leaves the defaults, and file.new reports it in profileError.
- New Document has a Manage Profiles pop-up with Edit and Reset.
Docs: docs/mcp.md, docs/target-app-parity.md.
The save dialog read the portal's current_filter with zvariant's tuple
conversion, which panics on a structure with fewer fields than the
tuple. On Linux and the BSDs the dialog's thread then ended after the
user picked a file, and nothing was saved. The label is now read only
from a (sa(us)) structure, the shape the FileChooser portal defines.
An answer of another shape keeps the path and names no file type, as
an answer without current_filter does. A structure with more fields
than (sa(us)) also no longer names a file type.
Exporting the window for the portal waits for the compositor to answer. The
sampler now does it on its worker thread, as the portal's save dialog does,
so a slow compositor does not hold up the UI.
On Linux, ui.sampleScreenColor and the Color Picker's eyedropper button
now show the XDG desktop portal's color sampler (Screenshot.PickColor,
https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Screenshot.html).
A thread of its own makes the call and waits for the person, and the
picked sRGB color goes through the same conversion into the working RGB
space as on macOS and the web. A cancel leaves the colors as they were.
A session without a portal that has PickColor, a portal that does not
return from the call within 25 seconds (VectorCraft's own limit) or
leaves the bus before it answers, and a portal that ends the request in
another way each show a status message and end the wait. The two new
messages are translated in every catalog that has the sampler's other
messages. The request token is random, as the Request documentation
asks (https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Request.html).
The window is named for the portal on the UI thread, as for the save
dialog, and the sampler's thread keeps the window and its export until
the portal answers.
A save or export that writes a file per artboard, linked images or image
maps names them after the file picked in the save panel, which asked only
about that name. A file already there under one of the other names was
replaced without a question.
Save As, Save a Copy, Save as Template, Save and Export now check those
files before writing anything. When any is there, nothing is written and
a replaceFiles question names it (and lists all of them when there are
several). OK runs the save or export again on the document that asked and
replaces the named files; a file it would now write that the question did
not name is asked about again. Cancel writes nothing. A background save
or export checks from its worker and asks once it ends, after a dialog
open then. Files the document's last Save or Save As wrote are replaced
without asking.
Services::exists is now an Arc<dyn Fn(&str) -> bool + Send + Sync>.
The Stroke panel menu's Edit Arrowheads… (stroke.arrowheads.edit) opens
Arrowheads.vectorcraft next to the preferences, creating it with one
example head when it is missing. Each symbol in the file is one head,
listed by name after the built-in heads in both arrowhead menus: it
points right, its registration point is the tip, and its height is drawn
as wide as the built-in heads. The file is read at startup and again
each time VectorCraft saves it; stroke.arrowheads.reload and
stroke.arrowheads.list read and list it.
Arrowhead gets a Custom variant, appended after the built-in names, that
carries the head's name and outline, so a document that uses one draws,
saves, reopens and exports it without the arrowheads file. stroke.set
takes {"custom": name} or the {"Custom": {name, path}} form that
document.inspect reports.
Part of #5421.
The input hook, the logic and the interface of a frame now mark their
time as timed whatever the activity around them, so a frame the system
runs while an in-line file dialog waits for the user is timed too, and
the dialog's wait is not timed again once the frame ends.
The end of a frame counted the renderer as busy only when the main
window had the focus, so a stall drawing input in a focused floating
panel or document window wrote no hang report. A floating window that
has the focus and is not minimized now counts too. A frame that sends
that window commands to minimize or hide it, or to move or resize it,
ends idle, including commands its own pass sent, which are noted
before egui passes them on.
The app that answers a late read may have lost the clipboard while the
paste waited. Once the answer comes, the paste makes the same read again
and uses the new answer, for arboard's reads and the core protocol's
text read alike.
The text and file-list reads that follow a late answer now wait until
10 s after the unanswered read was sent, not 2 s from when they start,
so a slow text answer is still pasted. Text that is blank or names a
picture is replaced by the bitmap only when the paste asks for one.
An in-line save dialog that first makes its folder marked the folder
work as the dialog too, so a stall in making the folder wrote no hang
report. The folder is now made before the dialog is marked, on the
background dialog thread as well, and a test checks the order.
The core-protocol text clipboard (used where the compositor has no
data-control protocol and there is no X11) failed a paste at once after
its 2 s read timeout, so the paste took the internal clipboard even when
the other app's text came within the paste's 10 s limit. It now keeps a
text read that got no answer in its wait, as the arboard path does, and
the paste waits for that answer on its background thread until 10 s
after the read was sent. The answer is pasted unless it is empty or the
text copied here.
When the check whether the clipboard still holds what VectorCraft copied,
or one of a paste's own reads, gets no answer within its 2 s, the read is
kept. The paste then waits for that answer on its background thread, up
to 10 s after the read was sent, instead of failing its other reads at
once and pasting the internal clipboard. When the answer is what
VectorCraft copied, or none comes, the paste takes the internal
clipboard; otherwise the clipboard is read as a paste reads it, with that
answer standing in for its read. An answer that came before the paste is
dropped and the clipboard is read again.
When the interface thread stays in one part of a frame for 3 s, a
watching thread writes a hang report to the log and to
logs/hang-report-<process id>.txt. The report gives the part of the
frame (input hook, logic, interface, or the renderer after a frame in
which any window had input), a system clipboard call in progress, the
last 8 different command ids, the last 16 frame times, the platform,
window system, desktop and session type, Flatpak, graphics adapter, the
present mode and frame latency the app asks for, the running time and
the number of open documents. It holds no document contents, file paths
or command parameters. The interface thread marks its stages with a few
atomic stores a frame, and the watching thread reads those marks without
waiting on it.
The process keeps the report file locked until the interface answers
again, then removes it. A file nobody holds at a later launch was left
by a session that was closed while it did not answer: the launch writes
the report to the log, moves the file to logs/hang-report.1.txt and,
unless another start-up message is showing, says so in the status bar.
Help › Copy Troubleshooting Info puts the platform facts, the recent
commands and frame times and both sessions' reports on the clipboard for
a bug report. An in-line file dialog, an open menu of the macOS menu bar,
and the time after a frame that minimizes or hides the window or starts
moving or resizing it are not timed.
The menu label and the two status messages have rows in every catalog.
A paste on Linux and the BSDs read the bitmap on the clipboard worker but
waited up to 10 s for it on the UI thread, so a bitmap from an app that
never sent its data froze the window long enough for the compositor to
offer to close it.
The paste now sends the bitmap read to the worker and returns at once;
its background thread waits up to 10 s for the answer and converts it to
PNG. While that read is open, other reads fail at once instead of
queuing behind it. Each read gets its own answer channel, so a late
answer is dropped. The check of whether the clipboard still holds the
app's own bitmap waits 2 s at most, as text does.