mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 01:00:06 +02:00
Floating windows: fix the scale crash, the click offset, and placement
- KWin's nested backend makes an output the size it's configured to times its scale, so after Meta+scroll every size ft-floatd sent was multiplied again, and an odd result disconnected KWin (buffer not divisible by its scale). ft-floatd now asks for sizes in the output's scaled terms (kwin_size), and asks again after each scale change. - SteamVR reports mouse positions on a panel with texture bounds in the whole texture, not the crop, so clicks on a floating window landed up to ~200 px off. The mouse scale is now the buffer's size, as on a screen. - A floated window starts 30 cm in front of its screen (was 5 cm), so it's easy to point at apart from the screen behind it. - No 1 s wait before a spare turns on (a disabled output never commits), and the login splash on the spares isn't taken for floating windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2a9fbdebb4
commit
c8fc6351bb
3 files changed
+78
-43
No files matched your search
@@ -434,8 +434,10 @@ static int control_readable(int fd, uint32_t mask, void *data) {
|
||||
int value, index, w, h;
|
||||
double scale;
|
||||
if (sscanf(buf, "size %d %d %d", &index, &w, &h) == 3) {
|
||||
// A new resolution for a screen, live: KWin resizes the screen to match.
|
||||
if (index < 1 || index > MAX_SCREENS || !s->screens[index - 1] || w < 320 || h < 200 || w > 16384 ||
|
||||
// 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;
|
||||
if (index < 1 || index > MAX_SCREENS || !s->screens[index - 1] || w < min_w || h < min_h || w > 16384 ||
|
||||
h > 16384) {
|
||||
snprintf(reply, sizeof reply, "error bad screen or size");
|
||||
} else {
|
||||
|
||||
+10
-15
@@ -276,10 +276,8 @@ struct Screen {
|
||||
return width > 0 ? metres * height / width : metres * 9 / 16;
|
||||
}
|
||||
// Buffer pixels from OpenVR's mouse position on the panel (its origin is bottom left).
|
||||
void ToBuffer(double mx, double my, double *x, double *y) const {
|
||||
if (floating && cropW > 0) *x = cropX + mx, *y = cropY + cropH - my;
|
||||
else *x = mx, *y = height - my;
|
||||
}
|
||||
// A cropped panel too: SteamVR gives the position in the whole texture, not the crop.
|
||||
void ToBuffer(double mx, double my, double *x, double *y) const { *x = mx, *y = height - my; }
|
||||
std::array<vr::VROverlayHandle_t, 6> Controls() const {
|
||||
return {bar, curveButton, rollButton, handle, dockButton, closeButton};
|
||||
}
|
||||
@@ -1150,14 +1148,15 @@ void Push(Screen &s, double notches) {
|
||||
|
||||
// ---------------------------------------------------------------- floating windows
|
||||
|
||||
// Show the window's rectangle of the buffer, and map the mouse to it (see ToBuffer).
|
||||
// Texture bounds are fractions of the buffer, v from the top.
|
||||
// Show the window's rectangle of the buffer. Texture bounds are fractions of the buffer, v
|
||||
// from the top. SteamVR reports mouse positions in the whole texture (the bounds applied), so
|
||||
// the mouse scale is the buffer's size, as on a screen (see ToBuffer).
|
||||
void CropOverlay(vr::VROverlayHandle_t o, const Screen &s, int x, int y, int w, int h) {
|
||||
if (s.width <= 0 || s.height <= 0 || w <= 0 || h <= 0) return;
|
||||
vr::VRTextureBounds_t b = {float(x) / s.width, float(y) / s.height, float(x + w) / s.width,
|
||||
float(y + h) / s.height};
|
||||
vr::VROverlay()->SetOverlayTextureBounds(o, &b);
|
||||
vr::HmdVector2_t scale = {float(w), float(h)};
|
||||
vr::HmdVector2_t scale = {float(s.width), float(s.height)};
|
||||
vr::VROverlay()->SetOverlayMouseScale(o, &scale);
|
||||
}
|
||||
|
||||
@@ -1571,15 +1570,11 @@ void ft_vr_poll(void (*handle)(const struct ft_event *, void *), void *data) {
|
||||
RefreshPoses();
|
||||
for (auto &[index, s] : g_screens) {
|
||||
vr::VREvent_t ev;
|
||||
// The screen itself: input for KWin.
|
||||
// The screen itself (and a floating window's popups): input for KWin.
|
||||
auto panelEvent = [&](const vr::VREvent_t &ev, bool sub, const Sub *from) {
|
||||
auto panelEvent = [&](const vr::VREvent_t &ev, bool sub) {
|
||||
ft_event e{};
|
||||
e.screen = index;
|
||||
auto at = [&] {
|
||||
if (from) e.x = from->x + ev.data.mouse.x, e.y = from->y + from->h - ev.data.mouse.y;
|
||||
else s.ToBuffer(ev.data.mouse.x, ev.data.mouse.y, &e.x, &e.y);
|
||||
};
|
||||
auto at = [&] { s.ToBuffer(ev.data.mouse.x, ev.data.mouse.y, &e.x, &e.y); };
|
||||
switch (ev.eventType) {
|
||||
case vr::VREvent_MouseMove:
|
||||
if (s.titleCarry) return; // KWin's pointer stays where the title bar was pressed
|
||||
@@ -1624,9 +1619,9 @@ void ft_vr_poll(void (*handle)(const struct ft_event *, void *), void *data) {
|
||||
}
|
||||
handle(&e, data);
|
||||
};
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(s.overlay, &ev, sizeof ev)) panelEvent(ev, false, nullptr);
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(s.overlay, &ev, sizeof ev)) panelEvent(ev, false);
|
||||
for (const auto &[k, sub] : s.subs)
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(sub.overlay, &ev, sizeof ev)) panelEvent(ev, true, &sub);
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(sub.overlay, &ev, sizeof ev)) panelEvent(ev, true);
|
||||
// The controls light up under a laser.
|
||||
auto hover = [&](int k) {
|
||||
const bool on = ev.eventType == vr::VREvent_MouseMove || ev.eventType == vr::VREvent_FocusEnter;
|
||||
|
||||
Reference in new issue
Block a user