fix(xdrawer,dwm,dmenu): remove top bar gap and eliminate softkey menu latency

This commit is contained in:
Luxferre
2026-10-21 10:11:11 +03:00
parent 8045929c87
commit 7b7ae1dcc5
9 changed files with 124 additions and 63 deletions
+49 -27
View File
@@ -956,9 +956,37 @@ query_softkeys_down(void)
return mask;
}
static void
read_softkey_state(int *mask_out, long long *ms_out)
{
char buf[64];
int fd = open("/tmp/sxmo_softkey_state", O_RDONLY | O_CLOEXEC);
*mask_out = 0;
*ms_out = 0;
if (fd >= 0) {
ssize_t n = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (n > 0) {
buf[n] = '\0';
sscanf(buf, "%d %lld", mask_out, ms_out);
}
}
}
static void
clear_softkey_state(void)
{
int fd = open("/tmp/sxmo_softkey_state", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd >= 0) {
(void)write(fd, "0 0\n", 4);
close(fd);
}
}
static void
spawn_xdrawer_and_exit(void)
{
clear_softkey_state();
write_softkey_suppress(dmenu_now_ms() + 500);
cleanup();
if (fork() == 0) {
@@ -984,12 +1012,15 @@ run(void)
{
XEvent ev;
int soft_pending = 0;
long long soft_first_ms = 0;
long long soft_deadline = 0;
long long start_ignore = dmenu_now_ms() + 40;
int initial_released = (query_softkeys_down() == 0);
int init_soft_mask = 0;
long long init_soft_ms = 0;
int xfd = ConnectionNumber(dpy);
read_softkey_state(&init_soft_mask, &init_soft_ms);
for (;;) {
if (!initial_released && query_softkeys_down() == 0)
initial_released = 1;
@@ -1004,28 +1035,23 @@ run(void)
int is_right = (ks == XF86XK_Back || ks == XF86XK_KbdLcdMenu2 || ev.xkey.keycode == 166);
if (is_left || is_right) {
long long now = dmenu_now_ms();
int which = (is_left ? 1 : 0) | (is_right ? 2 : 0);
if (ev.type == KeyPress && init_soft_mask != 0 &&
(init_soft_mask | which) == 3 &&
(now - init_soft_ms) <= 320) {
spawn_xdrawer_and_exit();
}
if (ev.type == KeyRelease) {
initial_released = 1;
if (soft_pending != 0 && soft_pending != 3) {
long long grace = now + 65;
if (grace > soft_deadline)
soft_deadline = grace;
}
continue;
}
if (!initial_released || now < start_ignore)
continue;
if (is_left)
soft_pending |= 1;
if (is_right)
soft_pending |= 2;
soft_pending |= query_softkeys_down();
soft_pending |= which | query_softkeys_down();
if (soft_pending == 3)
spawn_xdrawer_and_exit();
if (soft_deadline == 0) {
soft_first_ms = now;
soft_deadline = now + 200;
}
if (soft_deadline == 0)
soft_deadline = now + 30;
continue;
}
if (!issoftkey(ev.xkey.keycode)) {
@@ -1077,19 +1103,15 @@ run(void)
spawn_xdrawer_and_exit();
long long rem = soft_deadline - now;
if (rem <= 0) {
if (hw_down != 0 && (now - soft_first_ms) < 480) {
soft_deadline = now + 25;
rem = 25;
clear_softkey_state();
write_softkey_suppress(now + 250);
if (soft_pending == 1) {
puts((sel) ? sel->text : text);
cleanup();
exit(0);
} else {
write_softkey_suppress(now + 400);
if (soft_pending == 1) {
puts((sel) ? sel->text : text);
cleanup();
exit(0);
} else {
cleanup();
exit(1);
}
cleanup();
exit(1);
}
}
struct pollfd pfd = { xfd, POLLIN, 0 };
+61 -23
View File
@@ -1449,14 +1449,17 @@ ishold(KeySym keysym)
#define SOFTKEY_LEFT 1
#define SOFTKEY_RIGHT 2
#define SOFTKEY_CHORD_MS 200
#define SOFTKEY_MAX_HOLD_MS 480
#define SOFTKEY_CHORD_MS 30
#define SOFTKEY_CANCEL_WINDOW_MS 320
#define SOFTKEY_SUPPRESS_MS 500
static int softkey_pending = 0;
static long long softkey_first_ms = 0;
static long long softkey_deadline_ms = 0;
static long long softkey_suppress_until_ms = 0;
static int last_softkey_mask = 0;
static long long last_softkey_ms = 0;
static pid_t last_menu_pgid = 0;
static long long
dwm_now_ms(void)
@@ -1480,6 +1483,18 @@ write_softkey_suppress(long long until_ms)
}
}
static void
write_softkey_state(int mask, long long ms)
{
char buf[64];
int fd = open("/tmp/sxmo_softkey_state", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd >= 0) {
int len = snprintf(buf, sizeof(buf), "%d %lld\n", mask, ms);
(void)write(fd, buf, len);
close(fd);
}
}
static long long
read_softkey_suppress(void)
{
@@ -1517,13 +1532,34 @@ is_right_softkey(KeySym ks, unsigned int keycode)
return ks == XF86XK_Back || ks == XF86XK_KbdLcdMenu2 || keycode == 166;
}
static pid_t
spawn_pgid(const Arg *arg)
{
pid_t pid = fork();
if (pid == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
_exit(EXIT_SUCCESS);
}
return pid;
}
static void
trigger_xdrawer_chord(long long now)
{
const Arg xdrawercmd = { .v = (const char*[]){ "xdrawer", NULL } };
if (last_menu_pgid > 0) {
kill(-last_menu_pgid, SIGKILL);
last_menu_pgid = 0;
}
softkey_pending = 0;
softkey_first_ms = 0;
softkey_deadline_ms = 0;
last_softkey_mask = 0;
last_softkey_ms = 0;
write_softkey_state(0, 0);
write_softkey_suppress(now + SOFTKEY_SUPPRESS_MS);
XUngrabKeyboard(dpy, CurrentTime);
XFlush(dpy);
@@ -1541,10 +1577,10 @@ flush_pending_softkey(void)
XFlush(dpy);
if (pending == SOFTKEY_LEFT) {
const Arg syscmd = { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } };
spawn(&syscmd);
last_menu_pgid = spawn_pgid(&syscmd);
} else if (pending == SOFTKEY_RIGHT) {
const Arg ctxcmd = { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } };
spawn(&ctxcmd);
last_menu_pgid = spawn_pgid(&ctxcmd);
}
}
@@ -1567,6 +1603,9 @@ keypress(XEvent *e)
softkey_pending = 0;
softkey_first_ms = 0;
softkey_deadline_ms = 0;
last_softkey_mask = 0;
last_softkey_ms = 0;
write_softkey_state(0, 0);
write_softkey_suppress(dwm_now_ms() + SOFTKEY_SUPPRESS_MS);
XUngrabKeyboard(dpy, CurrentTime);
XFlush(dpy);
@@ -1583,16 +1622,25 @@ keypress(XEvent *e)
XFlush(dpy);
return;
}
int which = 0;
if (is_left_softkey(keysym, ev->keycode))
softkey_pending |= SOFTKEY_LEFT;
which |= SOFTKEY_LEFT;
if (is_right_softkey(keysym, ev->keycode))
softkey_pending |= SOFTKEY_RIGHT;
softkey_pending |= query_softkeys_down();
if (softkey_pending == (SOFTKEY_LEFT | SOFTKEY_RIGHT)) {
which |= SOFTKEY_RIGHT;
int combined = softkey_pending | which | query_softkeys_down();
if (last_softkey_mask != 0 && (now - last_softkey_ms) <= SOFTKEY_CANCEL_WINDOW_MS)
combined |= last_softkey_mask;
if (combined == (SOFTKEY_LEFT | SOFTKEY_RIGHT)) {
trigger_xdrawer_chord(now);
} else if (softkey_deadline_ms == 0) {
softkey_first_ms = now;
softkey_deadline_ms = now + SOFTKEY_CHORD_MS;
} else {
softkey_pending = which;
last_softkey_mask = which;
last_softkey_ms = now;
write_softkey_state(which, now);
if (softkey_deadline_ms == 0) {
softkey_first_ms = now;
softkey_deadline_ms = now + SOFTKEY_CHORD_MS;
}
}
return;
}
@@ -1640,11 +1688,6 @@ keyrelease(XEvent *e)
markreleased(keysym);
if (is_left_softkey(keysym, ev->keycode) || is_right_softkey(keysym, ev->keycode)) {
if (softkey_pending != 0 && softkey_pending != (SOFTKEY_LEFT | SOFTKEY_RIGHT)) {
long long grace = dwm_now_ms() + 65;
if (grace > softkey_deadline_ms)
softkey_deadline_ms = grace;
}
return;
}
@@ -2100,13 +2143,8 @@ run(void)
}
long long rem = softkey_deadline_ms - now;
if (rem <= 0) {
if (hw_down != 0 && (now - softkey_first_ms) < SOFTKEY_MAX_HOLD_MS) {
softkey_deadline_ms = now + 25;
timeout_ms = 25;
} else {
flush_pending_softkey();
continue;
}
flush_pending_softkey();
continue;
} else {
timeout_ms = (int)rem;
}
+14 -13
View File
@@ -33,13 +33,12 @@ namespace {
constexpr int kScreenWidth = 240;
constexpr int kScreenHeight = 320;
constexpr int kTopBarHeight = 26;
constexpr int kTopBarHeight = 24;
constexpr int kWinX = 0;
constexpr int kWinY = kTopBarHeight;
constexpr int kWinWidth = kScreenWidth;
constexpr int kWinHeight = kScreenHeight - kTopBarHeight; // 294px (7 * 42px)
constexpr int kWinHeight = kScreenHeight - kTopBarHeight; // 296px flush below 24px dwm bar
constexpr int kRowCount = 7;
constexpr int kRowHeight = kWinHeight / kRowCount; // 42px per row
// Nerd Font PUA icons matching sxmo_hook_icons.sh & dwm ("Fira Code, DejaVuSansM Nerd Font")
constexpr const char* kIconSpeaker = "\xef\x80\xa8"; // U+F028 speaker
@@ -587,18 +586,20 @@ int main() {
XSetForeground(dpy, gc, 0x222222);
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, kWinHeight);
// 7 Control rows (42px each, 7 * 42 = 294px exact)
// 7 Control rows filling the full 296px height flush from y=24 to y=320
const auto& items = controller.items();
for (size_t i = 0; i < items.size(); ++i) {
int ry = static_cast<int>(i) * kRowHeight;
int ry = static_cast<int>((i * kWinHeight) / kRowCount);
int nextRy = static_cast<int>(((i + 1) * kWinHeight) / kRowCount);
int rowH = nextRy - ry;
bool isSel = (i == selected);
XSetForeground(dpy, gc, isSel ? 0x005577 : ((i % 2 == 0) ? 0x282828 : 0x2e2e2e));
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, kRowHeight);
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, rowH);
if (isSel) {
XSetForeground(dpy, gc, 0xf4d03f);
XFillRectangle(dpy, pix, gc, 0, ry, 4, kRowHeight);
XFillRectangle(dpy, pix, gc, 0, ry, 4, rowH);
}
const ControlItem& it = items[i];
@@ -607,8 +608,8 @@ int main() {
// Icon column (x = 8..28) + Label column (x = 30..112 for sliders, 30..166 for toggles)
int labelMaxW = it.isSlider ? 82 : 136;
drawPango(layoutIcon, isSel ? &colYellow : &colLight, 8, ry, kRowHeight, rowIcon);
drawPango(layoutMain, isSel ? &colWhite : &colLight, 30, ry, kRowHeight,
drawPango(layoutIcon, isSel ? &colYellow : &colLight, 8, ry, rowH, rowIcon);
drawPango(layoutMain, isSel ? &colWhite : &colLight, 30, ry, rowH,
it.label, labelMaxW);
if (it.isSlider) {
@@ -627,7 +628,7 @@ int main() {
int barX = 114;
int barW = 78;
int barH = 12;
int barY = ry + (kRowHeight - barH) / 2;
int barY = ry + (rowH - barH) / 2;
XSetForeground(dpy, gc, 0x161616);
XFillRectangle(dpy, pix, gc, barX, barY, barW, barH);
@@ -650,16 +651,16 @@ int main() {
std::string pctStr(pctBuf);
int pw = pangoWidth(layoutSmall, pctStr);
drawPango(layoutSmall, isSel ? &colWhite : &colLight, kWinWidth - pw - 6,
ry, kRowHeight, pctStr);
ry, rowH, pctStr);
} else {
// Toggle switch icon + ON/OFF label (right-aligned within x = 160..234)
bool on = (it.value != 0);
std::string stStr = on ? "ON" : "OFF";
int stW = pangoWidth(layoutMain, stStr);
drawPango(layoutMain, on ? (isSel ? &colYellow : &colGreen) : &colMuted,
kWinWidth - stW - 8, ry, kRowHeight, stStr);
kWinWidth - stW - 8, ry, rowH, stStr);
drawPango(layoutIcon, on ? (isSel ? &colYellow : &colGreen) : &colMuted,
kWinWidth - stW - 30, ry, kRowHeight,
kWinWidth - stW - 30, ry, rowH,
on ? kIconToggleOn : kIconToggleOff);
}
}