wip
parent
df448b68af
commit
82077fc12a
|
|
@ -0,0 +1 @@
|
|||
export {}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "gnome-shell-extension-clash-indicator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "rollup -c",
|
||||
"build:dev": "rollup -c --environment DEBUG",
|
||||
"test": "sh test.sh",
|
||||
"push": "sh push.sh"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@9.3.0+sha512.ee7b93e0c2bd11409c6424f92b866f31d3ea1bef5fbe47d3c7500cdc3c9668833d2e55681ad66df5b640c61fa9dc25d546efa54d76d7f8bf54b13614ac293631",
|
||||
"devDependencies": {
|
||||
"@girs/clutter-14": "14.0.0-4.0.0-beta.5",
|
||||
"@girs/gio-2.0": "2.78.0-3.3.0",
|
||||
"@girs/gjs": "^3.3.0",
|
||||
"@girs/glib-2.0": "2.78.0-3.3.0",
|
||||
"@girs/gnome-shell": "46.0.0-beta8",
|
||||
"@girs/gobject-2.0": "2.78.0-3.3.0",
|
||||
"@girs/gtk-4.0": "4.12.5-3.3.0",
|
||||
"@girs/soup-3.0": "3.4.4-3.3.0",
|
||||
"@girs/st-14": "14.0.0-4.0.0-beta.5",
|
||||
"@rollup/plugin-commonjs": "^26.0.1",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"rimraf": "^5.0.7",
|
||||
"rollup": "^4.18.0",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"rollup-plugin-tsconfig-paths": "^1.5.2",
|
||||
"rollup-plugin-typescript2": "^0.36.0"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
ln -s ${PWD}/dist/ ${HOME}/.local/share/gnome-shell/extensions/clash-indicator@indusy.gmail.com
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// @ts-check
|
||||
|
||||
import { defineConfig } from "rollup";
|
||||
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import nodeResolve from "@rollup/plugin-node-resolve";
|
||||
import json from "@rollup/plugin-json";
|
||||
import terser from "@rollup/plugin-terser";
|
||||
import typescript from "rollup-plugin-typescript2";
|
||||
import copy from "rollup-plugin-copy";
|
||||
import tsconfigPaths from 'rollup-plugin-tsconfig-paths'
|
||||
|
||||
/** @type {(options: {matches: RegExp[]}) => import("rollup").Plugin} */
|
||||
const excludeImports = (options) => {
|
||||
const matches = options.matches;
|
||||
return {
|
||||
name: "exclude-imports-plugin",
|
||||
resolveId(source, importer) {
|
||||
if (importer) {
|
||||
if (matches.some((r) => r.test(source))) {
|
||||
return {
|
||||
id: source,
|
||||
external: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const config = defineConfig(() => {
|
||||
const commonPlugs = [
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
json(),
|
||||
typescript({ check: false }),
|
||||
excludeImports({
|
||||
matches: [/^gi:/, /^resource:/],
|
||||
}),
|
||||
// @ts-ignore
|
||||
].concat(process.env.DEBUG ? null : terser(), tsconfigPaths());
|
||||
|
||||
/** @type {import('rollup').RollupOptions} */
|
||||
const extensionModule = {
|
||||
input: "src/extension.ts",
|
||||
output: {
|
||||
name: "[name].js",
|
||||
dir: "dist",
|
||||
format: "es",
|
||||
},
|
||||
plugins: [
|
||||
...commonPlugs,
|
||||
copy({
|
||||
targets: [
|
||||
{
|
||||
src: "src/metadata.json",
|
||||
dest: "dist",
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
return [extensionModule];
|
||||
});
|
||||
|
||||
export default config;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class AllowLAN extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("允许局域网连接");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
import { GLib } from "@girs/glib-2.0";
|
||||
import { Gio } from "@girs/gio-2.0";
|
||||
import * as Main from "@girs/gnome-shell/ui/main";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
import { ExtensionMetadata } from "@girs/gnome-shell/extensions/extension";
|
||||
import { getCoreVersion } from "../core";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Configure extends PopupMenu.PopupSubMenuMenuItem {
|
||||
constructor(options: { metadata: ExtensionMetadata }) {
|
||||
super("配置");
|
||||
|
||||
const separator = new PopupMenu.PopupSeparatorMenuItem();
|
||||
|
||||
this.menu.addAction("config", () => {});
|
||||
this.menu.addMenuItem(separator);
|
||||
this.menu.addAction("打开配置文件夹", () => {
|
||||
const file = Gio.File.new_for_path(
|
||||
`${GLib.get_user_data_dir()}/${options.metadata.uuid}`
|
||||
);
|
||||
const appInfo = Gio.AppInfo.get_default_for_type(
|
||||
file
|
||||
.query_info(
|
||||
"standard::content-type",
|
||||
Gio.FileQueryInfoFlags.NONE,
|
||||
null
|
||||
)
|
||||
.get_content_type()!,
|
||||
false
|
||||
);
|
||||
|
||||
if (appInfo) {
|
||||
appInfo.launch([file], null);
|
||||
}
|
||||
});
|
||||
this.menu.addAction("托管配置", () => {});
|
||||
|
||||
const versionIt = new PopupMenu.PopupMenuItem('点击查看版本号')
|
||||
versionIt.connect('activate', () => {
|
||||
const version = getCoreVersion();
|
||||
log(version)
|
||||
})
|
||||
this.menu.addMenuItem(versionIt)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
import * as Main from "@girs/gnome-shell/ui/main";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
import { fetch } from "../utils/fetch";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Enabler extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("启用");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Exit extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("退出");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import * as PanelMenu from "@girs/gnome-shell/ui/panelMenu";
|
||||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
import { St } from "@girs/st-14";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
import { Enabler } from "./enabler";
|
||||
import { Mode } from "./mode";
|
||||
import { ProxyEnv } from "./proxy-env";
|
||||
import { SystemProxy } from "./system-proxy";
|
||||
import { StartAtBoot } from "./start-at-boot";
|
||||
import { AllowLAN } from "./allow-lan";
|
||||
import { Configure } from "./configure";
|
||||
import { Settings } from "./settings";
|
||||
import { ExtensionMetadata } from "@girs/gnome-shell/extensions/extension";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Indicator extends PanelMenu.Button {
|
||||
metadata: ExtensionMetadata;
|
||||
constructor(options: { metadata: ExtensionMetadata }) {
|
||||
super(0.0, _("Clash Indicator"));
|
||||
this.metadata = options.metadata;
|
||||
|
||||
this.add_child(
|
||||
new St.Icon({
|
||||
icon_name: "face-smile-symbolic",
|
||||
style_class: "system-status-icon",
|
||||
})
|
||||
);
|
||||
|
||||
this.menu = this.menu as PopupMenu.PopupMenu
|
||||
|
||||
const enabler = new Enabler();
|
||||
this.menu.addMenuItem(enabler);
|
||||
|
||||
const mode = new Mode();
|
||||
this.menu.addMenuItem(mode);
|
||||
|
||||
const proxyEnv = new ProxyEnv();
|
||||
this.menu.addMenuItem(proxyEnv);
|
||||
|
||||
const systemProxy = new SystemProxy();
|
||||
this.menu.addMenuItem(systemProxy);
|
||||
|
||||
const startAtBoot = new StartAtBoot();
|
||||
this.menu.addMenuItem(startAtBoot);
|
||||
|
||||
const allowLAN = new AllowLAN();
|
||||
this.menu.addMenuItem(allowLAN);
|
||||
|
||||
const settings = new Settings();
|
||||
this.menu.addMenuItem(settings);
|
||||
|
||||
const configure = new Configure({
|
||||
metadata: this.metadata,
|
||||
});
|
||||
this.menu.addMenuItem(configure);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Mode extends PopupMenu.PopupSubMenuMenuItem {
|
||||
constructor() {
|
||||
super("出站模式");
|
||||
this.label.text = "出站模式(规则)";
|
||||
|
||||
this.menu.addAction("规则模式", () => {
|
||||
globalThis.log("修改为规则模式");
|
||||
});
|
||||
this.menu.addAction("全局模式", () => {
|
||||
globalThis.log("修改为全局模式");
|
||||
});
|
||||
this.menu.addAction("直连模式", () => {
|
||||
globalThis.log("修改为直连模式");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class ProxyEnv extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("复制环境变量");
|
||||
|
||||
this.connect("activate", () => {
|
||||
globalThis.log("复制环境变量");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class Settings extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("打开设置面板");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class StartAtBoot extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("开机启动");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as PopupMenu from "@girs/gnome-shell/ui/popupMenu";
|
||||
|
||||
import { registerGObjectClass } from "../utils/gjs";
|
||||
|
||||
@registerGObjectClass
|
||||
export class SystemProxy extends PopupMenu.PopupMenuItem {
|
||||
constructor() {
|
||||
super("系统代理");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { fetch } from "../utils/fetch";
|
||||
|
||||
function startClash() {}
|
||||
|
||||
export function getCoreVersion() {
|
||||
const dataText = fetch.get('/version')
|
||||
const {version} = JSON.parse(dataText || '{}')
|
||||
return version
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* extension.js
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import {
|
||||
Extension,
|
||||
ExtensionMetadata,
|
||||
gettext as _,
|
||||
} from "@girs/gnome-shell/extensions/extension";
|
||||
import { GLib } from "@girs/glib-2.0";
|
||||
|
||||
import * as Main from "@girs/gnome-shell/ui/main";
|
||||
import { Indicator } from "./components/indicator";
|
||||
|
||||
export default class ClashIndicatorExtension extends Extension {
|
||||
private indicator!: Indicator | null;
|
||||
constructor(metadata: ExtensionMetadata) {
|
||||
super(metadata);
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const dataDir = GLib.build_filenamev([
|
||||
GLib.get_user_data_dir(),
|
||||
this.metadata.uuid,
|
||||
]);
|
||||
|
||||
log(dataDir);
|
||||
if (!GLib.file_test(dataDir, GLib.FileTest.EXISTS)) {
|
||||
GLib.mkdir_with_parents(dataDir, 0o755);
|
||||
log(dataDir);
|
||||
}
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.indicator = new Indicator({
|
||||
metadata: this.metadata,
|
||||
});
|
||||
Main.panel.addToStatusArea(this.uuid, this.indicator);
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.indicator?.destroy();
|
||||
this.indicator = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Clash Indicator",
|
||||
"description": "A clash user interface.",
|
||||
"uuid": "clash-indicator@indusy.gmail.com",
|
||||
"shell-version": [
|
||||
"46"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Soup } from "@girs/soup-3.0";
|
||||
import { GLib } from "@girs/glib-2.0";
|
||||
|
||||
const baseUrl = "http://localhost:9097";
|
||||
|
||||
function get(url: string) {
|
||||
const session = new Soup.Session();
|
||||
|
||||
const message = Soup.Message.new("GET", baseUrl + url);
|
||||
|
||||
try {
|
||||
const dataBytes = session.send_and_read(message, null);
|
||||
const textDecoder = new TextDecoder();
|
||||
const dataText = textDecoder.decode(dataBytes.get_data()!);
|
||||
dataBytes.get_data()?.forEach((x) => {
|
||||
log(x);
|
||||
});
|
||||
|
||||
return dataText;
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
export const fetch = {
|
||||
get,
|
||||
};
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import GObject from "@girs/gobject-2.0";
|
||||
|
||||
export function registerGObjectClass<
|
||||
K,
|
||||
T extends {
|
||||
metaInfo?: GObject.MetaInfo<any, any, any>;
|
||||
new (...params: any[]): K;
|
||||
}
|
||||
>(target: T) {
|
||||
if (Object.prototype.hasOwnProperty.call(target, "metaInfo")) {
|
||||
// @ts-ignore
|
||||
return GObject.registerClass<K, T>(
|
||||
target.metaInfo!,
|
||||
target
|
||||
) as typeof target;
|
||||
} else {
|
||||
// @ts-ignore
|
||||
return GObject.registerClass<K, T>(target) as typeof target;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SignalRepresentationType<A extends any[]> {
|
||||
param_types: A;
|
||||
accumulator: number;
|
||||
}
|
||||
|
||||
export type SignalsDefinition<T extends string> = {
|
||||
[key in T]: SignalRepresentationType<any> | Record<string, never>;
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
export G_MESSAGES_DEBUG=
|
||||
export MUTTER_DEBUG_DUMMY_MODE_SPECS=1366x768
|
||||
export SHELL_DEBUG=all
|
||||
|
||||
dbus-run-session -- \
|
||||
gnome-shell --nested \
|
||||
--wayland
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"types": [
|
||||
"@girs/gjs",
|
||||
"@girs/gtk-4.0",
|
||||
"@girs/gnome-shell/extensions/global"
|
||||
]
|
||||
},
|
||||
"include": ["src", "define.d.ts"]
|
||||
}
|
||||
Loading…
Reference in New Issue