7 Commits

Author SHA1 Message Date
3d05e560b1 chore: bump version to 0.1.7 2025-12-28 16:31:19 +01:00
604b902261 feat: add example themes (owl, catppuccin-mocha, nord)
Themes are installed to /usr/share/owlry/themes/ and can be
copied to ~/.config/owlry/themes/ for customization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:31:18 +01:00
bb0b0dfa87 chore: bump version to 0.1.6 2025-12-28 16:22:33 +01:00
fc4dde32eb docs: add example config location to README
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:22:32 +01:00
cc1ad7bbb7 chore: bump version to 0.1.5 2025-12-28 16:16:40 +01:00
16ba5b642a docs: add example config and CLAUDE.md
- config.example.toml with all available options documented
- CLAUDE.md with release workflow instructions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:16:31 +01:00
1608582cbd fix: detect dmenu mode correctly using fstat
Previously, poll() on /dev/null returned "readable" (EOF),
causing dmenu mode to trigger when launched from keybinds.

Now uses fstat() to check if stdin is a pipe or regular file
before checking for data. Character devices (TTY, /dev/null)
no longer trigger dmenu mode.

Fixes items not showing when launched from window manager keybinds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:07:59 +01:00
9 changed files with 479 additions and 5 deletions

32
CLAUDE.md Normal file
View File

@@ -0,0 +1,32 @@
# Owlry - Claude Code Instructions
## Release Workflow
Always use `just` for releases and AUR deployment:
```bash
# Bump version (updates Cargo.toml + Cargo.lock, commits)
just bump 0.x.y
# Push and create tag
git push && just tag
# Update AUR package
just aur-update
# Review changes, then publish
just aur-publish
```
Do NOT manually edit Cargo.toml for version bumps - use `just bump`.
## Available just recipes
- `just build` / `just release` - Build debug/release
- `just check` - Run cargo check + clippy
- `just test` - Run tests
- `just bump <version>` - Bump version
- `just tag` - Create and push git tag
- `just aur-update` - Update PKGBUILD checksums
- `just aur-publish` - Commit and push to AUR
- `just aur-test` - Test PKGBUILD locally

2
Cargo.lock generated
View File

@@ -859,7 +859,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "owlry"
version = "0.1.3"
version = "0.1.7"
dependencies = [
"clap",
"dirs",

View File

@@ -1,6 +1,6 @@
[package]
name = "owlry"
version = "0.1.3"
version = "0.1.7"
edition = "2024"
rust-version = "1.90"
description = "A lightweight, owl-themed application launcher for Wayland"

View File

@@ -100,6 +100,13 @@ Example: `:cmd git` searches only PATH commands for "git"
Configuration file: `~/.config/owlry/config.toml`
An example config is installed at `/usr/share/doc/owlry/config.example.toml`:
```bash
mkdir -p ~/.config/owlry
cp /usr/share/doc/owlry/config.example.toml ~/.config/owlry/config.toml
```
```toml
[general]
show_icons = true
@@ -157,15 +164,37 @@ You can override this with `launch_wrapper` in config, or set to empty string `"
By default, Owlry inherits colors from your system GTK4 theme (Adwaita, Breeze, etc.).
### Owl Theme
### Built-in Themes
Enable the built-in owl-inspired dark theme:
Owlry includes an owl-inspired dark theme:
```toml
[appearance]
theme = "owl"
```
### Included Example Themes
Example themes are installed to `/usr/share/owlry/themes/`:
- `owl.css` - Owl-inspired dark theme with amber accents
- `catppuccin-mocha.css` - Soothing pastel theme
- `nord.css` - Arctic, north-bluish palette
To use an example theme:
```bash
mkdir -p ~/.config/owlry/themes
cp /usr/share/owlry/themes/catppuccin-mocha.css ~/.config/owlry/themes/
```
Then set in config:
```toml
[appearance]
theme = "catppuccin-mocha"
```
### Custom Theme
Create a custom theme file at `~/.config/owlry/themes/mytheme.css`:

42
config.example.toml Normal file
View File

@@ -0,0 +1,42 @@
# Owlry Configuration
# Copy to ~/.config/owlry/config.toml
[general]
show_icons = true
max_results = 10
terminal_command = "kitty" # Auto-detected if not set
# Launch wrapper for app execution (auto-detected if not set)
# Examples:
# "uwsm app --" # For uwsm sessions
# "hyprctl dispatch exec --" # For Hyprland
# "" # Direct execution
# launch_wrapper = "uwsm app --"
[appearance]
width = 600
height = 400
font_size = 14
border_radius = 12
# Theme: "owl" for built-in dark theme, or leave unset for GTK default
# theme = "owl"
# Individual color overrides (CSS color values)
# [appearance.colors]
# background = "#1a1b26"
# background_secondary = "#24283b"
# border = "#414868"
# text = "#c0caf5"
# text_secondary = "#565f89"
# accent = "#7aa2f7"
# accent_bright = "#89b4fa"
# badge_app = "#9ece6a"
# badge_cmd = "#7aa2f7"
# badge_dmenu = "#bb9af7"
# badge_uuctl = "#f7768e"
[providers]
applications = true
commands = true
uuctl = true

View File

@@ -17,17 +17,37 @@ impl DmenuProvider {
}
/// Check if stdin has data (non-blocking check)
/// Returns true only if stdin is a pipe or regular file with data available.
/// Returns false for TTYs, /dev/null, and other character devices.
pub fn has_stdin_data() -> bool {
use std::os::unix::io::AsRawFd;
let stdin_fd = io::stdin().as_raw_fd();
// First check if stdin is a pipe or regular file (valid dmenu input sources)
// Character devices (TTY, /dev/null) should NOT trigger dmenu mode
let mut stat_buf: libc::stat = unsafe { std::mem::zeroed() };
let stat_result = unsafe { libc::fstat(stdin_fd, &mut stat_buf) };
if stat_result != 0 {
return false;
}
let mode = stat_buf.st_mode;
let is_pipe = (mode & libc::S_IFMT) == libc::S_IFIFO;
let is_file = (mode & libc::S_IFMT) == libc::S_IFREG;
// Only check for data if stdin is a pipe or file
if !is_pipe && !is_file {
return false;
}
// Non-blocking poll to check if data is available
let mut poll_fd = libc::pollfd {
fd: stdin_fd,
events: libc::POLLIN,
revents: 0,
};
// Non-blocking poll with 0 timeout
let result = unsafe { libc::poll(&mut poll_fd, 1, 0) };
result > 0 && (poll_fd.revents & libc::POLLIN) != 0
}

114
themes/catppuccin-mocha.css Normal file
View File

@@ -0,0 +1,114 @@
/*
* Owlry - Catppuccin Mocha Theme
* A soothing pastel theme based on Catppuccin Mocha palette
* https://catppuccin.com/
*
* Usage: Copy to ~/.config/owlry/themes/catppuccin-mocha.css
* Set theme = "catppuccin-mocha" in config.toml
*/
:root {
--owlry-bg: #1e1e2e;
--owlry-bg-secondary: #313244;
--owlry-border: #45475a;
--owlry-text: #cdd6f4;
--owlry-text-secondary: #a6adc8;
--owlry-accent: #cba6f7;
--owlry-accent-bright: #f5c2e7;
--owlry-badge-app: #a6e3a1;
--owlry-badge-cmd: #89b4fa;
--owlry-badge-dmenu: #f9e2af;
--owlry-badge-uuctl: #fab387;
}
.owlry-main {
background-color: rgba(30, 30, 46, 0.95);
border: 1px solid rgba(69, 71, 90, 0.6);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(203, 166, 247, 0.1);
}
.owlry-search {
background-color: rgba(49, 50, 68, 0.8);
border: 2px solid rgba(69, 71, 90, 0.5);
color: var(--owlry-text);
caret-color: var(--owlry-accent);
}
.owlry-search:focus {
border-color: var(--owlry-accent);
box-shadow: 0 0 0 2px rgba(203, 166, 247, 0.2);
}
.owlry-result-row:hover {
background-color: rgba(49, 50, 68, 0.6);
}
.owlry-result-row:selected {
background-color: rgba(203, 166, 247, 0.15);
border-left: 3px solid var(--owlry-accent);
}
.owlry-result-row:selected .owlry-result-name {
color: var(--owlry-accent-bright);
}
.owlry-result-row:selected .owlry-result-icon {
color: var(--owlry-accent);
}
.owlry-badge-app {
background-color: rgba(166, 227, 161, 0.2);
color: var(--owlry-badge-app);
}
.owlry-badge-cmd {
background-color: rgba(137, 180, 250, 0.2);
color: var(--owlry-badge-cmd);
}
.owlry-badge-dmenu {
background-color: rgba(249, 226, 175, 0.2);
color: var(--owlry-badge-dmenu);
}
.owlry-badge-uuctl {
background-color: rgba(250, 179, 135, 0.2);
color: var(--owlry-badge-uuctl);
}
.owlry-filter-button:checked {
background-color: rgba(203, 166, 247, 0.2);
color: var(--owlry-accent);
border-color: rgba(203, 166, 247, 0.4);
}
.owlry-filter-app:checked {
background-color: rgba(166, 227, 161, 0.2);
color: var(--owlry-badge-app);
border-color: rgba(166, 227, 161, 0.4);
}
.owlry-filter-cmd:checked {
background-color: rgba(137, 180, 250, 0.2);
color: var(--owlry-badge-cmd);
border-color: rgba(137, 180, 250, 0.4);
}
.owlry-filter-uuctl:checked {
background-color: rgba(250, 179, 135, 0.2);
color: var(--owlry-badge-uuctl);
border-color: rgba(250, 179, 135, 0.4);
}
scrollbar slider {
background-color: rgba(69, 71, 90, 0.5);
}
scrollbar slider:hover {
background-color: rgba(88, 91, 112, 0.7);
}
scrollbar slider:active {
background-color: var(--owlry-accent);
}

114
themes/nord.css Normal file
View File

@@ -0,0 +1,114 @@
/*
* Owlry - Nord Theme
* An arctic, north-bluish color palette
* https://nordtheme.com/
*
* Usage: Copy to ~/.config/owlry/themes/nord.css
* Set theme = "nord" in config.toml
*/
:root {
--owlry-bg: #2e3440;
--owlry-bg-secondary: #3b4252;
--owlry-border: #4c566a;
--owlry-text: #eceff4;
--owlry-text-secondary: #d8dee9;
--owlry-accent: #88c0d0;
--owlry-accent-bright: #8fbcbb;
--owlry-badge-app: #a3be8c;
--owlry-badge-cmd: #81a1c1;
--owlry-badge-dmenu: #ebcb8b;
--owlry-badge-uuctl: #bf616a;
}
.owlry-main {
background-color: rgba(46, 52, 64, 0.95);
border: 1px solid rgba(76, 86, 106, 0.6);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
0 0 0 1px rgba(136, 192, 208, 0.1);
}
.owlry-search {
background-color: rgba(59, 66, 82, 0.8);
border: 2px solid rgba(76, 86, 106, 0.5);
color: var(--owlry-text);
caret-color: var(--owlry-accent);
}
.owlry-search:focus {
border-color: var(--owlry-accent);
box-shadow: 0 0 0 2px rgba(136, 192, 208, 0.2);
}
.owlry-result-row:hover {
background-color: rgba(59, 66, 82, 0.6);
}
.owlry-result-row:selected {
background-color: rgba(136, 192, 208, 0.15);
border-left: 3px solid var(--owlry-accent);
}
.owlry-result-row:selected .owlry-result-name {
color: var(--owlry-accent-bright);
}
.owlry-result-row:selected .owlry-result-icon {
color: var(--owlry-accent);
}
.owlry-badge-app {
background-color: rgba(163, 190, 140, 0.2);
color: var(--owlry-badge-app);
}
.owlry-badge-cmd {
background-color: rgba(129, 161, 193, 0.2);
color: var(--owlry-badge-cmd);
}
.owlry-badge-dmenu {
background-color: rgba(235, 203, 139, 0.2);
color: var(--owlry-badge-dmenu);
}
.owlry-badge-uuctl {
background-color: rgba(191, 97, 106, 0.2);
color: var(--owlry-badge-uuctl);
}
.owlry-filter-button:checked {
background-color: rgba(136, 192, 208, 0.2);
color: var(--owlry-accent);
border-color: rgba(136, 192, 208, 0.4);
}
.owlry-filter-app:checked {
background-color: rgba(163, 190, 140, 0.2);
color: var(--owlry-badge-app);
border-color: rgba(163, 190, 140, 0.4);
}
.owlry-filter-cmd:checked {
background-color: rgba(129, 161, 193, 0.2);
color: var(--owlry-badge-cmd);
border-color: rgba(129, 161, 193, 0.4);
}
.owlry-filter-uuctl:checked {
background-color: rgba(191, 97, 106, 0.2);
color: var(--owlry-badge-uuctl);
border-color: rgba(191, 97, 106, 0.4);
}
scrollbar slider {
background-color: rgba(76, 86, 106, 0.5);
}
scrollbar slider:hover {
background-color: rgba(76, 86, 106, 0.7);
}
scrollbar slider:active {
background-color: var(--owlry-accent);
}

123
themes/owl.css Normal file
View File

@@ -0,0 +1,123 @@
/*
* Owlry - Owl Theme
* An owl-inspired dark theme with amber accents
*
* Color Palette:
* - Deep night sky: #1a1b26 (background)
* - Twilight: #24283b (secondary bg)
* - Owl feathers: #414868 (borders/muted)
* - Moon glow: #c0caf5 (primary text)
* - Owl eyes (amber): #e0af68 (accent/highlight)
* - Forest shadows: #565f89 (secondary text)
* - Barn owl cream: #f5e0dc (bright accent)
*
* Usage: Copy to ~/.config/owlry/themes/owl.css
* Set theme = "owl" in config.toml
* (Note: "owl" is also built-in, so this file is optional)
*/
:root {
--owlry-bg: #1a1b26;
--owlry-bg-secondary: #24283b;
--owlry-border: #414868;
--owlry-text: #c0caf5;
--owlry-text-secondary: #565f89;
--owlry-accent: #e0af68;
--owlry-accent-bright: #f5e0dc;
--owlry-badge-app: #7aa2f7;
--owlry-badge-cmd: #bb9af7;
--owlry-badge-dmenu: #9ece6a;
--owlry-badge-uuctl: #e0af68;
}
.owlry-main {
background-color: rgba(26, 27, 38, 0.95);
border: 1px solid rgba(65, 72, 104, 0.6);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(224, 175, 104, 0.1);
}
.owlry-search {
background-color: rgba(36, 40, 59, 0.8);
border: 2px solid rgba(65, 72, 104, 0.5);
color: var(--owlry-text);
caret-color: var(--owlry-accent);
}
.owlry-search:focus {
border-color: var(--owlry-accent);
box-shadow: 0 0 0 2px rgba(224, 175, 104, 0.2);
}
.owlry-result-row:hover {
background-color: rgba(36, 40, 59, 0.6);
}
.owlry-result-row:selected {
background-color: rgba(224, 175, 104, 0.15);
border-left: 3px solid var(--owlry-accent);
}
.owlry-result-row:selected .owlry-result-name {
color: var(--owlry-accent-bright);
}
.owlry-result-row:selected .owlry-result-icon {
color: var(--owlry-accent);
}
.owlry-badge-app {
background-color: rgba(122, 162, 247, 0.2);
color: var(--owlry-badge-app);
}
.owlry-badge-cmd {
background-color: rgba(187, 154, 247, 0.2);
color: var(--owlry-badge-cmd);
}
.owlry-badge-dmenu {
background-color: rgba(158, 206, 106, 0.2);
color: var(--owlry-badge-dmenu);
}
.owlry-badge-uuctl {
background-color: rgba(224, 175, 104, 0.2);
color: var(--owlry-badge-uuctl);
}
.owlry-filter-button:checked {
background-color: rgba(224, 175, 104, 0.2);
color: var(--owlry-accent);
border-color: rgba(224, 175, 104, 0.4);
}
.owlry-filter-app:checked {
background-color: rgba(122, 162, 247, 0.2);
color: var(--owlry-badge-app);
border-color: rgba(122, 162, 247, 0.4);
}
.owlry-filter-cmd:checked {
background-color: rgba(187, 154, 247, 0.2);
color: var(--owlry-badge-cmd);
border-color: rgba(187, 154, 247, 0.4);
}
.owlry-filter-uuctl:checked {
background-color: rgba(224, 175, 104, 0.2);
color: var(--owlry-badge-uuctl);
border-color: rgba(224, 175, 104, 0.4);
}
scrollbar slider {
background-color: rgba(65, 72, 104, 0.5);
}
scrollbar slider:hover {
background-color: rgba(86, 95, 137, 0.7);
}
scrollbar slider:active {
background-color: var(--owlry-accent);
}