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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+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);
}
}