mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 05:00:08 +02:00
Prevent small desktop overlay pointer movements from starting a drag
This commit is contained in:
1 parent
85532a54f3
commit
77f28f0922
6 files changed
+167
-1
No files matched your search
+20
-1
@@ -58,6 +58,7 @@
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "vr.h"
|
||||
#include "controller-click.h"
|
||||
|
||||
#define MAX_SCREENS 24 // screens and spare outputs
|
||||
|
||||
@@ -104,6 +105,7 @@ struct server {
|
||||
struct wl_list buffers; // tracked_buffer
|
||||
struct wl_event_source *tick;
|
||||
struct screen *pointer_focus;
|
||||
struct ft_controller_click controller_click;
|
||||
pid_t child;
|
||||
// Where typing goes: the screens after a click on one, Steam after a click on another
|
||||
// panel. The input relay grabs the keyboards while it's the screens (see keys_update).
|
||||
@@ -292,6 +294,11 @@ static void handle_vr_event(const struct ft_event *e, void *data) {
|
||||
return;
|
||||
}
|
||||
if (e->screen < 0 || e->screen >= MAX_SCREENS || !s->screens[e->screen]) return;
|
||||
struct ft_event filtered = *e;
|
||||
if (e->screen < s->n_config &&
|
||||
!ft_controller_click_filter(&s->controller_click, &filtered, s->scale[e->screen])) return;
|
||||
e = &filtered;
|
||||
if (e->screen < 0 || e->screen >= MAX_SCREENS || !s->screens[e->screen]) return;
|
||||
struct screen *sc = s->screens[e->screen];
|
||||
struct wlr_surface *surface = sc->toplevel->base->surface;
|
||||
const uint32_t t = now_ms();
|
||||
@@ -514,7 +521,18 @@ static int control_readable(int fd, uint32_t mask, void *data) {
|
||||
unsigned code;
|
||||
int value, index, w, h;
|
||||
double scale;
|
||||
if (sscanf(buf, "size %d %d %d", &index, &w, &h) == 3) {
|
||||
char tail;
|
||||
if (strcmp(buf, "controller-click?") == 0) {
|
||||
snprintf(reply, sizeof reply,
|
||||
"{\"supported\":true,\"threshold\":%.3f,\"held\":%s,\"dragging\":%s,\"suppressedMotions\":%lu,\"clicks\":%lu,\"drags\":%lu}",
|
||||
s->controller_click.threshold, s->controller_click.held ? "true" : "false",
|
||||
s->controller_click.dragging ? "true" : "false", s->controller_click.suppressed,
|
||||
s->controller_click.clicks, s->controller_click.drags);
|
||||
} else if (sscanf(buf, "controller-click %lf %c", &scale, &tail) == 1) {
|
||||
if (!isfinite(scale) || scale < 0 || scale > 64 || s->controller_click.buttons)
|
||||
snprintf(reply, sizeof reply, "error threshold or held controller button");
|
||||
else { s->controller_click.threshold = scale; snprintf(reply, sizeof reply, "ok"); }
|
||||
} else if (sscanf(buf, "size %d %d %d", &index, &w, &h) == 3) {
|
||||
// A new resolution for a screen, live: KWin resizes the screen to match. (KWin makes
|
||||
// it this size times its scale; ft-floatd sends spares' sizes divided by theirs.)
|
||||
const int min_w = index - 1 < s->n_config ? 320 : 64, min_h = index - 1 < s->n_config ? 200 : 64;
|
||||
@@ -641,6 +659,7 @@ static bool setup_dmabuf(struct server *s) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct server s = {0};
|
||||
s.controller_click.threshold = 8;
|
||||
for (int i = 0; i < MAX_SCREENS; ++i) s.scale[i] = 1;
|
||||
s.kb_screen = -1;
|
||||
const char *socket_name = "ft-screens-0", *control_name = "ft_screens";
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef FT_CONTROLLER_CLICK_H
|
||||
#define FT_CONTROLLER_CLICK_H
|
||||
#include <math.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include "vr.h"
|
||||
struct ft_controller_click {
|
||||
bool held, dragging;
|
||||
int screen;
|
||||
uint32_t buttons;
|
||||
double x, y, threshold, radius;
|
||||
unsigned long suppressed, clicks, drags;
|
||||
};
|
||||
// Hold the desktop position at press time until movement exceeds a logical-pixel
|
||||
// radius. No timer, delayed button-down, or change to native mouse input.
|
||||
static inline bool ft_controller_click_filter(struct ft_controller_click *c,
|
||||
struct ft_event *e, double scale) {
|
||||
if (e->type == FT_BUTTON && e->button >= BTN_LEFT && e->button < BTN_LEFT+8) {
|
||||
uint32_t bit = 1u << (e->button-BTN_LEFT);
|
||||
if (e->pressed) c->buttons |= bit; else c->buttons &= ~bit;
|
||||
}
|
||||
if (e->type == FT_BUTTON && e->pressed) {
|
||||
if (e->button == BTN_LEFT && !c->held && c->threshold > 0) {
|
||||
c->held = true; c->dragging = false; c->screen = e->screen;
|
||||
c->x = e->x; c->y = e->y; c->radius = c->threshold * scale;
|
||||
} else if (e->button != BTN_LEFT) {
|
||||
c->held = false; // Multi-button gestures retain their usual semantics.
|
||||
}
|
||||
} else if (e->type == FT_MOTION && c->held && !c->dragging) {
|
||||
if (e->screen == c->screen && hypot(e->x-c->x, e->y-c->y) <= c->radius) {
|
||||
++c->suppressed;
|
||||
return false;
|
||||
}
|
||||
c->dragging = true; ++c->drags;
|
||||
} else if (e->type == FT_BUTTON && e->button == BTN_LEFT && !e->pressed && c->held) {
|
||||
if (!c->dragging) {
|
||||
e->screen = c->screen; e->x = c->x; e->y = c->y;
|
||||
++c->clicks;
|
||||
}
|
||||
c->held = false;
|
||||
} else if (e->type == FT_LEAVE && c->held) {
|
||||
return false; // Preserve the implicit grab through tiny edge excursions.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#include <assert.h>
|
||||
#include "../controller-click.h"
|
||||
static struct ft_event event(enum ft_event_type t, bool down, double x, double y) {
|
||||
return (struct ft_event){.type=t,.screen=0,.button=BTN_LEFT,.pressed=down,.x=x,.y=y};
|
||||
}
|
||||
int main(void) {
|
||||
struct ft_controller_click c={.threshold=8};
|
||||
struct ft_event e=event(FT_BUTTON,true,100,100);
|
||||
assert(ft_controller_click_filter(&c,&e,2));
|
||||
e=event(FT_MOTION,false,112,108);
|
||||
assert(!ft_controller_click_filter(&c,&e,2));
|
||||
assert(c.held && !c.dragging && c.suppressed==1);
|
||||
e=event(FT_BUTTON,false,116,111);
|
||||
assert(ft_controller_click_filter(&c,&e,2));
|
||||
assert(e.x==100 && e.y==100 && c.clicks==1 && !c.held);
|
||||
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
|
||||
e=event(FT_MOTION,false,109,100);assert(ft_controller_click_filter(&c,&e,1));
|
||||
assert(c.dragging && c.drags==1);
|
||||
e=event(FT_MOTION,false,101,100);assert(ft_controller_click_filter(&c,&e,1));
|
||||
e=event(FT_BUTTON,false,103,100);assert(ft_controller_click_filter(&c,&e,1));
|
||||
assert(e.x==103 && c.clicks==1 && !c.held);
|
||||
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
|
||||
e=event(FT_LEAVE,false,0,0);assert(!ft_controller_click_filter(&c,&e,1));
|
||||
e=event(FT_BUTTON,false,800,900);e.screen=1;ft_controller_click_filter(&c,&e,1);
|
||||
assert(e.screen==0 && e.x==100 && c.clicks==2);
|
||||
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
|
||||
e=event(FT_MOTION,false,101,100);e.screen=1;
|
||||
assert(ft_controller_click_filter(&c,&e,1) && c.dragging);
|
||||
e=event(FT_BUTTON,false,101,100);ft_controller_click_filter(&c,&e,1);
|
||||
c.threshold=0;
|
||||
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
|
||||
e=event(FT_MOTION,false,101,100);assert(ft_controller_click_filter(&c,&e,1) && !c.held);
|
||||
c.threshold=8;
|
||||
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
|
||||
e=event(FT_BUTTON,true,100,100);e.button=BTN_RIGHT;ft_controller_click_filter(&c,&e,1);
|
||||
assert(!c.held);
|
||||
}
|
||||
Reference in new issue
Block a user