feat(settings): add grouped configuration hub, languages and tray controls

This commit is contained in:
aria committed 2026-10-28 03:37:22 +09:00
1 parent 6f34fd080f
commit cc3b6f903f
90 files changed
+3625 -408

No files matched your search

+12 -11
View File
@@ -83,7 +83,7 @@ def environment():
"IBUS_ADDRESS": "", "FERESE_SESSION_IMPORT_ENV": "0", "FERESE_ENABLE_INPUT_METHOD": "1",
"FERESE_RIME_CONTROL": str(RUNTIME / "rime-control.sock"),
"FERESE_ENABLE_TEST_POINTER": "1",
"FERESE_ENABLE_SCREENCOPY": "1", "XDG_DATA_DIRS": f"{Path.home()}/.local/share:/usr/local/share:/usr/share"}
"FERESE_ENABLE_SCREENCOPY": "1", "PATH": f"{ROOT}/target/debug:" + os.environ.get("PATH", "/usr/bin"), "XDG_DATA_DIRS": f"{Path.home()}/.local/share:/usr/local/share:/usr/share"}
values.update({f"XDG_{kind.upper()}_HOME": str(DATA / "profile" / kind) for kind in ("config", "data", "cache", "state")})
return values
@@ -131,15 +131,16 @@ def start():
RUNTIME.mkdir(mode=0o700, exist_ok=True)
if RUNTIME.stat().st_uid != os.getuid() or RUNTIME.stat().st_mode & 0o077:
raise RuntimeError("Unexpected private runtime owner or permissions")
(DATA / "profile/config/ferese/config.kdl").write_text('''
xwayland { enabled #false; }
status { keybinding-guide #false; }
window-rule app-id="dev.ferese.RimeValidation" floating=#true width=880 height=560
window-rule app-id="io.github.lgse.Strata" floating=#true width=1050 height=720
window-rule app-id="QQ" floating=#true width=1000 height=720
window-rule app-id="teams-for-linux" floating=#true width=1000 height=720
theme { typography { font-family "MiSans"; }; }
''')
if not (DATA / "profile/config/ferese/config.kdl").exists():
(DATA / "profile/config/ferese/config.kdl").write_text('''
xwayland { enabled #false; }
status { keybinding-guide #false; }
window-rule app-id="dev.ferese.RimeValidation" floating=#true width=880 height=560
window-rule app-id="io.github.lgse.Strata" floating=#true width=1050 height=720
window-rule app-id="QQ" floating=#true width=1000 height=720
window-rule app-id="teams-for-linux" floating=#true width=1000 height=720
theme { typography { font-family "MiSans"; }; }
''')
host_runtime = Path(os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}"))
host_display = Path(os.environ.get("WAYLAND_DISPLAY", "wayland-0"))
if not host_display.is_absolute():
@@ -148,7 +149,7 @@ theme { typography { font-family "MiSans"; }; }
raise RuntimeError("Parent Wayland display is missing")
env = {**environment(), "WAYLAND_DISPLAY": str(host_display), "RUST_LOG": "info"}
start_unit(MAIN, ["/usr/bin/dbus-run-session", "--", str(ROOT / "target/debug/ferese"), "--backend", "nested",
"--supervise-client", "--grant-effects", "--grant-shell-control", "--", "/usr/bin/ferese-shell"], env, "3G")
"--supervise-client", "--grant-effects", "--grant-shell-control", "--", str(ROOT / "target/debug/ferese-shell")], env, "3G")
c = wait_for(context, "Development compositor did not publish its private connection")
(DATA / "context.json").write_text(json.dumps(c, indent=2) + "\n")
start_ime()
+29
View File
@@ -0,0 +1,29 @@
// Private-session StatusNotifierItem fixture. Never sends application messages.
const {Gio,GLib}=imports.gi;
const output=ARGV[0];
const xml=`<node><interface name="org.kde.StatusNotifierItem">
<property name="Category" type="s" access="read"/><property name="Id" type="s" access="read"/>
<property name="Title" type="s" access="read"/><property name="Status" type="s" access="read"/>
<property name="WindowId" type="i" access="read"/><property name="IconName" type="s" access="read"/>
<property name="IconPixmap" type="a(iiay)" access="read"/><property name="IconThemePath" type="s" access="read"/>
<property name="OverlayIconName" type="s" access="read"/><property name="OverlayIconPixmap" type="a(iiay)" access="read"/>
<property name="AttentionIconName" type="s" access="read"/><property name="AttentionIconPixmap" type="a(iiay)" access="read"/>
<property name="AttentionMovieName" type="s" access="read"/><property name="ToolTip" type="(sa(iiay)ss)" access="read"/>
<property name="ItemIsMenu" type="b" access="read"/><property name="Menu" type="o" access="read"/>
<method name="Activate"><arg type="i" direction="in"/><arg type="i" direction="in"/></method>
<method name="SecondaryActivate"><arg type="i" direction="in"/><arg type="i" direction="in"/></method>
<method name="ContextMenu"><arg type="i" direction="in"/><arg type="i" direction="in"/></method>
<method name="Scroll"><arg type="i" direction="in"/><arg type="s" direction="in"/></method>
<signal name="NewIcon"/><signal name="NewStatus"><arg type="s"/></signal>
</interface></node>`;
let activated=0;
const pixels=Array.from({length:16*16*4},(_,i)=>[255,19,231,173][i%4]);
const item={Category:'ApplicationStatus',Id:'ferese-tray-fixture',Title:'Ferese tray fixture',Status:'Active',WindowId:0,
IconName:'',IconPixmap:[[16,16,pixels]],IconThemePath:'',OverlayIconName:'',OverlayIconPixmap:[],AttentionIconName:'',AttentionIconPixmap:[],AttentionMovieName:'',ToolTip:['',[],'Ferese tray fixture','Test icon'],ItemIsMenu:false,Menu:'/NO_DBUSMENU',
Activate(){GLib.file_set_contents(output,JSON.stringify({activated:++activated}));},SecondaryActivate(){},ContextMenu(){},Scroll(){}};
const loop=new GLib.MainLoop(null,false);
let exported;
Gio.bus_own_name(Gio.BusType.SESSION,'dev.ferese.TrayFixture',Gio.BusNameOwnerFlags.NONE,
connection=>{exported=Gio.DBusExportedObject.wrapJSObject(xml,item);exported.export(connection,'/StatusNotifierItem');},
(connection,name)=>{connection.call('org.kde.StatusNotifierWatcher','/StatusNotifierWatcher','org.kde.StatusNotifierWatcher','RegisterStatusNotifierItem',new GLib.Variant('(s)',[name]),null,Gio.DBusCallFlags.NONE,5000,null,(c,r)=>{try{c.call_finish(r);GLib.file_set_contents(output,JSON.stringify({activated,registered:true}));}catch(e){printerr(e.message);loop.quit();}});},()=>loop.quit());
loop.run();