Skip to content
Open
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
8 changes: 5 additions & 3 deletions .config/hypr/scripts/quickshell/applauncher/appLauncher.qml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ Item {
}
}

function launchApp(execStr) {
function launchApp(name, execStr) {
Quickshell.execDetached(["python3", Quickshell.env("HOME") + "/.config/hypr/scripts/quickshell/applauncher/app_fetcher.py", "--increment", name]);
Quickshell.execDetached(["hyprctl", "dispatch", "exec", "--", execStr]);
Quickshell.execDetached(["bash", Quickshell.env("HOME") + "/.config/hypr/scripts/qs_manager.sh", "close"]);
}
Expand Down Expand Up @@ -308,7 +309,8 @@ Item {
}
Keys.onReturnPressed: {
if (appList.currentIndex >= 0 && appList.currentIndex < appModel.count) {
launchApp(appModel.get(appList.currentIndex).exec);
let item = appModel.get(appList.currentIndex);
launchApp(item.name, item.exec);
}
event.accepted = true;
}
Expand Down Expand Up @@ -548,7 +550,7 @@ Item {
hoverEnabled: true
onClicked: {
appList.currentIndex = index;
launchApp(model.exec);
launchApp(model.name, model.exec);
}
}
}
Expand Down
46 changes: 38 additions & 8 deletions .config/hypr/scripts/quickshell/applauncher/app_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,38 @@
import os
import glob
import json
import sys

CACHE_DIR = os.path.expanduser("~/.cache/quickshell/applauncher")
USAGE_FILE = os.path.join(CACHE_DIR, "usage.json")

def load_usage():
if os.path.exists(USAGE_FILE):
try:
with open(USAGE_FILE, 'r') as f:
return json.load(f)
except Exception:
pass
return {}

def save_usage(usage):
try:
os.makedirs(CACHE_DIR, exist_ok=True)
with open(USAGE_FILE, 'w') as f:
json.dump(usage, f)
except Exception:
pass

def increment_usage(name):
usage = load_usage()
usage[name] = usage.get(name, 0) + 1
save_usage(usage)

def fetch_apps():
usage = load_usage()
apps = {}
home = os.path.expanduser('~')

# Expanded directories to catch Flatpaks, system apps, and Nix packages
dirs = [
'/usr/share/applications',
'/usr/local/share/applications',
Expand Down Expand Up @@ -40,24 +66,28 @@ def fetch_apps():
if line.startswith('Name=') and not app['name']:
app['name'] = line[5:]
elif line.startswith('Exec=') and not app['exec']:
# Strip %u, %f, and @@ placeholders
app['exec'] = line[5:].split(' %')[0].split(' @@')[0]
elif line.startswith('Icon=') and not app['icon']:
app['icon'] = line[5:]
elif line.startswith('NoDisplay=true') or line.startswith('NoDisplay=1'):
no_display = True

if app['name'] and app['exec'] and not no_display:
apps[app['name']] = app
app['usage'] = usage.get(app['name'], 0)
# Keep only the first occurrence or prioritize one with higher usage if already exists?
# Usually, duplicates are the same app in different paths.
if app['name'] not in apps or app['usage'] > apps[app['name']]['usage']:
apps[app['name']] = app
except Exception:
pass

# Sort alphabetically and return as JSON
res = list(apps.values())
res.sort(key=lambda x: x['name'].lower())
# Sort by usage (descending) and then name (ascending)
res.sort(key=lambda x: (-x.get('usage', 0), x['name'].lower()))
print(json.dumps(res))

if __name__ == "__main__":
fetch_apps()


if len(sys.argv) > 2 and sys.argv[1] == "--increment":
increment_usage(sys.argv[2])
else:
fetch_apps()