Root cause (see issue #218 discussion):
- QETApp::eventFiltrer (Q_OS_DARWIN) was correct in intent but never
actually installed as an event filter anywhere, and its name didn't
match the QObject::eventFilter virtual signature, so even if it had
been installed it would never have been invoked as an override.
Confirmed dead code.
- main.cpp instead routed Finder's QFileOpenEvent through
MacOSXOpenEvent -> SingleApplication::sendMessage(), which is the
secondary-to-primary IPC channel. Called from within the primary
instance itself, sendMessage() fails silently and the file path is
dropped, which is exactly what double-click does (Finder doesn't spawn
a secondary process, the running instance receives the FileOpen event
directly).
- openFiles() takes a QETArguments, not a QStringList. The dead code's
openFiles(QStringList() << filename) only worked via an untested
implicit QStringList -> QList<QString> -> QETArguments conversion
chain.
Fix:
- Rename eventFiltrer -> eventFilter (qetapp.h/.cpp) so it's a proper
override of QObject::eventFilter, and make it public so main.cpp can
install it on QApplication.
- Build the QETArguments explicitly instead of relying on implicit
conversion.
- main.cpp: drop MacOSXOpenEvent entirely (include + instantiation),
install qetapp as the Q_OS_MACOS event filter on app right after
QETApp qetapp; is constructed and before app.exec(). No race window:
the event loop hasn't started, so no QFileOpenEvent can be delivered
before the filter is installed.
QETArguments::handleFileArgument() already sorts files by extension
(.elmt, titleblock, else project) and openFiles() already fans out to
openProjectFiles()/openElementFiles()/openTitleBlockTemplateFiles()
accordingly, so this single fix covers .qet, .elmt and .titleblock
double-click/drag-to-dock on macOS, not just .qet.
SingleApplication's sendMessage/receivedMessage flow (used for CLI args
on all platforms) is untouched; this only touches the Q_OS_MACOS block,
so there is no behavior change on Windows/Linux.
Follow-up (not included here): the macOS Info.plist (misc/Info.plist)
has an empty CFBundleShortVersionString, which may affect macOS's
willingness to retain file associations across app updates.
1. machine_info.h: zero-initialise Screen struct members
Max_width, Max_height, count, width[] and height[] were bare
int32_t with no initialiser. The comparisons in
init_get_Screen_info() read them before any write, producing
undefined behaviour flagged by Valgrind as 'Conditional jump
or move depends on uninitialised value(s)'.
2. main.cpp: pre-initialise MachineInfo on the main thread
MachineInfo::instance() was first called inside QtConcurrent::run(),
causing its constructor (which calls qApp->screens()) to run on a
background thread. QScreen methods are not thread-safe in Qt5.
Calling instance() once on the main thread before the worker
launches guarantees the singleton is fully built first; subsequent
calls from the worker just return the cached pointer.
3. qetdiagrameditor.h: move m_first_show before the QActionGroup members
C++ initialises members in declaration order. m_first_show was
declared after the QActionGroup members (line 256 vs 168). During
construction of m_row_column_actions_group(this), Qt dispatches a
QObject parent-change event that reaches QETDiagramEditor::event(),
which reads m_first_show before it has been initialised.
Moving the declaration to the top of the first private: block
ensures it is initialised before any member that can trigger events.
All three found via Valgrind --tool=memcheck on Ubuntu 22.04 / Qt 5.15.3.
Relates-to: PR #514 (same QtConcurrent thread-safety pattern).
QETProject schedules an asynchronous crash-recovery backup on construction
(writeBackup() -> QtConcurrent::run(QET::writeToFile, ..., &m_backup_file)).
In one-shot CLI mode the QETProject is destroyed as soon as the command
returns, while that background write still references its m_backup_file
member — an intermittent use-after-free segfault during teardown (~1 in 6
runs; observed on --resave and --set-titleblock).
A crash-recovery backup is meaningless for a short-lived headless command,
so add QETProject::setBackupEnabled(false), called from the CLI entry in
main(). writeBackup() then early-returns, so no background write is ever
launched. Fixes the crash for all CLI commands. See #492.
Implements the long-requested batch/headless export
(bugtracker #171, GitHub #309): render a project's diagrams to files
without opening the GUI.
qelectrotech --export-pdf <project.qet> <output.pdf> one multi-page PDF
qelectrotech --export-png <project.qet> <output_dir> one PNG per diagram
qelectrotech --export-svg <project.qet> <output_dir> one SVG per diagram
main.cpp detects an export request before SingleApplication is created (so the
arguments are not forwarded to a running instance), spins up a plain
QApplication for rendering, and exits with the export's status code.
Rendering reuses Diagram::render() over
BorderTitleBlock::borderAndTitleBlockRect(), the same geometry the GUI
print/export path uses, so output matches the editor. Image files are named
NN_Title.<ext>.
New files: sources/cli_export.{h,cpp}, registered in
cmake/qet_compilation_vars.cmake.
Because on windows MachineInfo take a little time to init, we make it to
a singleton.
MachineInfo is build the first time in main.cpp.
Now all other places where we use MachineInfo (aboutqetdialog and
configdialog) gui don't hang anymore in waiting to MachineInfo finish to
build.