Gnome shell 扩展登录回调

Posted

技术标签:

【中文标题】Gnome shell 扩展登录回调【英文标题】:Gnome shell extension login callback 【发布时间】:2021-12-24 07:14:32 【问题描述】:

我创建了一个自定义 GJS 扩展来连接到 ***。基本上它是一个外壳脚本的包装器,由任务栏控制。有一个问题,PC进入挂起模式并返回后,扩展仍然显示,即断开连接,而它仍然连接。

const GObject = imports.gi.GObject;
const St = imports.gi.St;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;

const Gettext = imports.gettext;
const _ = Gettext.gettext;

const Me = imports.misc.extensionUtils.getCurrentExtension();
const MainLoop = imports.mainloop;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;

let close_connection = `
    pkexec kill -SIGINT $(pidof openconnect) 2>&1
`;

let create_connection = `
    trap clean SIGINT
    clean() 
        pkexec kill -SIGINT $(pidof openconnect) 2>&1
    

    ***-ura-pke &
    wait
`;

let _icon;
let _connectionSwitch;
let _last_connection = false;
let _already_running = false;
let _proc = null;

const iconsState = [
    'network-***-acquiring-symbolic', // disconnected
    'network-***-symbolic' // connected
];

function setConnectionState(connected) 
    // prevent same notification changing
    if (_last_connection == connected) return;

    _icon.icon_name = iconsState[connected ? 1 : 0];
    Main.notify('*** URA', (connected ? 'connected' : 'disconnected'));
    _last_connection = connected;


// read line callback
function onProcLine(stream, result) 
    try 
        let line = stream.read_line_finish_utf8(result)[0];

        if (line !== null) 
            // process read line
            log("onProcLine:" + line);
            // check connection status
            if (line.includes('Connected as ')) setConnectionState(true);
            else if(line.includes('Logout successful')) setConnectionState(false);

            stream.read_line_async(0, null, onProcLine.bind(this));
        
     catch (ex) 
        logError(ex);
    


// exec async process
async function execCheck(argv) 
    _proc = new Gio.Subprocess(
        argv: argv,
        flags: (Gio.SubprocessFlags.STDIN_PIPE |
            Gio.SubprocessFlags.STDOUT_PIPE |
            Gio.SubprocessFlags.STDERR_PIPE)
    );
    _proc.init(null);

    try 
        let stdoutStream = new Gio.DataInputStream(
            base_stream: _proc.get_stdout_pipe()
        );

        stdoutStream.read_line_async(
            GLib.PRIORITY_DEFAULT,
            null,
            onProcLine.bind(this)
        );

        _proc.wait_check_async(null, (_proc, res) => 
            try 
                if (!_proc.wait_check_finish(res)) 
                    let status = _proc.get_exit_status();
                    setConnectionState(false);

                    if (status != 0) 
                        throw new Gio.IOErrorEnum(
                            code: Gio.io_error_from_errno(status),
                            message: GLib.strerror(status)
                        );
                    
                
             catch (ex) 
                setConnectionState(false);
                logError(ex);
             finally 
                _connectionSwitch.setToggleState(false);
            
        );
     catch (ex) 
        logError(ex);
    


const Indicator = GObject.registerClass(
class Indicator extends PanelMenu.Button 
    toggleConnection(enabled) 
        if (enabled) 
            log("enable connection");
            // start process
            execCheck([
                'bash',
                '-c',
                create_connection]
            );
         else 
            log("disable conenction");
            // close running process
            if (_proc) _proc.send_signal(2);
            else if (_already_running) 
                // kill process
                Gio.Subprocess.new([
                    'bash',
                    '-c',
                    close_connection],
                    Gio.SubprocessFlags.STDOUT_PIPE
                );
                _already_running = false;
                setConnectionState(false);
            
        
    

    _init() 
        super._init(0.0, _('*** URA'));

        // set icon
        _icon = new St.Icon(
            icon_name: iconsState[0],
            style_class: 'system-status-icon'
        );
        this.add_child(_icon);

        // toggle connection
        _connectionSwitch = new PopupMenu.PopupSwitchMenuItem('Connection', false);
        _connectionSwitch.connect('toggled', (_item, state) => 
            this.toggleConnection(state);
        );
        this.menu.addMenuItem(_connectionSwitch);

        // check if process is not already running
        let [, , , status] = GLib.spawn_command_line_sync('pidof openconnect');
        if (status == 0) 
            _already_running = true;
            _connectionSwitch.setToggleState(true);
            setConnectionState(true);
        
   
);

class Extension 
    constructor(uuid) 
        this._uuid = uuid;
    

    enable() 
        _already_running = false;

        this._indicator = new Indicator();
        Main.panel.addToStatusArea(this._uuid, this._indicator, 1);
    

    disable() 
        _proc = null;

        _connectionSwitch = null;
        _last_connection = false;

        _icon.destroy();
        _icon = null;

        this._indicator.destroy();
        this._indicator = null;
    


function init(meta) 
    return new Extension(meta.uuid);

即使我添加了一个案例,我试图使用 pidof 来检测进程是否已经在运行。它只捕获了从扩展外部启动进程的情况,但没有捕获我想要的情况。

如何绑定到回调,当会话恢复时触发?或者有什么其他方法可以解决这个问题?

谢谢, 安迪

【问题讨论】:

【参考方案1】:

我也尝试为同样的目的编写一个基本的 gnome 扩展。 作为 gjs 编码的新手,我在研究中找到了有关连接更新的答案。 希望其中一些对您有所帮助:

Util.spawnCommandLine does not work on GNOME Shell extension

How to get OS name while writing gnome-extensions

GLib run command with root privileges

Running an asynchronous function in a GNOME extension

【讨论】:

以上是关于Gnome shell 扩展登录回调的主要内容,如果未能解决你的问题,请参考以下文章

不容错过这十款 GNOME Shell 扩展

不容错过这十款 GNOME Shell 扩展

如何将字符串发送到 gnome-shell 扩展?

GNOME Shell 集成扩展正在运行,未检测到本机主机连接器?

GNOME-shell 扩展件(extensions)的安装方法

修改gnome-shell扩展“Applications Menu”的菜单区域宽度。