mirror of
https://github.com/logos-co/logos-app.git
synced 2026-08-27 17:31:13 +00:00
master
23
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f6bca12270 |
Test/MCP preparation UI tests (#338)
* ci(tests): run shutdown-test in the PR gate and enforce the combined suite time budget
* test(harness): add shared fixtures (LGX generator, G-ERR/G-ALIVE/G-EXIT gates, xfail runner) and rea
* test(ui): assert welcome page state on first launch before any interaction (A1)
* fix(tests): retry the A1 greeting assertion so it cannot race the async launcherApps refresh
* ci(tests): tee the app log into BASECAMP_APP_LOG so the ui-tests G-ERR gate scans real output
* fix(tests): typename
* fix(tests): shutdown test to follow behavior from
|
||
|
|
9b8cf6e47e |
feat(shell): ship main_ui as a plugin that links no logos runtime
Measured on the built artefact: main_ui.dylib DEFINES zero and IMPORTS zero of
TokenManager, StoreRegistry, LogosAPI, LogosAPIClient and logos_core_*, out of
3410 symbols read. It links Qt and nothing else from this workspace, which
nix/symbol-gate.nix enforces across the in-process image set.
Getting there needed the last non-Qt types off the boundary: the model
properties cross as QAbstractItemModel*, catalogInstallStageChanged carries an
int rather than InstallStage::Value, and the two prebuilt AppsFilterProxy
instances are declared in QML instead of owned by MainUIBackend. That last one
removes a real inversion -- PackageCoordinator called setRequiredPackages() on
a proxy the host held a pointer to; it now emits requiredPackagesResolved() and
QML binds to the republished property.
Window resolves the plugin, qobject_casts it to IShellView, checks
hostAbiVersion() against IShellHost_abi, and calls createShell(IShellHost*).
No error-label fallback widget: that degraded to something that looked like a
working app with an empty window.
Filter proxies read role constants off host-side models and InstallEnums is
used by nine host files, so app/interfaces/ gains the contract headers both
sides compile against -- the models inherit the role structs, leaving every
AppsModel::NameRole call site unchanged. The plugin's include path is
app/interfaces only, so including a host header does not compile.
Four things only running it finds:
* Logos::DesignSystem may be linked by exactly ONE image -- both linked it
and the app aborted with "Cannot add multiple registrations for
Logos.Icons"; QML module registration is process-global
* qmltyperegistrar emits no #include for a SOURCES header given as an
absolute path outside the project
* each qt_add_qml_module is its own target and inherits no include dirs
* AUTOMOC pairs header<->cpp by same-basename-same-DIRECTORY, which the
split breaks
tst_AppManagerView.qml grows five tests for the QML binding, checked with a
negative control: breaking one assertion fails qml-tests, so they run.
|
||
|
|
9c3d023062 |
feat(shell): put the UI shell behind IShellHost, and order its shutdown
The shell held the host's objects: MainContainer owned MainUIBackend, took a
LogosAPI* and a QtLogosCore*, and connected to backend signals by concrete
type. Nothing stopped it minting identities or reading the token store.
Three headers in app/interfaces/, on the include path both targets share, so
there is exactly one copy and source drift is impossible:
* IShellHost -- 8 operations the shell may perform
* IShellObserver -- 5 notifications the host may deliver
* IShellView -- how the host builds and tears down the shell
Only QObject*, QWidget* and Qt value types cross. MainContainer holds one
IShellHost* and nothing else; QML reaches the backend as an opaque QObject*
via backendObject(), resolved through the metaobject, so no host C++ type has
to be nameable by the shell.
Ownership inverts: Window owns MainUIBackend, ShellHostAdapter and
MainShellView; the shell borrows. Teardown stops being a consequence of
construction order and becomes a stated contract:
1. beginShutdown() unmounts in-process UI plugin widgets WHILE the shell's
tree is intact -- they are docked inside it
2. destroyShell() detaches the observer, then deletes the shell
3. the backend goes, tearing down Package -> UIPlugin -> Core
4. main() destroys the core facade
Every observer forward is null-guarded: PluginLoader dispatches through
QTimer::singleShot(0, ...) and a 30s ViewModuleHost timeout, so a callback can
land after teardown starts, and QPointer cannot help -- IShellObserver is not
a QObject. UIPluginManager's plugin-widget maps become QPointer for the
mirror-image reason: those widgets are docked inside the shell, so its Qt
parent can destroy them without going through unloadUiModule.
IComponent is untouched and still serves the third-party legacy widget
plugins PluginLoader loads.
|
||
|
|
13665a5e34 |
feat(host-core): adopt the SDK core facade, and delete both C ABI mirrors
CoreModuleManager and main.cpp each carried a hand-written `extern "C"` mirror
of liblogos' core-management ABI -- two blocks declaring the same symbols in
one image, an ODR hazard with no diagnostic. Both are replaced by
logos::qt::QtLogosCore over logos::host::LogosCore, which owns the
char*/char** marshalling, the `delete[]`-not-`free()` rule, and the pre-start
ordering constraint -- the last as constructor arguments, so the illegal order
stops being expressible.
Four things about the stats path that fail INVISIBLY, all preserved:
* "cpu"/"memory" stay 1-decimal STRINGS -- QML and ModuleInstanceModel bind
those names, so the facade's cpuPercent/memoryMb spelling stops here
* allStats() is called ONCE per tick; each moduleStats(name) repeats the
full C call and parse, and the snapshot walks every known module
* the three-way back-compat fallbacks are kept for older runtimes
* memoryMb (double), never memoryBytes
The cpp-sdk lock moves for that last point: the pin predated the rename, and
that pair does not compile -- qt-sdk's header reads s.memoryMb while the
pinned cpp-sdk struct still called it memoryBytes.
Also drops a QTimer in main.cpp that was started and stopped with no
connect() at all.
|
||
|
|
7851bf9f46 |
feat(host): per-plugin identities, an opt-in access policy, and the source split
Each loaded plugin -- including pure-QML ones -- gets its own LogosAPI identity rather than sharing the host's, so a plugin's calls are attributable and can be refused independently. The host-services grant is wired through to capability_module, and its trust root is guarded on an OUTCOME rather than a log line. Inter-module access policy stays OFF by default: enforce mode's derived deny-by-default gates every ui_qml app's calls to its own backend module, because UI plugins load out-of-process and are not tracked as dependents in the core ModuleRegistry. Operators opt in per launch with --access-policy enforce or LOGOS_ACCESS_POLICY. Takes the Qt host runtime from logos-plugin-qt rather than logos-qt-sdk, which keeps only the Qt<->lp seam headers, and moves logos-protocol onto the rev that split host needs. On Windows logos_core must come LAST on the link line: GNU ld resolves an archive left to right, so the view runtime's references have to be undefined already when it reaches the import library. Separates the two source trees -- app/ is the host, src/ is the UI shell -- and brings the CI onto setup-nix-cache-action. Merges master. |
||
|
|
aa5884c673 |
feat(windows): cross-build Basecamp — plus startup and window fixes for every platform (#323)
* feat(windows): wire Basecamp for the x86_64-windows target
First slice of Stage 4. Basecamp now evaluates for the Windows
pseudo-system up to its first genuinely unported dependency
(logos-design-system); native aarch64-darwin and x86_64-linux
evaluation is unchanged.
Four blockers cleared, found by evaluating and fixing in turn:
1. flake.nix used a hardcoded `systems` list, so packages.x86_64-windows
did not exist. Now routes through logos-nix.lib.forAllTargets, which
keys the cross target as a pseudo-system — that is what lets the 34
`dep.packages.${system}.x` interpolations stay untouched. Bundlers
(nix-bundle-logos-module-install, nix-bundle-dir) are keyed by
buildSystem instead: they RUN on the builder, so taking them from the
target set would hand it a PE it cannot execute.
2. meta.platforms was platforms.unix.
3. krb5 does not cross-evaluate: it carries a host-platform bash, so the
splice fails with "Refusing to evaluate package 'bash-5.3p9'" — an
error naming bash, several levels from the cause. Guarded in both
common.buildInputs and app.nix's qtLibPath.
4. qtwebview propagates qtwebengine — a full Chromium — which fails to
cross-evaluate on cups, three levels from the cause. It is also
entirely unused: no C++ include, no `import QtWebView` in any QML,
and app/CMakeLists.txt's find_package COMPONENTS list omits WebView.
The only surviving mention is a stale line in docs/project.md.
krb5 and qtwebview are GUARDED rather than deleted, so this stays a
Windows-only change. Both look like dead weight on Unix as well, and
dropping them there would shrink every bundle — worth doing separately,
with its own testing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): drop the QML inspector on Windows
logos-qt-mcp is the QML inspector behind the UI test harness. It has no
Windows target and is not needed to run the app -- nix/app.nix already
accepts `logosQtMcp ? null` and gates the inspector on it -- so Windows
builds go without it, and the inspector-dependent outputs are simply
absent from the Windows package set.
With this, logos-basecamp EVALUATES for x86_64-windows end to end; native
aarch64-darwin and x86_64-linux are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): cross-build LogosBasecamp.exe
Basecamp now produces a real Windows executable. Five blockers, each
found by building and each of a kind already seen in this port.
1. abseil-cpp does not cross-compile (absl/base/internal/
thread_identity.cc includes <pthread.h>, absent on mingw+mcfgthread).
It is dead weight -- "absl" appears nowhere in the sources or CMake,
only in nix files and the README. Guarded here; also removed from
logos-package-manager-ui's metadata, which pulled it in separately.
2. installedModules cut to [] on Windows. The install path runs each
module through nix-bundle-logos-module-install -> nix-bundle-lgx ->
nix-bundle-dir, and nix-bundle-dir is ELF/Mach-O only. This keeps the
bundler chain, lgpm and four module repos off the critical path.
3. The hand-rolled configurePhase never passed $cmakeFlags, so
-DCMAKE_SYSTEM_NAME=Windows was dropped. The symptom was nowhere near
the cause: FindThreads probed for pthreads instead of Win32 threads and
Qt6Config reported "Qt6 could not be found because dependency Threads
could not be found".
4. Qt's host-TOOL packages were unreachable. app.nix builds its own cmake
line and never inherited common.cmakeFlags, so adding the flags there
was not enough -- they had to go on the invocation too. Symptom again
misleading: 'Failed to find required Qt component "RemoteObjects"',
when the TARGET Qt6RemoteObjects is present and it is
Qt6RemoteObjectsTools, the host package, that is missing.
5. Two unsuffixed-name defects, the class that has now appeared eleven
times. app/CMakeLists.txt copied `logos_host` without
CMAKE_EXECUTABLE_SUFFIX, and because it is a POST_BUILD step the
failure read "FAILED: LogosBasecamp.exe" with no undefined references
-- the real message was the "Error copying file" line above it. Then
the installPhase's `if [ -f build/LogosBasecamp ]` had no else-branch,
so the mingw build installed NOTHING, exited 0, and produced an output
whose bin/, lib/, modules/ and plugins/ were all empty. It now probes
both spellings and hard-fails with a directory listing.
Also: ENABLE_QML_INSPECTOR is now gated on logosQtMcp != null rather than
on enableInspector alone -- the inspector cannot be on without it -- and
Windows installs the binary directly instead of behind a /bin/sh wrapper
that could not run there.
NOT YET RUN on Windows; that needs the Qt plugin/QML staging proven in
the design-system milestone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): main_ui configures and compiles under cross
Two fixes, both of kinds already seen in this port.
The code generator must RUN on the builder, so it now comes from the
BUILD system via a new logosSdkBuild binding. This is a SPLIT, not a
swap: the same cpp-sdk output carries both the generator binary AND the
target headers/CMake package, so logosSdk stays for
-DLOGOS_CPP_SDK_ROOT. Getting it backwards succeeds natively and, under
cross, puts a PE on the builder's PATH -- the symptom was
"logos-cpp-generator: command not found".
main-ui.nix has its own hand-rolled configurePhase which, like app.nix's,
never passed $cmakeFlags -- so -DCMAKE_SYSTEM_NAME=Windows was dropped
and FindThreads probed for pthreads, surfacing three levels away as
"Qt6 could not be found because dependency Threads could not be found".
It now passes $cmakeFlags and Qt's host-TOOL package paths.
main_ui now configures and compiles. It does NOT yet link: the qt-sdk
static library is pulled in twice, giving "multiple definition of
LogosAPI::LogosAPI". That is a link-graph question, not a Windows
spelling issue, and is the next thing to solve.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(windows): name the main_ui plugin .dll, and link it
src/CMakeLists.txt set the plugin SUFFIX with `if(APPLE) ".dylib"
else() ".so"` and no Windows branch, so the cross build emitted
main_ui.so -- a genuine PE carrying a Unix extension. app/window.cpp
looks for ".dll" under Q_OS_WIN, so it would never have been found and
Basecamp would have gone on reporting "No main UI" with nothing
obviously wrong. Windows is now tested before the else-branch, and
nix/main-ui.nix accepts the .dll spelling too.
With the liblogos_core export fix, main_ui links and installs as
main_ui.dll.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: don't block startup on modules that are not loaded
PackageCoordinator guarded its startup IPC with
`if (!client || !client->isConnected()) return;`, which never fired --
see the logos-protocol fix. Past that dead guard it made ~19 blocking
calls (4 directory setters, 8 package_manager subscriptions, 1
package_downloader) against modules that were absent, each waiting 20 s
twice over. All of it runs on the GUI thread inside the Window
constructor (window.cpp invokes createWidget with Qt::DirectConnection),
and main.cpp calls show() only afterwards -- so the window simply did not
appear for ~7 minutes.
Ask the question in-process instead: logos_core_get_loaded_modules, via
the CoreModuleManager this class already holds. No IPC, no timeout. The
same guard already ships in logos-logoscore-cli's daemon, which skips the
identical setEmbeddedModulesDirectory block and reports that package
commands are unavailable. Basecamp already logged "Failed to load
package_manager module by default" roughly 40 s before the first block --
it knew, and ignored it.
The subscriptions are re-armed on CoreModuleManager::coreModulesChanged,
so a module installed later in the session still gets wired up; without
that this would trade a 7-minute stall for a silently non-functional
Modules view, which is the worse bug. Both subscribe paths are
idempotent, and the "not loaded" warning is emitted once rather than on
every stats-timer tick.
Verified on Windows: the guard now fires, the transport warns before the
doomed wait, and Basecamp's real UI renders -- sidebar, Logos mark and
Welcome page -- instead of a blank window.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: guard the remaining package_manager startup calls
fetchUiPluginMetadata() and refreshDependencyInfo() checked only
`!m_logosAPI`, so they still blocked ~20 s acquiring a token for an
absent package_manager after the subscribe paths were guarded. That was
the last blocking wait at startup, and the transport's new
"will block up to 20000 ms" warning is what pointed at it.
fetchUiPluginMetadata reuses its existing metadata-unavailable branch
rather than inventing a new one -- it clears m_appsLoading and emits
uiModulesChanged, so the UI settles instead of sitting in a loading state
for the timeout. refreshRepositories needed no change: it guards on
isConnected(), which now tells the truth.
Measured on Windows with no modules installed: "will block up to" 0,
"Timeout waiting for replica" 0, "Requesting object" 0. The UI renders
identically -- sidebar, Logos mark, Welcome page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(windows): resolve UI plugins' private DLLs from their own directory
The logos-module chokepoint fix covers LogosModule::loadFromPath, which
is every process-isolated module. Basecamp constructs its own
QPluginLoaders and was not covered: PluginLoader's background pre-load
and finishCppPluginLoad for UI plugins, and window.cpp for main_ui.
Each lives in its own directory (plugins/<name>/), so anything vendored
beside it is invisible to Windows' loader, which searches the
EXECUTABLE's directory rather than the importing DLL's. This works today
only because every DLL happens to be staged next to the exe; a plugin
with a private dependency would fail with "The specified module could not
be found", naming the plugin rather than the dependency.
The references are deliberately not released: these plugins stay resident
for the process lifetime (QPluginLoader's destructor does not unload).
No-op off Windows, so no platform guards at the call sites.
Cross-builds and native build both green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(windows): key the install bundlers by target
nix-bundle-logos-module-install now does its own host/target split
internally, so keying the whole bundler by buildSystem is no longer
right -- that is what made it derive the .lgx variant name and library
extension from the build platform.
installedModules stays [] on Windows for now: with the labelling fixed,
lgpm correctly refuses to install a windows-x86_64 package on a Linux
builder, and cross-installation needs a platform override that lgpm does
not have yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): ship the pre-installed modules
installedModules is no longer cut on Windows. The cross-install path now
works end to end: capability_module, package_manager and
package_downloader are laid out under modules/, main_ui and
package_manager_ui under plugins/, each a real PE with its own DLL
closure and a variant file reading windows-x86_64-dev.
It took a host/target split at every layer, and each failed somewhere
unrelated to itself: the .lgx bundler keyed by target (it decides the
variant name and library extension), lgpm from the build system (it runs
there), a --platform override for cross-installation, and a Nix-double
to lgpm-variant translation.
Verified on real Windows: capability_module and package_manager load,
spawn their hosts, and answer IPC over named pipes -- the log shows
ModuleProxy rejecting unauthorized calls, which is the token flow
talking, not a Windows failure.
KNOWN GAP, and it fails loudly: package_downloader does not load --
"Cannot load library ... package_downloader_plugin.dll: The specified
module could not be found". Its external library
libpackage_downloader_lib.dll needs libcurl-4.dll, which is in neither
the module directory nor bin/. LogosModule.cmake copies an external
library's DLL but not that DLL's own dependencies, so the closure must be
walked to a fixpoint there too -- the same lesson as the Qt plugin and
bundle closures. Strictly better than shipping no modules at all, and the
failure names the file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): import the shared runtime instead of linking it
LogosBasecamp.exe and main_ui.dll now compile with LOGOS_SHARED_USE_DLL
and link an emptied logos-qt-sdk archive, so TokenManager, LogosAPI and
LogosAPIClient come from liblogos_core.dll. Before this each image linked
its own copy and therefore its own function-local statics: the host saved
a capability token into its TokenManager, main_ui read its own empty one,
and every cross-module call was refused.
Measured on real Windows across three runs: "rejecting unauthorized call"
29 -> 0, and "No token found" 29 -> 0 replaced by nine "Found token for
module". All modules still load; no missing-symbol or duplicate-symbol
diagnostics.
NOT fixed by this, and not caused by it: the package_manager_ui icon
still does not appear in the sidebar. The pre-change run had the same
zero ui-host spawns. Sidebar entries come from
PackageCoordinator::getInstalledUiPluginsAsync, which reads
package_manager's installed-package registry -- empty in this payload, so
the list is empty regardless of what is on disk in plugins/. That is a
separate unmet precondition.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: never open a window larger than the screen
setupUi asked for a fixed 1600x900 and nothing anywhere in this repo consulted
the screen -- the <QScreen> include at the top of window.cpp had been unused.
On a display smaller than that the window opens with its right and bottom edges
off-screen, and on Windows it cannot be dragged back into view, so whatever
hangs off is permanently unreachable: in practice the sidebar's bottom-anchored
system buttons and the version label.
Two halves, because one is not enough:
* setupUi clamps the requested size to availableGeometry, so an oversized
window is never mapped in the first place.
* showEvent re-checks once. resize() sets the CLIENT size while
availableGeometry() bounds the FRAME, and the decoration margins are not
knowable until the platform window exists -- measured, the clamped client
filled the work area exactly and the frame still hung 72px below it.
Both are skipped under the offscreen platform (QOffscreenScreen hardcodes its
geometry) so headless UI doctests keep their full-size window and qt-mcp's
scene-position clicks still land.
Three things that look like they could be simpler and cannot, each measured:
* The showEvent check compares SIZES, not rectangles. QRect::contains() is the
obvious formulation and misfires on both platforms: on Windows
frameGeometry() comes from GetWindowRect, which includes DWM's invisible
resize border (~13px/side at 192dpi), so a correctly placed window never
reports as contained and this would run on every launch; on macOS Qt reports
a frame whose title bar sits above availableGeometry's origin, and acting on
that moved the window 66px down at launch on a platform where nothing is
broken.
* The shrink is bounded by the current size. Without boundedTo, a window that
is merely too TALL is also stretched to the full available WIDTH -- observed
on this path: 1600 logical wide silently became 1715.
* The clamp is to availableGeometry exactly, not to a fraction of it. Anything
less is not a no-op on displays that fit the design size, and would undo the
widening documented at the resize() call (1600 was chosen so the Package
Manager's Action and Description columns are not clipped).
Measured on Windows (real hardware, DPI-aware capture, visible frame via
DWMWA_EXTENDED_FRAME_BOUNDS against a 3456x1826 work area):
normal session bottom overflow 45px -> 2px (rounding), width still 1600
small desktop ~550px of width off-screen -> right 14px, bottom 2px
below app minimum bottom 126px -> 33px (Basecamp's own 800x600 floor)
Verified a no-op elsewhere by running the identical logic against Qt 6.11.1 on
macOS: constructor clamp no-op, showEvent reports FITS, size and position
unchanged; and under QT_QPA_PLATFORM=offscreen both paths are skipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: re-fit the window when the screen shrinks under it
The launch clamp (76e0f6d) only runs once. An RDP session with
/dynamic-resolution, or a taskbar appearing, shrinks the desktop under a running
window and nothing reacted -- the window was left overflowing, with the
sidebar's bottom-anchored system buttons under the taskbar and unreachable.
Watches availableGeometryChanged on the screen the window is on, coalesced
through a 150ms settle timer, and re-fits. Measured on real Windows, same
binary pair and run conditions, work area shrinking 1922 -> 1826 physical px:
shipped overflow (3,3) -> (4,111) window did NOT shrink NO-REFIT
re-fit overflow (3,3) -> (3,2) window shrank REFIT-WORKS
An 8-agent design pass was REFUTED 3/3 by its own reviewers and this is the
corrected version, not that design. Three of its defects were real:
* THE RATCHET. It fitted to min(previous, available) on every event -- a
monotone non-increasing map, so the window converges on the smallest work area
seen all session and never grows back. A taskbar that auto-hides and
reappears, or an RDP window dragged smaller and back, would have shrunk
Basecamp permanently. Fixed by bounding against m_desiredSize: the launch
design size, replaced by any resize the USER performs, so the window grows
back but never past what was asked for.
* NO isVisible() GATE. closeEvent hides to the tray on EVERY platform and hide()
does not set Qt::WindowMinimized, so a window-state gate does not cover it.
The fit would have run and latched on a hidden window whose frame geometry is
meaningless.
* A QRect LATCH that could not distinguish "the screen shrank under the window"
from "the window moved to another monitor". Dropped entirely: the
`target == size()` early return is both the idempotence and the
non-recursion, so there is no latch to fall out of sync -- and no need for the
design's re-entrancy flag, which a reviewer showed could never be true on
entry.
Three things kept from that design because they beat the obvious choice:
screenChanged re-points the watch but never fits (Qt migrates windows onto a
1024x768 lock screen on RDP disconnect, and fitting there would shrink with no
way back); the settle timer, because the fit shrinks and chasing a drag's
intermediates would latch its smallest frame; and connections held by handle
with a QPointer<QScreen>, because a session lock adds and then DELETES a screen.
Every guard lives inside fitFrameToAvailableGeometry() rather than in the
callers, so all three entry points are covered by construction -- a reviewer
caught that the design left the scheduler unguarded while changeEvent called it
on every state change.
Two bugs found in this implementation while writing it: QPointer<QScreen> needs
QScreen COMPLETE (QPointer static_asserts QObject derivation), caught by the
cross build; and resizeEvent recorded the MAXIMIZED size as the user's intent,
so a later un-maximize would try to grow the window to full-screen size. Also
replaced `if (!m_screenChangedConnection)` with an explicit QPointer<QWindow>
comparison: Qt documents Connection::operator bool only as "the connect() call
succeeded" and says nothing about sender lifetime, so a stale-but-truthy
connection would have silently stopped re-pointing the watch.
Verified a no-op elsewhere by running the shipped function body against Qt
6.11.1 on macOS: constructor clamp no-op, fit reports FITS, size and position
unchanged; and under QT_QPA_PLATFORM=offscreen both paths are skipped, so
headless UI doctests keep their full-size window.
NOT verified: whether an RDP resolution change arrives as
availableGeometryChanged on the same screen rather than a screen remove/add,
which is deliberately not fitted on. The work-area path is proven; that one is
inferred.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(windows): ship the portable Basecamp with its modules pre-installed
The distributed build cut installedModules to [] on Windows, and skipped
nix-bundle-dir was never the reason -- the comment claimed bundle.sh
would emit an empty payload, which is true, but the conclusion should
have been "don't run bundle.sh on Windows", not "ship no modules".
A PE needs no relocation: its import table carries DLL base names only
and Windows searches the executable's own directory first, so the build
output is already position-independent, and win-dll-link.sh has staged
the closure into bin/. nix-bundle-lgx reached the same conclusion for
module payloads in d539a3f; this applies it to the app bundle.
Without this there is no portable Windows Basecamp with a working
package manager, and therefore no way to install anything from a
catalog: platformVariantsToTry() appends "-dev" to every variant unless
LGPM_PORTABLE_BUILD is set, so the dev build asks for
`windows-x86_64-dev` while a published package is `windows-x86_64` and
every catalog row reports Not Available.
Native builds are unchanged by construction -- bundleFor is dirBundler
off Windows.
* fix(windows): app.nix copied no shared libraries at all
The liblogos shared-library loop globbed *.dylib and *.so only. On Windows
it matched nothing, and because each candidate is guarded by `[ -f "$f" ]`
with a trailing `|| true`, it copied zero files and exited 0.
Thirteen DLLs sit in that same lib/ -- liblogos_core, libpackage_manager_lib,
liblgx, icuuc76, icudt76, libsodium-26 and the mingw runtime -- and
LogosBasecamp.exe imports liblogos_core.dll DIRECTLY. The result is
0xC0000135 (STATUS_DLL_NOT_FOUND) before main(): no Qt error, no stderr, no
output whatsoever. It has only ever run on Windows because those DLLs were
hand-staged into the payload.
Adds *.dll to the glob, sends DLLs to bin/ rather than lib/ (Windows searches
the executable's own directory, has no rpath, and win-dll-link.sh only
processes $out/bin), and makes copying zero libraries a hard error -- this
loop exiting 0 having done nothing is the whole defect.
Also corrects the comment on bundleFor. It claimed skipping nix-bundle-dir on
Windows was right because a PE needs no relocation. That conflates the
bundler's two jobs: relocation (genuinely unnecessary on PE) and Qt plugin /
QML / qt.conf staging (required on every platform, since those DLLs are
LoadLibrary'd and appear in no import table). Skipping it yields a bundle with
no qt.conf and no QPA plugin. The comment now says so and names the real fix.
* fix(windows): stage liblogos' own dependency DLLs, and prove the closure
|
||
|
|
25300f0e90 | fix: fix the show/hide behavior for basecamp after its minimized | ||
|
|
3a73d33824 | chore: revert x on linux closes app | ||
|
|
f8dddc3456 | chore: remove check logs in smoke test | ||
|
|
aa6bd126b9 | feat: fix Cmd+Q on macos and Linux behavior expected as well | ||
|
|
c2702402cf | fix: bring back tooltip on side bar | ||
|
|
2a2aec2478 |
fix: widen default launch window so Package Manager columns are visible
The default 1024x768 launch size left the content area at ~912px, but the Package Manager view needs ~1300px (category sidebar 200 + table min 984 + margins/spacing) to show the table's Action and Description columns with the details panel closed (the default no-selection view). At 1024 those rightmost columns were clipped off the right edge. Bump the default to 1600x900 (~1504px content, ~200px of slack), which shows the full table comfortably. The window minimum stays 800x600 (MainContainer) so it can still be resized down; there is no geometry persistence, so the new default applies on every launch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
312a1dfb28 | replace all Logos App references | ||
|
|
113b67c733 | leverage package-manager-module for module/ui-plugin detection (#110) | ||
|
|
17ef99cb28 | chore: rename repo to logos-basecamp | ||
|
|
ccb4cdba1a |
properly handle portable modules (#71)
* properly handle portable modules * preinstall modules on startup instead of bundling them at build time * get icons from manifest * consistent user dir * revert to main branch of dependencies * add release derivations * add appimage release job * fix app icon on Linux |
||
|
|
d4281e96be | chore: review fixes | ||
|
|
2f199aa04d | feat: Making macos traffic buttons to be overlayed on top of app and alligning app for this to look okay | ||
|
|
d893b0b69e | support installing plugins inside folders | ||
|
|
813ad1269b | extract package manager ui to its own plugin | ||
|
|
827dc485d2 | support systray | ||
|
|
ebf9cf7cfe |
add nix build
add nix build chore: update cmakelists (wip) chore: update cmakelists (wip) working nix config fix issues building app fix path issue working app fix issue with paths |
||
|
|
58c4b16c5a | chore: move logos_app to its own repo |