最近想自己写个gnome-shell扩展找到了下面两个教程
GNOME 3.0 and 3.1 Shell Extensions
More GNOME Shell Customization
这是两篇2011年的 gnome3.0 和 3.1 的教程,相信很多开发 gnome-shell 扩展的朋友也看见过这两篇教程吧,我现在用的是3.18,我想差不了太多的,毕竟都是 gnome 3,我便照着这两个教程开发,没想到这就是我开发 gnome-shell 扩展噩梦的开始。。。。。
为什么我的扩展就运行不起来呢,只好又在 github 上看了好多扩展的代码,终于发现了
main( ) 函数不再是程序入口了!!!
main( ) 函数不再是程序入口了!!!
main( ) 函数不再是程序入口了!!!
于是只能按照模板提供的方式开发扩展,上面的教程的代码根本运行不起来,求我心理阴影面积。。。
好了,吐槽完了开始正式讲讲 gnome 现在开发的基本结构,其实变化也没用太大只是把以前的 main( ) 拆成了三个函数分别是 init( ),enable( ),disable( ),上面两篇教程还是很值得学习的,只要会 JavaScript 和 GObject 五分钟就能学会开发 gnome-shell 扩展
另外我的/usr/share/gnome-shell/
里为什么死活找不到./js/ui
这个文件夹呀,连./js
都没有。。。。如果你也找不到请移步这里,找各个组件的名字属性什么的就全靠它了
首先创建一个 gnome-shell-extension 模板,输入如下命令
# gnome-shell-extension-tool -c
就会在$HOME/.local/share/gnome-shell/extensions
下创建一个模板扩展,里面有三个文件
先上 extension.js 的代码
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
let text, button;
function _hideHello() {
Main.uiGroup.remove_actor(text);
text = null;
}
function _showHello() {
if (!text) {
text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
Main.uiGroup.add_actor(text);
}
text.opacity = 255;
let monitor = Main.layoutManager.primaryMonitor;
text.set_position(monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
Tweener.addTween(text,
{ opacity: 0,
time: 2,
transition: 'easeOutQuad',
onComplete: _hideHello });
}
function init() {
button = new St.Bin({ style_class: 'panel-button',
reactive: true,
can_focus: true,
x_fill: true,
y_fill: false,
track_hover: true });
let icon = new St.Icon({ icon_name: 'system-run-symbolic',
style_class: 'system-status-icon' });
button.set_child(icon);
button.connect('button-press-event', _showHello);
}
function enable() {
Main.panel._rightBox.insert_child_at_index(button, 0);
}
function disable() {
Main.panel._rightBox.remove_child(button);
}
扩展运行如图,每点一次右上角的齿轮图标就会闪现一下 Hello,world!
分析上面的代码,可以看出整个扩展结构其实比一个main( ) 函数变得更清晰了,enable( ) 函数负责构造,init( ) 函数负责初始化,disable( ) 函数负责构析,而看了官方代码后发现,这并不是正确编写扩展的姿势,正确姿势应该是用 lang.class 实现,修改后的代码如下
const Lang = imports.lang;
const St = imports.gi.St;
const Main = imports.ui.main;
const Atk = imports.gi.Atk;
const PanelMenu = imports.ui.panelMenu;
const Tweener = imports.ui.tweener;
const extensionName = "hello,world!";
const extension = new Lang.Class({
Name : extensionName,
Extends : PanelMenu.Button,
_init : function() {
this.parent(null,extensionName);
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
this._text = null;
this._icon = new St.Icon({ icon_name: 'system-run-symbolic',
style_class: 'system-status-icon' });
this.actor.add_child(this._icon);
this.actor.connect('button-press-event', Lang.bind(this, this._showHello));
},
_hideHello : function () {
Main.uiGroup.remove_actor(this._text);
this._text = null;
},
_showHello : function () {
if (!this._text) {
this._text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
Main.uiGroup.add_actor(this._text);
}
this._text.opacity = 255;
let monitor = Main.layoutManager.primaryMonitor;
this._text.set_position(monitor.x + Math.floor(monitor.width / 2 - this._text.width / 2),
monitor.y + Math.floor(monitor.height / 2 - this._text.height / 2));
Tweener.addTween(this._text,
{ opacity: 0,
time: 2,
transition: 'easeOutQuad',
onComplete: this._hideHello });
}
});
let instance;
function init() {
}
function enable() {
instance = new extension();
Main.panel.addToStatusArea(extensionName, instance);
}
function disable() {
instance = null;
}
写完了就要开始调试扩展了,坑又来了,gnome 提供了一个 javascript 的解释器 gjs 但是 gnome 提供的东西不能调试自家的扩展,运行扩展会出现这样的错误
(gjs:7179): Gjs-WARNING **: JS ERROR: Error: Requiring St, version none: Typelib file for namespace 'St' (any version) not found
@/home/oxalics/.local/share/gnome-shell/extensions/hello_world@Oxalics/extension.js:3
# export UI_TYPELIB_PATH=/usr/lib/gnome-shell
也不好使,数据只在 gnome 的进程中有效
于是只有Alt+F2
输入 lg 可以进入 lookingGlass 里调试,如图
可以看见 lookGlass 的界面还是很不错的。。。。可是
错误信息竟然不显示行号
错误信息竟然不显示行号
错误信息竟然不显示行号
多么反人类的设计啊,于是我有找到种调试方法,见这里。。。可是
GNOME 不崩溃没有错误信息
GNOME 不崩溃没有错误信息
GNOME 不崩溃没有错误信息
我现在很好奇 gnome 的工程师是怎么调试程序的。。。。我的经验就是不停地 try catch 不停的用 Gio 往终端输出信息,这样勉强能定位错误。
经过大概三天的折腾,在几乎官方资料为零(过期资料还不如零呢~~~),终于开发扩展走上正轨了,我把我踩过的雷都写在这里,这些资料足够让你顺利开始开发 gnome-shell 扩展了,也希望后人少走些弯路吧