fix: Bundle resources in package to fix missing system tray icons (fixes #349) (#354)

* fix: bundle resources in package to fix missing icons in system tray (fixes #349)

The resources directory (icons and sounds) was not included in pip-installed
packages because it lived outside the src/ package directory. This caused
the resource_manager to find an empty icon directory at runtime, resulting in
the ellipsis (three dots) icon in the GNOME system tray.

Changes:
- Copy resources into src/vocalinux/resources/ so setuptools bundles them
- Add 'vocalinux.resources/**/*' to package-data in pyproject.toml
- Add MANIFEST.in for sdist builds
- Update resource_manager to check package-bundled resources first
  (module_dir.parent / 'resources') before checking external paths
- Add install_resources_to_venv() to install.sh for curl-based installs,
  copying resources to /share/vocalinux/resources

This fixes both pip installs (resources bundled in the wheel) and curl-based
installs (resources copied to venv share directory).

* fix: ensure bundled resources are included in sdist and pip installs

- Add 'vocalinux.resources' to setuptools packages list so the
  subpackage (and its __init__.py) is recognized by setuptools
- Add __init__.py to src/vocalinux/resources/ to make it a proper
  Python subpackage for reliable discovery
- Add 'recursive-include src/vocalinux/resources *' to MANIFEST.in
  so sdist archives include the bundled icons and sounds
This commit is contained in:
Jatin K Malik
2026-03-27 11:07:19 -07:00
committed by GitHub
parent d74d1da8fc
commit 860a9f9ae6
12 changed files with 5963 additions and 2 deletions
+4
View File
@@ -0,0 +1,4 @@
include vocalinux.desktop
include resources/icons/scalable/*.svg
include resources/sounds/*.wav
recursive-include src/vocalinux/resources *
+46
View File
@@ -2548,12 +2548,58 @@ update_icon_cache() {
fi
}
# Function to install resources (icons, sounds) to the virtual environment
# so the resource_manager can find them at runtime
install_resources_to_venv() {
print_info "Installing resources to virtual environment..."
# Target directory: $VENV_DIR/share/vocalinux/resources
local VENV_RESOURCES_DIR="$VENV_DIR/share/vocalinux/resources"
# Create directories
mkdir -p "$VENV_RESOURCES_DIR/icons/scalable" || {
print_warning "Failed to create venv resources directory"
return 1
}
mkdir -p "$VENV_RESOURCES_DIR/sounds" || {
print_warning "Failed to create venv sounds directory"
return 1
}
# Copy icons if available
if [ -d "resources/icons/scalable" ]; then
cp resources/icons/scalable/*.svg "$VENV_RESOURCES_DIR/icons/scalable/" 2>/dev/null || {
print_warning "Failed to copy icons to venv resources"
}
fi
# Copy sounds if available
if [ -d "resources/sounds" ]; then
cp resources/sounds/*.wav "$VENV_RESOURCES_DIR/sounds/" 2>/dev/null || {
print_warning "Failed to copy sounds to venv resources"
}
fi
# Verify
local ICON_COUNT=$(ls "$VENV_RESOURCES_DIR/icons/scalable/"*.svg 2>/dev/null | wc -l)
local SOUND_COUNT=$(ls "$VENV_RESOURCES_DIR/sounds/"*.wav 2>/dev/null | wc -l)
if [ "$ICON_COUNT" -gt 0 ] && [ "$SOUND_COUNT" -gt 0 ]; then
print_success "Installed resources to venv ($ICON_COUNT icons, $SOUND_COUNT sounds)"
else
print_warning "Some resources may be missing from venv ($ICON_COUNT icons, $SOUND_COUNT sounds)"
fi
}
# Install desktop entry
install_desktop_entry || print_warning "Desktop entry installation failed"
# Install icons
install_icons || print_warning "Icon installation failed"
# Install resources to venv for runtime discovery
install_resources_to_venv || print_warning "Venv resource installation failed"
# Install models based on selected engine
# whisper.cpp is now the default engine
if [ "$SKIP_MODELS" = "no" ]; then
+2 -1
View File
@@ -87,7 +87,7 @@ Issues = "https://github.com/jatinkrmalik/vocalinux/issues"
Changelog = "https://github.com/jatinkrmalik/vocalinux/releases"
[tool.setuptools]
packages = ["vocalinux", "vocalinux.speech_recognition", "vocalinux.text_injection", "vocalinux.ui", "vocalinux.ui.keyboard_backends", "vocalinux.utils"]
packages = ["vocalinux", "vocalinux.resources", "vocalinux.speech_recognition", "vocalinux.text_injection", "vocalinux.ui", "vocalinux.ui.keyboard_backends", "vocalinux.utils"]
package-dir = {"" = "src"}
[tool.setuptools.dynamic]
@@ -95,6 +95,7 @@ version = {attr = "vocalinux.version.__version__"}
[tool.setuptools.package-data]
"*" = ["*.svg", "*.wav"]
"vocalinux" = ["resources/**/*"]
[tool.black]
line-length = 100
+1
View File
@@ -0,0 +1 @@
"""Bundled resources (icons, sounds) for Vocalinux."""
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<!-- Placeholder for microphone off icon -->
<circle cx="64" cy="64" r="60" fill="#e74c3c" />
<rect x="44" y="40" width="40" height="60" rx="20" fill="#7f8c8d" />
<line x1="40" y1="88" x2="88" y2="40" stroke="#e74c3c" stroke-width="8" />
<!-- This is a placeholder. Replace with actual custom design. -->
</svg>

After

Width:  |  Height:  |  Size: 465 B

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<!-- Placeholder for microphone processing icon -->
<circle cx="64" cy="64" r="60" fill="#f39c12" />
<rect x="44" y="40" width="40" height="60" rx="20" fill="#2c3e50" />
<circle cx="64" cy="40" r="8" fill="#f39c12">
<animate attributeName="cy" values="40;50;40" dur="1s" repeatCount="indefinite" />
</circle>
<circle cx="48" cy="60" r="8" fill="#f39c12">
<animate attributeName="cy" values="60;70;60" dur="1s" repeatCount="indefinite" />
</circle>
<circle cx="80" cy="60" r="8" fill="#f39c12">
<animate attributeName="cy" values="60;70;60" dur="1s" repeatCount="indefinite" />
</circle>
<!-- This is a placeholder. Replace with actual custom design. -->
</svg>

After

Width:  |  Height:  |  Size: 836 B

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<!-- Placeholder for microphone on/active icon -->
<circle cx="64" cy="64" r="60" fill="#2ecc71" />
<rect x="44" y="40" width="40" height="60" rx="20" fill="#2c3e50" />
<path d="M 40,78 Q 64,88 88,78" stroke="#2ecc71" stroke-width="4" fill="none" />
<path d="M 40,88 Q 64,98 88,88" stroke="#2ecc71" stroke-width="4" fill="none" />
<!-- This is a placeholder. Replace with actual custom design. -->
</svg>

After

Width:  |  Height:  |  Size: 560 B

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+4 -1
View File
@@ -49,9 +49,12 @@ class ResourceManager:
# Build list of candidate paths in priority order
candidates = [
# Resources bundled inside the installed package (pip install)
# This resolves to src/vocalinux/resources when installed
module_dir.parent / "resources",
# For direct repository execution (go up from src/vocalinux/utils to root)
module_dir.parent.parent.parent / "resources",
# For installed package or virtual environment
# For installed package or virtual environment (install.sh copies here)
Path(sys.prefix) / "share" / "vocalinux" / "resources",
# For development in virtual environment
Path(sys.prefix).parent / "resources",