feat: add evil bit support
This commit is contained in:
parent
da72bc5483
commit
d6f032e52e
4 changed files with 239 additions and 0 deletions
151
gnome-extensions/evil-bit-toggle/extension.js
Normal file
151
gnome-extensions/evil-bit-toggle/extension.js
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as QuickSettings from 'resource:///org/gnome/shell/ui/quickSettings.js';
|
||||
|
||||
const EVIL_BIT_CTL = '@evilBitCtl@';
|
||||
const PKEXEC = '/run/wrappers/bin/pkexec';
|
||||
const STATE_FILE = '/run/evil-bit-toggle/enabled';
|
||||
const ICON_NAME = 'dialog-warning-symbolic';
|
||||
|
||||
const EvilBitToggle = GObject.registerClass(
|
||||
class EvilBitToggle extends QuickSettings.QuickToggle {
|
||||
constructor() {
|
||||
super({
|
||||
title: 'Evil Bit',
|
||||
subtitle: 'RFC 3514: good',
|
||||
iconName: ICON_NAME,
|
||||
toggleMode: true,
|
||||
});
|
||||
|
||||
this._syncing = false;
|
||||
this._pending = false;
|
||||
this._destroyed = false;
|
||||
this._syncFromState();
|
||||
|
||||
this._checkedId = this.connect('notify::checked', () => {
|
||||
if (this._syncing)
|
||||
return;
|
||||
|
||||
this._setEvilBit(this.checked);
|
||||
});
|
||||
}
|
||||
|
||||
_isEnabled() {
|
||||
return GLib.file_test(STATE_FILE, GLib.FileTest.EXISTS);
|
||||
}
|
||||
|
||||
_syncFromState() {
|
||||
this._syncing = true;
|
||||
this.checked = this._isEnabled();
|
||||
this._syncing = false;
|
||||
this._syncSubtitle();
|
||||
}
|
||||
|
||||
_setEvilBit(enabled) {
|
||||
if (this._pending)
|
||||
return;
|
||||
|
||||
this._pending = true;
|
||||
this.reactive = false;
|
||||
this.subtitle = 'Applying...';
|
||||
|
||||
const action = enabled ? 'enable' : 'disable';
|
||||
let proc;
|
||||
|
||||
try {
|
||||
proc = Gio.Subprocess.new(
|
||||
[PKEXEC, EVIL_BIT_CTL, action],
|
||||
Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE
|
||||
);
|
||||
} catch (error) {
|
||||
this._finishSetEvilBit(error);
|
||||
return;
|
||||
}
|
||||
|
||||
proc.communicate_utf8_async(null, null, (subprocess, result) => {
|
||||
try {
|
||||
const [, , stderr] = subprocess.communicate_utf8_finish(result);
|
||||
|
||||
if (!subprocess.get_successful())
|
||||
throw new Error(stderr.trim() || `evil-bitctl ${action} failed`);
|
||||
|
||||
this._finishSetEvilBit(null);
|
||||
} catch (error) {
|
||||
this._finishSetEvilBit(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_finishSetEvilBit(error) {
|
||||
if (error)
|
||||
console.warn(`Unable to toggle Evil Bit: ${error.message}`);
|
||||
|
||||
if (this._destroyed)
|
||||
return;
|
||||
|
||||
this._pending = false;
|
||||
this.reactive = true;
|
||||
this._syncFromState();
|
||||
}
|
||||
|
||||
_syncSubtitle() {
|
||||
this.subtitle = this.checked ? 'RFC 3514: evil' : 'RFC 3514: good';
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._destroyed = true;
|
||||
|
||||
if (this._checkedId) {
|
||||
this.disconnect(this._checkedId);
|
||||
this._checkedId = null;
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const EvilBitIndicator = GObject.registerClass(
|
||||
class EvilBitIndicator extends QuickSettings.SystemIndicator {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = ICON_NAME;
|
||||
|
||||
this._toggle = new EvilBitToggle();
|
||||
this._indicator.visible = this._toggle.checked;
|
||||
this._checkedId = this._toggle.connect('notify::checked', () => {
|
||||
this._indicator.visible = this._toggle.checked;
|
||||
});
|
||||
|
||||
this.quickSettingsItems.push(this._toggle);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._checkedId) {
|
||||
this._toggle.disconnect(this._checkedId);
|
||||
this._checkedId = null;
|
||||
}
|
||||
|
||||
this.quickSettingsItems.forEach(item => item.destroy());
|
||||
this._toggle = null;
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
export default class EvilBitToggleExtension extends Extension {
|
||||
enable() {
|
||||
this._indicator = new EvilBitIndicator();
|
||||
Main.panel.statusArea.quickSettings.addExternalIndicator(this._indicator);
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._indicator.destroy();
|
||||
this._indicator = null;
|
||||
}
|
||||
}
|
||||
6
gnome-extensions/evil-bit-toggle/metadata.json
Normal file
6
gnome-extensions/evil-bit-toggle/metadata.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"uuid": "evil-bit-toggle@jetpham.github.com",
|
||||
"name": "Evil Bit Toggle",
|
||||
"description": "Adds a Quick Settings toggle for the RFC 3514 evil bit.",
|
||||
"shell-version": ["49"]
|
||||
}
|
||||
|
|
@ -182,6 +182,7 @@ in
|
|||
"appindicatorsupport@rgcjonas.gmail.com"
|
||||
"gnome-shell-extension-maximized-by-default@stiggimy.github.com"
|
||||
"no-titlebar-when-maximized@alec.ninja"
|
||||
"evil-bit-toggle@jetpham.github.com"
|
||||
"reduced-motion-toggle@jetpham.github.com"
|
||||
];
|
||||
favorite-apps = favoriteApps;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,68 @@
|
|||
}:
|
||||
|
||||
let
|
||||
evilBitCtl = pkgs.writeShellApplication {
|
||||
name = "evil-bitctl";
|
||||
runtimeInputs = [
|
||||
pkgs.coreutils
|
||||
pkgs.nftables
|
||||
];
|
||||
text = ''
|
||||
state_dir=/run/evil-bit-toggle
|
||||
state_file="$state_dir/enabled"
|
||||
table=evil_bit
|
||||
chain=output
|
||||
|
||||
usage() {
|
||||
printf 'Usage: evil-bitctl {enable|disable|status}\n' >&2
|
||||
exit 64
|
||||
}
|
||||
|
||||
enable() {
|
||||
nft add table ip "$table" 2>/dev/null || true
|
||||
|
||||
if nft list chain ip "$table" "$chain" >/dev/null 2>&1; then
|
||||
nft flush chain ip "$table" "$chain"
|
||||
else
|
||||
nft add chain ip "$table" "$chain" '{ type route hook output priority mangle; policy accept; }'
|
||||
fi
|
||||
|
||||
nft add rule ip "$table" "$chain" ip frag-off set ip frag-off '|' 0x8000
|
||||
install -d -m 0755 "$state_dir"
|
||||
touch "$state_file"
|
||||
}
|
||||
|
||||
disable() {
|
||||
nft delete table ip "$table" 2>/dev/null || true
|
||||
rm -f "$state_file"
|
||||
rmdir "$state_dir" 2>/dev/null || true
|
||||
}
|
||||
|
||||
status() {
|
||||
if [ -e "$state_file" ] && nft list table ip "$table" >/dev/null 2>&1; then
|
||||
printf 'enabled\n'
|
||||
else
|
||||
printf 'disabled\n'
|
||||
fi
|
||||
}
|
||||
|
||||
case "''${1:-}" in
|
||||
enable)
|
||||
enable
|
||||
;;
|
||||
disable)
|
||||
disable
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
reducedMotionToggleExtension = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "gnome-shell-extension-reduced-motion-toggle";
|
||||
version = "1";
|
||||
|
|
@ -20,6 +82,24 @@ let
|
|||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
|
||||
evilBitToggleExtension = pkgs.stdenvNoCC.mkDerivation {
|
||||
pname = "gnome-shell-extension-evil-bit-toggle";
|
||||
version = "1";
|
||||
src = ../gnome-extensions/evil-bit-toggle;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
substituteInPlace extension.js \
|
||||
--replace-fail @evilBitCtl@ ${evilBitCtl}/bin/evil-bitctl
|
||||
|
||||
mkdir -p "$out/share/gnome-shell/extensions/evil-bit-toggle@jetpham.github.com"
|
||||
cp -r . "$out/share/gnome-shell/extensions/evil-bit-toggle@jetpham.github.com"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
|
|
@ -105,6 +185,7 @@ in
|
|||
gnomeExtensions.system-monitor-next
|
||||
gnomeExtensions.tailscale-qs
|
||||
gnomeExtensions.wifi-qrcode
|
||||
evilBitToggleExtension
|
||||
reducedMotionToggleExtension
|
||||
|
||||
nerd-fonts.commit-mono
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue