Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ document/api/
third_party/*/
!third_party/aex/
!third_party/QuarkWidgets/
!third_party/apps/
# third_party/apps/ is a local parking spot for cloned app source trees
# (CFDeskit, future pdfReader/MediaPlayer/...). Only the README is tracked;
# each developer clones their own app repos, content stays untracked.
third_party/apps/*
!third_party/apps/README.md
!third_party/.gitkeep

__pycache__/
Expand Down
35 changes: 0 additions & 35 deletions apps/README.md

This file was deleted.

6 changes: 6 additions & 0 deletions desktop/base/path/src/desktop_main_path_resolvers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ bool DesktopMainPathProvider::request_created(const PathType p) {
}

QString DesktopMainPathProvider::absolutePath(const PathType p) {
// Apps is the runtime deployment target for standalone apps — lowercase to
// match the unix-style "apps" directory convention. Other PathTypes use
// their X-macro stringified name (Home, Desktop, Documents, ...).
if (p == PathType::Apps) {
return make(root, "apps");
}
return make(root, DesktopMainPathProvider::kPathNames[static_cast<size_t>(p)]);
}

Expand Down
1 change: 1 addition & 0 deletions desktop/ui/components/launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ PRIVATE
QuarkWidgets::quarkwidgets # ThemeManager + Material tokens for the popup/tiles
cfbase # aex::expected / WeakPtrFactory (propagated via cfbase -> aex::aex)
cflogger # Diagnostic logging for launch success/failure
cfpath # DesktopMainPathProvider: third_party/apps discovery path
)
20 changes: 15 additions & 5 deletions desktop/ui/components/launcher/app_discoverer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#include "app_discoverer.h"

#include "cflog.h"
#include "cfpath/desktop_main_path_resolvers.h"

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
Expand All @@ -30,18 +30,24 @@ constexpr const char* kManifestName = "app.json";
} // namespace

QList<AppEntry> AppDiscoverer::discover() {
const QString apps_dir = QCoreApplication::applicationDirPath() + QStringLiteral("/../apps");
// Apps deployment target: <active_root>/apps/<id>/{exe, app.json}. This is
// where installed/built apps land (e.g. via CFDeskit's cmake --install).
const QString apps_dir = cf::desktop::path::DesktopMainPathProvider::instance().absolutePath(
cf::desktop::path::DesktopMainPathProvider::PathType::Apps);
return discoverFrom(apps_dir);
}

QList<AppEntry> AppDiscoverer::discoverFrom(const QString& apps_dir) {
QList<AppEntry> result;
QDir dir(apps_dir);
if (!dir.exists()) {
if (!QDir(apps_dir).exists()) {
// Apps are optional — a missing apps directory is normal (nothing
// deployed yet). Log INFO, not a warning, and return empty.
log::infoftag(kLogTag, "Apps directory '{}' not found; no apps to discover",
apps_dir.toStdString());
return result;
}

const QFileInfoList subdirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
const QFileInfoList subdirs = QDir(apps_dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const auto& sub : subdirs) {
const QString app_dir = sub.absoluteFilePath();
const QString manifest_path =
Expand Down Expand Up @@ -85,6 +91,10 @@ QList<AppEntry> AppDiscoverer::discoverFrom(const QString& apps_dir) {

result.append(entry);
}

if (result.isEmpty()) {
log::infoftag(kLogTag, "No apps discovered under '{}'", apps_dir.toStdString());
}
return result;
}

Expand Down
10 changes: 4 additions & 6 deletions desktop/ui/components/launcher/app_discoverer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ namespace cf::desktop::desktop_component {
* @brief Discovers standalone apps from per-app @c app.json manifests.
*
* The discovery contract:
* - @c <apps_dir>/<id>/app.json is the manifest (JSON object).
* - Scans @c <active_root>/apps/<id>/app.json (the runtime deployment target
* — where built apps are installed, e.g. via CFDeskit's @c cmake --install).
* - Fields: @c app_id, @c display_name, @c icon (relative to manifest),
* @c exec (relative to manifest).
* - @c icon_path / @c exec_command are resolved to absolute paths
* (@c <app_dir>/<icon|exec>).
* - Subdirs without @c app.json are skipped silently; manifests missing
* @c app_id or @c exec are skipped with a warning (no silent fallback).
* - Empty/missing apps directory → INFO log, empty result (apps are optional).
*
* @ingroup components
*/
Expand All @@ -42,13 +44,11 @@ class AppDiscoverer {
AppDiscoverer() = delete;

/**
* @brief Discovers apps under @c <bin>/../apps/<id>/app.json.
* @brief Discovers apps under @c <active_root>/apps/<id>/app.json.
*
* @return Parsed AppEntry list (icon/exec resolved to absolute paths);
* empty if the apps directory is absent or has no manifests.
*
* @throws None.
*
* @since 0.20
* @ingroup components
*/
Expand All @@ -58,9 +58,7 @@ class AppDiscoverer {
* @brief Discovers apps under @p apps_dir.
*
* @param[in] apps_dir Directory containing <id>/ subdirs with app.json.
*
* @return Parsed AppEntry list.
*
* @throws None.
* @note Used by discover(); exposed for unit tests.
* @since 0.20
Expand Down
41 changes: 41 additions & 0 deletions third_party/apps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# third_party/apps/ — local app source parking (untracked)

This directory is a **local parking spot for app source trees**. Clone any
standalone app repo here and build it; then deploy (install/copy) the built
apps to the **runtime apps directory** (`<active_root>/apps/`, e.g.
`~/desktop/apps/`) where `AppDiscoverer` scans at startup.

**Not a submodule, not tracked** (see `.gitignore`) — every developer clones
their own. The main repo stays free of app sources.

## Workflow

```bash
# 1. clone an app repo here (source parking)
git clone https://github.com/Awesome-Embedded-Learning-Studio/CFDeskit.git \
third_party/apps/CFDeskit

# 2. build it
cmake -S third_party/apps/CFDeskit -B third_party/apps/CFDeskit/build
cmake --build third_party/apps/CFDeskit/build -j

# 3. deploy to the runtime apps dir (<active_root>/apps/)
cmake --install third_party/apps/CFDeskit/build --prefix "$HOME/desktop"
# or, for a quick copy:
cp -r third_party/apps/CFDeskit/build/apps/. "$HOME/desktop/apps/"
```

The desktop discovers apps under `<active_root>/apps/<id>/app.json` — that's
where built executables + their manifests must land. This `third_party/apps/`
directory is **only source parking**; the desktop does NOT scan here.

## One rule, all apps

Same flow for any app repo: CFDeskit today; `pdfReader` / `MediaPlayer` /
embedded tools in the future. Clone here, build, deploy to `~/desktop/apps/`.
No per-app wiring in the main repo.

## If `~/desktop/apps/` is empty

The desktop logs `INFO: No apps discovered under '.../apps'` and continues —
**no error, no crash**. Deploy an app whenever you need it.
Loading