5 Commits

Author SHA1 Message Date
Radu Macocian b480cfec3f Updated checksums for v0.0.4
Tag and publish to AUR / tag (push) Successful in 25s
Tag and publish to AUR / publish (push) Has been skipped
2026-07-15 15:27:36 +02:00
Radu Macocian 58823cb24a Moved to module structure to work in embeded qs processes
Tag and publish to AUR / tag (push) Successful in 1m20s
Tag and publish to AUR / publish (push) Has been skipped
2026-07-15 15:25:33 +02:00
amacocian c63d1dc6ce Theme quick reload (#1)
Tag and publish to AUR / tag (push) Successful in 14s
Tag and publish to AUR / publish (push) Successful in 48s
Co-authored-by: Alexandru Macocian <amacocian@yahoo.com>
Reviewed-on: #1
2026-06-09 13:00:54 +00:00
Radu Macocian c2112c68c0 Added theme engine support and aur publish pipeline
Tag and publish to AUR / tag (push) Successful in 18s
Tag and publish to AUR / publish (push) Successful in 52s
2026-06-09 13:51:45 +02:00
Radu Macocian 170a320564 Version 0.1 2026-06-04 15:31:17 +02:00
14 changed files with 314 additions and 71 deletions
+122
View File
@@ -0,0 +1,122 @@
name: Tag and publish to AUR
on:
push:
branches: [master]
jobs:
tag:
runs-on: ubuntu-latest
container:
image: archlinux:latest
defaults:
run:
shell: bash
outputs:
created: ${{ steps.tag.outputs.created }}
pkgver: ${{ steps.tag.outputs.pkgver }}
steps:
- name: Install dependencies
run: pacman -Syu --noconfirm --needed git
- name: Checkout source
run: |
git clone --branch ${{ gitea.ref_name }} \
http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git .
- name: Tag if pkgver bumped
id: tag
run: |
set -euo pipefail
PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD)
TAG="v${PKGVER}"
git config --global --add safe.directory "$(pwd)"
git fetch --tags origin
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "Tag ${TAG} already exists, skipping release."
echo "created=0" >> "$GITHUB_OUTPUT"
exit 0
fi
git config user.name "${{ vars.AUR_GIT_NAME || 'Radu Macocian' }}"
git config user.email "${{ vars.AUR_GIT_EMAIL || 'radu@macocian.com' }}"
git tag -a "${TAG}" -m "Release ${TAG}"
git push \
http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git \
"${TAG}"
echo "created=1" >> "$GITHUB_OUTPUT"
echo "pkgver=${PKGVER}" >> "$GITHUB_OUTPUT"
publish:
needs: tag
if: needs.tag.outputs.created == '1'
runs-on: ubuntu-latest
container:
image: archlinux:latest
defaults:
run:
shell: bash
steps:
- name: Install dependencies
run: |
pacman -Syu --noconfirm --needed git openssh pacman-contrib base-devel sudo curl coreutils
useradd -m builder
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
- name: Checkout source at tag
run: |
git clone --depth 1 --branch v${{ needs.tag.outputs.pkgver }} \
http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git .
- name: Recompute sha256sums for tagged archive
run: |
set -euo pipefail
PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD)
URL=$(awk -F\" '/^url=/{print $2}' PKGBUILD)
SRC_URL="${URL}/archive/v${PKGVER}.tar.gz"
echo "Fetching ${SRC_URL}"
curl -fsSL "${SRC_URL}" -o /tmp/src.tar.gz
NEW_SHA=$(sha256sum /tmp/src.tar.gz | awk '{print $1}')
sed -i "s/^sha256sums=.*/sha256sums=('${NEW_SHA}')/" PKGBUILD
- name: Configure SSH for AUR
env:
AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
run: |
install -dm700 ~/.ssh
printf '%s\n' "$AUR_SSH_KEY" > ~/.ssh/aur
chmod 600 ~/.ssh/aur
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
cat > ~/.ssh/config <<EOF
Host aur.archlinux.org
User aur
IdentityFile ~/.ssh/aur
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config
- name: Publish to AUR
run: |
set -euo pipefail
SRC=$(pwd)
rm -rf /tmp/aur
git clone ssh://aur@aur.archlinux.org/omni-launcher.git /tmp/aur
if [ ! -d /tmp/aur/.git ]; then
git -C /tmp/aur init
git -C /tmp/aur remote add origin ssh://aur@aur.archlinux.org/omni-launcher.git
fi
git config --global --add safe.directory /tmp/aur
cp "$SRC/PKGBUILD" /tmp/aur/PKGBUILD
chown -R builder:builder /tmp/aur
sudo -u builder bash -c 'cd /tmp/aur && makepkg --printsrcinfo > .SRCINFO'
cd /tmp/aur
git config user.name "${{ vars.AUR_GIT_NAME || 'Radu Macocian' }}"
git config user.email "${{ vars.AUR_GIT_EMAIL || 'radu@macocian.com' }}"
git add PKGBUILD .SRCINFO
if git diff --cached --quiet; then
echo "No changes to publish."
exit 0
fi
PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD)
PKGREL=$(awk -F= '/^pkgrel=/{print $2}' PKGBUILD)
git commit -m "Update to ${PKGVER}-${PKGREL}"
git push origin master
+1
View File
@@ -2,3 +2,4 @@
*.tar.zst *.tar.zst
pkg/ pkg/
src/ src/
.SRCINFO
+17 -11
View File
@@ -1,25 +1,31 @@
# Maintainer: Radu Macocian <radu@macocian.com> # Maintainer: Radu Macocian <radu@macocian.com>
pkgname=omni-launcher pkgname=omni-launcher
pkgver=0.0.1 pkgver=0.0.4
pkgrel=1 pkgrel=1
pkgdesc="Application launcher overlay built on Quickshell, with calculator, unit/currency conversion, unicode search and Giphy search" pkgdesc="Application launcher overlay built on Quickshell, with calculator, unit/currency conversion, unicode search and Giphy search. Installable as a Quickshell QML module (OmniLauncher) for embedded use or standalone via omni-launcher."
arch=('any') arch=('any')
url="https://git.estatecloud.org/radumaco/omni-launcher" url="https://git.estatecloud.org/radumaco/omni-launcher"
license=('GPL-3.0-or-later') license=('GPL-3.0-or-later')
depends=('quickshell' 'wl-clipboard' 'curl' 'python' 'glib2') depends=('quickshell' 'qt6-declarative' 'wl-clipboard' 'curl' 'python' 'glib2' 'inotify-tools')
optdepends=('hyprland: close-on-workspace-change and focus-grab integration') optdepends=('hyprland: close-on-workspace-change and focus-grab integration')
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz") source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
sha256sums=('SKIP') sha256sums=('9c87f6afa1a1f242709df435931d1cde61fcb22def6f0f59899fd7333c376ee0')
package() { package() {
cd "$srcdir/$pkgname-$pkgver" cd "$srcdir/$pkgname"
install -dm755 "$pkgdir/usr/share/$pkgname" # QML module — installed on the Qt6 import path so both the standalone
install -m644 qml/* "$pkgdir/usr/share/$pkgname/" # shell.qml and any host quickshell config can `import OmniLauncher`.
install -dm755 "$pkgdir/usr/lib/qt6/qml/OmniLauncher"
install -m644 module/* "$pkgdir/usr/lib/qt6/qml/OmniLauncher/"
install -Dm755 bin/omni-launcher "$pkgdir/usr/bin/omni-launcher" # Standalone entry point + launcher scripts.
install -Dm755 bin/omni-launcher-toggle "$pkgdir/usr/bin/omni-launcher-toggle" install -dm755 "$pkgdir/usr/share/$pkgname"
install -m644 shell.qml "$pkgdir/usr/share/$pkgname/"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" install -Dm755 bin/omni-launcher "$pkgdir/usr/bin/omni-launcher"
install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md" install -Dm755 bin/omni-launcher-toggle "$pkgdir/usr/bin/omni-launcher-toggle"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
} }
+51 -3
View File
@@ -28,6 +28,10 @@ makepkg -si
## Usage ## Usage
omni-launcher can run in two modes: **standalone** (its own quickshell process) or **embedded** (imported as a QML module inside an existing quickshell config, saving a process).
### Standalone mode
Start the daemon once per session (e.g. in `~/.config/hypr/hyprland.conf`): Start the daemon once per session (e.g. in `~/.config/hypr/hyprland.conf`):
``` ```
@@ -42,9 +46,41 @@ bind = SUPER, SPACE, exec, omni-launcher-toggle
`omni-launcher-toggle` calls the running instance over Quickshell IPC. The launcher closes on `Esc`, click-outside, or workspace switch (Hyprland). `omni-launcher-toggle` calls the running instance over Quickshell IPC. The launcher closes on `Esc`, click-outside, or workspace switch (Hyprland).
### Embedded mode
Instead of running a separate quickshell process, you can import `OmniLauncher` directly inside your existing quickshell config. The module ships its own `Theme`, `Config`, and `LauncherService` singletons (module-scoped — they won't collide with your config's own singletons).
1. Install `omni-launcher` from the AUR (this places the module on the Qt6 import path at `/usr/lib/qt6/qml/OmniLauncher/`).
2. In your `shell.qml`, import the module and instantiate `Launcher {}`:
```qml
import Quickshell
import Quickshell.Io
import OmniLauncher
ShellRoot {
IpcHandler {
target: "launcher"
function toggle(): void { LauncherService.toggle(); }
function open(): void { LauncherService.open(); }
function close(): void { LauncherService.close(); }
}
Launcher {}
}
```
3. Bind a key to toggle it via your host config's IPC socket:
```
bind = SUPER, SPACE, exec, quickshell ipc call launcher toggle
```
Do **not** run `omni-launcher` (the daemon) in embedded mode — the host quickshell process already owns the launcher.
## Configuration ## Configuration
`~/.config/omni-launcher/config.json` — any missing key falls back to a built-in default: `~/.config/omni-launcher/config.json` — any missing key falls back to a built-in default, so the file can be omitted entirely:
```json ```json
{ {
@@ -52,7 +88,19 @@ bind = SUPER, SPACE, exec, omni-launcher-toggle
"fontSize": 16, "fontSize": 16,
"giphyApiKey": "", "giphyApiKey": "",
"panelWidth": 720, "panelWidth": 720,
"panelHeight": 520 "panelHeight": 520,
"padding": 5,
"spacing": 5,
"radius": 10,
"colors": {
"background": "#101010",
"foreground": "#e6e6e6",
"idle": "#a0a0a0",
"accent": "#5e9eff",
"overlayStrong": "#2b5f96",
"overlayWeak": "#202020",
"border": "#3a3a3a"
}
} }
``` ```
@@ -60,7 +108,7 @@ Changes take effect on restart (`omni-launcher`).
### Theming ### Theming
The launcher reads `org.freedesktop.appearance` from `xdg-desktop-portal` for color-scheme and accent, and falls back to Qt's `SystemPalette` (qt6ct / KDE / qgnomeplatform) for everything else. No app-side config is required for theming. The launcher reads `org.freedesktop.appearance` from `xdg-desktop-portal` for color-scheme and accent, and falls back to Qt's `SystemPalette` (qt6ct / KDE / qgnomeplatform) for everything else. Values under `colors` are optional overrides for users or theme managers that want a fixed palette.
## Dependencies ## Dependencies
+101
View File
@@ -0,0 +1,101 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: root
// Defaults. User config overrides any of these.
property string fontFamily: "JetBrainsMono Nerd Font Propo"
property int fontSize: 16
property string giphyApiKey: ""
property int panelWidth: 720
property int panelHeight: 520
property int padding: 5
property int spacing: 5
property int radius: 10
property string backgroundColor: ""
property string foregroundColor: ""
property string idleColor: ""
property string accentColor: ""
property string overlayStrongColor: ""
property string overlayWeakColor: ""
property string borderColor: ""
property bool loaded: false
readonly property string configPath: (Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")) + "/omni-launcher/config.json"
function _apply(obj) {
if (typeof obj.fontFamily === "string" && obj.fontFamily.length > 0) fontFamily = obj.fontFamily;
if (typeof obj.fontSize === "number" && obj.fontSize > 0) fontSize = obj.fontSize;
if (typeof obj.giphyApiKey === "string") giphyApiKey = obj.giphyApiKey;
if (typeof obj.panelWidth === "number" && obj.panelWidth > 0) panelWidth = obj.panelWidth;
if (typeof obj.panelHeight === "number" && obj.panelHeight > 0) panelHeight = obj.panelHeight;
if (typeof obj.padding === "number" && obj.padding > 0) padding = obj.padding;
if (typeof obj.spacing === "number" && obj.spacing > 0) spacing = obj.spacing;
if (typeof obj.radius === "number" && obj.radius >= 0) radius = obj.radius;
const colors = obj.colors || {};
if (typeof colors.background === "string" && colors.background.length > 0) backgroundColor = colors.background;
if (typeof colors.foreground === "string" && colors.foreground.length > 0) foregroundColor = colors.foreground;
if (typeof colors.idle === "string" && colors.idle.length > 0) idleColor = colors.idle;
if (typeof colors.accent === "string" && colors.accent.length > 0) accentColor = colors.accent;
if (typeof colors.overlayStrong === "string" && colors.overlayStrong.length > 0) overlayStrongColor = colors.overlayStrong;
if (typeof colors.overlayWeak === "string" && colors.overlayWeak.length > 0) overlayWeakColor = colors.overlayWeak;
if (typeof colors.border === "string" && colors.border.length > 0) borderColor = colors.border;
}
Component.onCompleted: {
_load();
_startWatcher();
}
function _load() {
_loader.running = false;
_loader.command = ["cat", configPath];
_loader.running = true;
}
function _startWatcher() {
_watcher.running = false;
_watcher.command = [
"sh", "-c",
"while inotifywait -q -e close_write " + JSON.stringify(configPath) + " 2>/dev/null; do echo CHANGED; done"
];
_watcher.running = true;
}
property Process _watcher: Process {
running: false
stdout: SplitParser {
splitMarker: "\n"
onRead: line => {
if (line.indexOf("CHANGED") >= 0) {
console.log("omni-launcher: config changed, reloading");
root._load();
}
}
}
onExited: root._startWatcher()
}
property Process _loader: Process {
running: false
stdout: StdioCollector {
onStreamFinished: {
const text = (this.text || "").trim();
if (text.length > 0) {
try {
root._apply(JSON.parse(text));
} catch (e) {
console.log("omni-launcher: config.json parse error:", e);
}
}
root.loaded = true;
}
}
}
}
+21 -13
View File
@@ -13,7 +13,7 @@ QtObject {
// Portal-reported state. Defaults match "prefer dark, neutral accent". // Portal-reported state. Defaults match "prefer dark, neutral accent".
// 0 = no preference, 1 = dark, 2 = light (per xdg-desktop-portal spec). // 0 = no preference, 1 = dark, 2 = light (per xdg-desktop-portal spec).
property int colorScheme: 1 property int colorScheme: 1
property color accent: "#5e9eff" property color portalAccent: "#5e9eff"
property bool _portalLoaded: false property bool _portalLoaded: false
readonly property bool dark: colorScheme !== 2 readonly property bool dark: colorScheme !== 2
@@ -22,22 +22,30 @@ QtObject {
// background mixing portal color-scheme with SystemPalette text led to // background mixing portal color-scheme with SystemPalette text led to
// unreadable combinations (dark bg + dark text) when the Qt platform // unreadable combinations (dark bg + dark text) when the Qt platform
// theme disagrees with the portal. // theme disagrees with the portal.
readonly property color foreground: dark ? "#e6e6e6" : "#1a1a1a" readonly property color accent: Config.accentColor.length > 0
readonly property color idle: dark ? Qt.rgba(1, 1, 1, 0.55) ? Config.accentColor : portalAccent
: Qt.rgba(0, 0, 0, 0.55) readonly property color foreground: Config.foregroundColor.length > 0
readonly property color opaque_background: dark ? Config.foregroundColor : (dark ? "#e6e6e6" : "#1a1a1a")
readonly property color idle: Config.idleColor.length > 0
? Config.idleColor : (dark ? Qt.rgba(1, 1, 1, 0.55)
: Qt.rgba(0, 0, 0, 0.55))
readonly property color opaque_background: Config.backgroundColor.length > 0
? Config.backgroundColor : (dark
? Qt.rgba(0, 0, 0, 0.8) ? Qt.rgba(0, 0, 0, 0.8)
: Qt.rgba(1, 1, 1, 0.9) : Qt.rgba(1, 1, 1, 0.9))
readonly property color overlay_strong: dark ? Qt.rgba(1, 1, 1, 0.14) : Qt.rgba(0, 0, 0, 0.10) readonly property color overlay_strong: Config.overlayStrongColor.length > 0
readonly property color overlay_weak: dark ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.04) ? Config.overlayStrongColor : (dark ? Qt.rgba(1, 1, 1, 0.14) : Qt.rgba(0, 0, 0, 0.10))
readonly property color border_subtle: dark ? Qt.rgba(1, 1, 1, 0.10) : Qt.rgba(0, 0, 0, 0.10) readonly property color overlay_weak: Config.overlayWeakColor.length > 0
? Config.overlayWeakColor : (dark ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.04))
readonly property color border_subtle: Config.borderColor.length > 0
? Config.borderColor : (dark ? Qt.rgba(1, 1, 1, 0.10) : Qt.rgba(0, 0, 0, 0.10))
readonly property string fontFamily: Config.fontFamily readonly property string fontFamily: Config.fontFamily
readonly property int fontSize: Config.fontSize readonly property int fontSize: Config.fontSize
readonly property int padding: 5 readonly property int padding: Config.padding
readonly property int spacing: 5 readonly property int spacing: Config.spacing
readonly property int radius: 10 readonly property int radius: Config.radius
// Read the portal once at startup. The portal also emits a SettingChanged // Read the portal once at startup. The portal also emits a SettingChanged
// signal we could subscribe to, but a one-shot read keeps us out of a // signal we could subscribe to, but a one-shot read keeps us out of a
@@ -60,7 +68,7 @@ QtObject {
const ac = text.match(/'accent-color':\s*<\(([-\d.eE+]+),\s*([-\d.eE+]+),\s*([-\d.eE+]+)\)>/); const ac = text.match(/'accent-color':\s*<\(([-\d.eE+]+),\s*([-\d.eE+]+),\s*([-\d.eE+]+)\)>/);
if (ac) { if (ac) {
const r = parseFloat(ac[1]), g = parseFloat(ac[2]), b = parseFloat(ac[3]); const r = parseFloat(ac[1]), g = parseFloat(ac[2]), b = parseFloat(ac[3]);
if (r >= 0 && g >= 0 && b >= 0) root.accent = Qt.rgba(r, g, b, 1); if (r >= 0 && g >= 0 && b >= 0) root.portalAccent = Qt.rgba(r, g, b, 1);
} }
root._portalLoaded = true; root._portalLoaded = true;
} }
View File
-44
View File
@@ -1,44 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: root
// Defaults. User config overrides any of these.
property string fontFamily: "JetBrainsMono Nerd Font Propo"
property int fontSize: 16
property string giphyApiKey: ""
property int panelWidth: 720
property int panelHeight: 520
property bool loaded: false
function _apply(obj) {
if (typeof obj.fontFamily === "string" && obj.fontFamily.length > 0) fontFamily = obj.fontFamily;
if (typeof obj.fontSize === "number" && obj.fontSize > 0) fontSize = obj.fontSize;
if (typeof obj.giphyApiKey === "string") giphyApiKey = obj.giphyApiKey;
if (typeof obj.panelWidth === "number" && obj.panelWidth > 0) panelWidth = obj.panelWidth;
if (typeof obj.panelHeight === "number" && obj.panelHeight > 0) panelHeight = obj.panelHeight;
}
property Process _loader: Process {
running: true
command: ["sh", "-c", "cat \"${XDG_CONFIG_HOME:-$HOME/.config}/omni-launcher/config.json\" 2>/dev/null"]
stdout: StdioCollector {
onStreamFinished: {
const text = (this.text || "").trim();
if (text.length > 0) {
try {
root._apply(JSON.parse(text));
} catch (e) {
console.log("omni-launcher: config.json parse error:", e);
}
}
root.loaded = true;
}
}
}
}
+1
View File
@@ -1,5 +1,6 @@
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import OmniLauncher
ShellRoot { ShellRoot {
IpcHandler { IpcHandler {