Phase 1/2: .desktop launcher, volume control in deskbar
- Launcher now loads apps dynamically from /usr/share/applications and ~/.local/share/applications instead of a hardcoded list; maps desktop Categories to tab system, falls back to built-in list on systems without .desktop files (dev/macOS builds) - Launcher gains scroll support: mouse wheel and PgUp/PgDn scroll the app grid, scrollbar drawn on right edge when needed - Deskbar status bar shows VOL % from pactl (cached, polls every 5s) - Deskbar status bar: scroll wheel changes volume ±5%, left-click toggles mute Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
9089c14a19
commit
2b8ea90a57
2 files changed
+267
-96
No files matched your search
+42
-5
@@ -161,6 +161,23 @@ static int read_cpu_percent(void) {
|
||||
return (int)(100 * (d_total - d_idle) / d_total);
|
||||
}
|
||||
|
||||
static int read_volume_percent(void) {
|
||||
static int cached = -1;
|
||||
static int ticks = 0;
|
||||
if (ticks-- > 0) return cached;
|
||||
ticks = 4; /* re-poll every 5 seconds */
|
||||
FILE *f = popen("pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null", "r");
|
||||
if (!f) return cached;
|
||||
char line[256];
|
||||
cached = -1;
|
||||
if (fgets(line, sizeof(line), f)) {
|
||||
char *p = strstr(line, "/ ");
|
||||
if (p) cached = atoi(p + 2);
|
||||
}
|
||||
pclose(f);
|
||||
return cached;
|
||||
}
|
||||
|
||||
static int read_battery_percent(void) {
|
||||
FILE *f;
|
||||
char path[80];
|
||||
@@ -422,16 +439,20 @@ void db_draw(Deskbar *db) {
|
||||
int mem = read_mem_percent();
|
||||
int bat = read_battery_percent();
|
||||
char bst = read_battery_status();
|
||||
char status[64];
|
||||
int vol = read_volume_percent();
|
||||
char status[80];
|
||||
int pos = 0;
|
||||
if (vol >= 0)
|
||||
pos += snprintf(status + pos, sizeof(status) - pos,
|
||||
"VOL %d%%", vol);
|
||||
if (cpu >= 0)
|
||||
pos += snprintf(status + pos, sizeof(status) - pos,
|
||||
"CPU %d%%", cpu);
|
||||
"%sCPU %d%%", pos ? " " : "", cpu);
|
||||
if (mem >= 0)
|
||||
pos += snprintf(status + pos, sizeof(status) - pos,
|
||||
" MEM %d%%", mem);
|
||||
if (bat >= 0) {
|
||||
const char *arrow = (bst == 'C') ? "↑" : (bst == 'F') ? "=" : "↓";
|
||||
const char *arrow = (bst == 'C') ? "+" : (bst == 'F') ? "=" : "-";
|
||||
pos += snprintf(status + pos, sizeof(status) - pos,
|
||||
" BAT %d%%%s", bat, arrow);
|
||||
}
|
||||
@@ -888,8 +909,24 @@ void db_run(Deskbar *db) {
|
||||
if (e.xexpose.count == 0) db_draw(db);
|
||||
break;
|
||||
case ButtonPress:
|
||||
if (e.xany.window == db->win)
|
||||
db_click(db, e.xbutton.x, e.xbutton.y);
|
||||
if (e.xany.window == db->win) {
|
||||
int sy = db_status_y(db);
|
||||
if (e.xbutton.button == Button4) {
|
||||
/* scroll up on status bar = volume up */
|
||||
if (e.xbutton.y >= sy)
|
||||
system("pactl set-sink-volume @DEFAULT_SINK@ +5% 2>/dev/null &");
|
||||
break;
|
||||
}
|
||||
if (e.xbutton.button == Button5) {
|
||||
if (e.xbutton.y >= sy)
|
||||
system("pactl set-sink-volume @DEFAULT_SINK@ -5% 2>/dev/null &");
|
||||
break;
|
||||
}
|
||||
if (e.xbutton.button == Button1 && e.xbutton.y >= sy)
|
||||
system("pactl set-sink-mute @DEFAULT_SINK@ toggle 2>/dev/null &");
|
||||
else
|
||||
db_click(db, e.xbutton.x, e.xbutton.y);
|
||||
}
|
||||
break;
|
||||
case MotionNotify:
|
||||
if (e.xany.window == db->win)
|
||||
|
||||
Reference in new issue
Block a user