mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 06:00:09 +02:00
Float key in the input relay, docking everything, and the plan for profiles
The input relay owns the float key now: float_toggle (Meta+Shift+F unless the rules have their own key combinations) floats the window under the pointer, or the active one over the wallpaper, and docks it if it floats. dock_all puts every floating window back. Both are mappable to mouse and controller buttons, and work without pointer mode. The KWin script no longer registers a shortcut, and ft-floatd drops the old one. Key combinations move to Input Settings' Keyboard page. docs/floating-windows.md records the decisions from 2026-09-30 (the title bar button, Launch as Standalone, profiles), and docs/profiles.md plans profiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e16b7588e2
commit
1e83f96b0f
9 files changed
+220
-69
No files matched your search
+25
-4
@@ -2,7 +2,7 @@
|
||||
// loads it into the desktop's KWin over D-Bus (org.kde.kwin.Scripting) and talks to it:
|
||||
// - events go to ft-floatd as JSON strings (org.frametop.Float.Event), for the windows it
|
||||
// cares about: floating windows (the ones on a spare output, WL-<screens> and up), their
|
||||
// popups and dialogs, new windows, and "Float in VR" requests;
|
||||
// popups and dialogs, new windows, and requests to float or dock one;
|
||||
// - commands come back through a long poll: the script calls NextCommand, ft-floatd
|
||||
// answers when it has one (or after a while with nothing), and the script calls again.
|
||||
// KWin scripts can call D-Bus but can't serve it, hence the poll. Window ids are KWin's
|
||||
@@ -104,8 +104,26 @@ registerUserActionsMenu(w => {
|
||||
triggered: () => requestFloat(w)
|
||||
};
|
||||
});
|
||||
registerShortcut("Frametop Float Window", "Frametop: Float Window in VR (or put it back)", "Meta+Shift+F",
|
||||
() => requestFloat(workspace.activeWindow));
|
||||
// The float key is the input relay's (float_toggle, Meta+Shift+F by default): it reaches us as
|
||||
// "request-pointer". No shortcut of KWin's own, so one press can't float a window and dock it again.
|
||||
|
||||
// The window under KWin's pointer (where the 3D mouse or a laser last was on a panel): the top
|
||||
// one there, a popup or dialog standing for the window it belongs to. Null over the wallpaper
|
||||
// or the taskbar.
|
||||
function underPointer() {
|
||||
const p = workspace.cursorPos;
|
||||
const order = workspace.stackingOrder;
|
||||
for (let i = order.length - 1; i >= 0; --i) {
|
||||
const w = order[i];
|
||||
if (w.deleted || w.minimized || w.hidden || !w.managed) continue;
|
||||
const g = w.frameGeometry;
|
||||
if (p.x < g.x || p.y < g.y || p.x >= g.x + g.width || p.y >= g.y + g.height) continue;
|
||||
let top = w;
|
||||
for (let n = 0; top.transientFor && n < 10; ++n) top = top.transientFor;
|
||||
return top.normalWindow && !top.popupWindow ? top : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function run(c) {
|
||||
const w = c.id ? byId(c.id) : null;
|
||||
@@ -140,9 +158,12 @@ function run(c) {
|
||||
case "info":
|
||||
if (w) report("window", w);
|
||||
break;
|
||||
case "request-active": // ft-float float|dock active: like the shortcut
|
||||
case "request-active": // ft-float float|dock active
|
||||
requestFloat(workspace.activeWindow);
|
||||
break;
|
||||
case "request-pointer": // the float key: the window under the pointer, else the active one
|
||||
requestFloat(underPointer() || workspace.activeWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
"""ft-float: talk to ft-floatd (floating windows in the Frametop desktop).
|
||||
|
||||
ft-float float [ID|active] float a window (default: the active one; for it, a toggle)
|
||||
ft-float float pointer the float key: float the window under the pointer (else the
|
||||
active one), or put it back if it floats
|
||||
ft-float dock [ID|active] put a floating window back on the desktop
|
||||
ft-float dock all put every floating window back
|
||||
ft-float close ID close a window
|
||||
ft-float list the spare outputs and what floats on them
|
||||
FT_FLOAT_SOCKET names ft-floatd's socket (default frametop_float).
|
||||
|
||||
+18
-1
@@ -11,7 +11,9 @@ which window floats on which spare output and panel, and connects three parts:
|
||||
- kscreen-doctor, to turn spare outputs on and off and place them in KWin's layout.
|
||||
Commands and ft-screens' events arrive as datagrams on @frametop_float (ft-float is the
|
||||
command-line side). Replies go to the sender:
|
||||
float [ID|active] dock [ID|active] close ID list quit (ft-float)
|
||||
float [ID|active|pointer] dock [ID|active|all] close ID list quit (ft-float)
|
||||
("float pointer" is the float key: the window under the pointer, else the active one,
|
||||
floated or docked; the input relay sends it for float_toggle, and "dock all" for dock_all)
|
||||
dock N | close N | resize N W H | scale N STEPS (ft-screens, N = its screen)
|
||||
|
||||
Spare outputs are WL-<screens> .. WL-<screens + slots - 1>. A floating window's output is its
|
||||
@@ -197,6 +199,14 @@ class Daemon:
|
||||
raise RuntimeError("KWin didn't load the script")
|
||||
bus.get_object("org.kde.KWin", f"/Scripting/Script{sid}").run(dbus_interface="org.kde.kwin.Script")
|
||||
log(f"script loaded ({sid})")
|
||||
# Older scripts registered the float key with KWin; the input relay owns it now. Drop
|
||||
# that shortcut, so System Settings doesn't list one that does nothing.
|
||||
try:
|
||||
accel = dbus.Interface(bus.get_object("org.kde.kglobalaccel", "/kglobalaccel"), "org.kde.KGlobalAccel")
|
||||
if accel.unregister("kwin", "Frametop Float Window"):
|
||||
log("dropped KWin's old float shortcut")
|
||||
except dbus.DBusException:
|
||||
pass
|
||||
|
||||
# ------------------------------------------------------------ events from the script
|
||||
|
||||
@@ -520,6 +530,13 @@ class Daemon:
|
||||
if cmd in ("float", "dock") and (not rest or rest[0] == "active"):
|
||||
self.command(cmd="request-active")
|
||||
return "ok"
|
||||
if cmd == "float" and rest == ["pointer"]:
|
||||
self.command(cmd="request-pointer")
|
||||
return "ok"
|
||||
if cmd == "dock" and rest == ["all"]:
|
||||
for f in list(self.floats.values()):
|
||||
self.dock(f)
|
||||
return "ok"
|
||||
if cmd in ("dock", "close", "resize", "scale") and rest and rest[0].isdigit():
|
||||
f = self.by_panel(int(rest[0]))
|
||||
if not f:
|
||||
|
||||
Reference in new issue
Block a user