通過了半個月的摸爬滾打,總算在寫GNOME插件上走上了點正軌。這篇文章雖然是指南,其實就是一些抱怨(笑)javascript
首先說說GNOME Extension是什麼來的。html
2011年,GNOME釋放了萬衆期待的大版本更新GNOME 3。據wiki描述,這個萬衆期待的大版本氣得Linus Torvalds投向了xfce,而且把GNOME開發組狠狠地罵了一頓。不過在GNOME 3這麼迭代了幾個版本以後,他又用回了GNOME。前端
而GNOME Extension就是GNOME 3開始的,一種更加開放自由的方式提供給用戶tweak本身的工做環境的方式。GNOME 3的桌面環境稱做GNOME Shell,它負責Top Bar,還有Activites,Workspaces。整個GNOME Shell是由一種Javascript方言GJS和一大堆GTK+庫Binding寫成的。java
前端開發的同窗都知道,不管一個網頁寫成什麼樣子,我只要在控制檯輸入幾行js代碼,就能夠魔改這個網頁,也即沒有所謂名字保護機制,任何部分均可以自由訪問。GNOME Shell天然也是這樣,因此每個插件上傳都須要至關長的時間由工做人員Review以後才能釋出。node
在終端輸入gjs
,你就能夠開始用一個由GNOME傾情提供的js解釋器了:git
$ gjs gjs> print("Hello World!"); Hello World! gjs> const Gtk = imports.gi.Gtk; gjs> const GLib = imports.gi.GLib; gjs> Gtk.init(null); gjs> let mainloop = new GLib.MainLoop(null, null); gjs> let w = new Gtk.Window(); gjs> w.show_all(); gjs> mainloop.run();
在你打完最後一句以後,應該會出來一個小窗口兒了。github
是否是有一種勝券在握的感受。有了這個gjs感受能夠扔掉nodejs了(二者使用的JS引擎不一樣,nodejs和QML使用Google的V8,而GJS使用Mozilla的SpiderMonkey,這兩家真是世仇啊哈哈),甚至還能夠10行之內開發Native GUI,還可使用由GTK+提供的全部庫!是否是很爽。其實噩夢纔剛剛開始。`shell
首先,你碰到的第一個問題就是。你根本找不到文檔。這麼著名的GNOME項目竟然連文檔都沒有怎麼可能。你不死心地Google了半天,只找到了一些零零散散的文檔。這時你會在Stackoverflow看到有人問GJS的文檔在哪裏,答案就是很無奈的:你想一次過拿到一份完整的文檔,是不可能的了(笑)。挖槽!編程
下面公佈真相。能用的文檔有兩個:segmentfault
Seed Documentation: https://www.roojs.com/seed/gi...
Official GCampagna Documentation: https://people.gnome.org/~gca...
第一個是非官方的Seed文檔,看起來還不錯(Seed是GJS的一個兄弟,功能幾乎同樣,可是分開維護,老實說你們對此都很懵逼)。第二個是官方文檔,看起來……喵喵喵喵喵????? 這也太隨便了吧老實說。不過幸虧還能用。總的來講就是。用到GTK家族的庫的時候,以第二份爲準,第一份備用參考(由於第二份很是不全),有時還要參考一下GTK+的C文檔以瞭解詳細狀況。
接下來另外一個問題就是,怎麼跟這該死的GNOME Shell互動了。上面兩份文檔裏面都不包含任何GNOME的內容。可能還有很多人不知道GNOME和GTK+和GLib這些東西的關係。這種東西要認真糾結起來簡直麻煩到上天。它們是這樣的關係:
GLib是GTK+的一部分,用於在C上面布建一個面向對象編程和反射的架構(GObject)。
GTK+則是一個以界面庫爲中心的一大堆實用庫,包括GLib, Gio, GTK,一開始是給GIMP作界面用的。咱們平時用+來代替「家」,好比Vocaloid=V+。不知是什麼心有靈犀,總之GTK+就是整個這個實用庫家族。更正:這個家族的庫官方又稱做GNOME平臺庫。
GTK(沒有+)就是正真正銘的界面庫了,按鈕文本框標籤什麼的。更正:GTK是一個古老的界面庫。GTK+同時也特指這一個界面庫。僅爲了區分,下面我全部的文字,但凡帶+的,都是指整個家族,不帶+的,都是特指這個界面庫。
GNOME Foundation/GNOME Project後來相中了GTK+用它來開發桌面環境,後來把順便它歸入了本身旗下。如今GNOME基金會是GTK+老爸。
GNOME,本文特指GNOME 3,主要是指一個桌面環境(GNOME Shell)和一些應用程序(好比Nautilus,GNOME Terminal)。不帶歧義時不少時候特指桌面環境。GNOME 2是徹底的C/C++寫(libgnomeui),後來發展出了GObject Introspection、Vala和GJS這些基於GObject體系的東西,這樣方便起見GNOME Shell很多業務邏輯就用腳本語言寫了。
GNOME Shell的文檔在哪兒呢?答案就是沒有。也就是說,你必須去閱讀GNOME Shell的代碼。從 https://github.com/GNOME/gnom... 把代碼下載下來讀吧。所幸它的代碼寫得挺容易讀,因此也不是件壞事。
其它的資料參考:
有點過期的教程:https://wiki.gnome.org/Projec...
一個有點過期可是至關有指導意義的Blog(請自備雲梯):http://mathematicalcoffee.blo...
爲了方便調試GNOME很善意地提供了一個Looking Glass來做爲GNOME的控制檯。按<Alt-F2>
運行lg
便可進入。很惋惜這個東西不是通常的難用。進入了lg以後其它部分就不能再動了,因此你也不能開着它一遍寫一遍調試。你也不能一大段代碼複製進去運行。可能有人會問剛纔不是有個gjs
能在終端跑麼,可是那個東西沒辦法干預到GNOME,由於它單單就是一個解釋器,GNOME是運行在別的進程怎麼可能能夠訪問。
GNOME的東西通訊都有個尿性,就是喜歡用DBus。當我用dbus-monitor監視DBus總線上的通訊時,不出所料,lg就是經過DBus發送內容給GNOME進程計算的。不過使人很惱火的是它發送的內容是加密過的,因此就不能利用了。查了一段時間資料以後,發現了一個Eval
接口:
說到DBus就不能不說D-Feet和dbus-monitor了。前者是你在茫茫接口裏尋寶的寶器,後者是用來監控DBus總線上的活動。若是你以爲什麼數據都能被監視很沒安全感,那你就應該作點公鑰加密,畢竟DBus接口作出來就是開放給公用的,包括命名管道,包括信箱也是,這些傳統的IPC都是公用的。
經過它,咱們能夠測試一些代碼,來操做GNOME了。這裏就要注意了:gnome-shell桌面跑在一個單線程,因此千萬不要做死運行可能阻塞的代碼,包括死循環,包括任何阻塞的東西,包括跑一個Gtk+窗口,這會瞬間弄崩你的GNOME。輕則service gdm restart
,重則重啓電腦才能解決。
每一次的Eval都是獨立的Scope,因此上一次Eval時產生的變量,下一次Eval的時候就沒有了。解決方法是將變量保存在global對象裏,或者不用let/var
這些定義變量,直接讓它成爲全局變量,不過小心名字污染。當你在調試的時候你可能會須要log(指global.log()
)一些信息,這些信息不會在Eval的時候直接返回給你。在:
$ journalctl -f /usr/bin/gnome-shell
能夠找到日誌。可是若是日誌太大的話你就沒這麼愉快了。我第一次打開日誌的時候,花了差很少10分鐘才尋到文件末尾,兩三年的日誌加起來總共90多萬行。用:
# journalctl --vacuum-time=2d
來將兩天以前的日誌刪除。
GNOME Shell放棄了GNOME 2時代一直在用GTK,將界面繪製全面遷移到了Clutter庫。Clutter也不是外家的東西,一樣是基於GObject,也是GNOME項目組的一員。那爲何要用它呢?由於它用OpenGL繪製界面,有硬件加速。
爲了搞清楚這些亂七八糟的項目的前因後果,從Linux的X Window開始捋一捋。不嚴謹地說,是這樣一個啓動順序:GDM首先由Systemd啓動,而後GDM也就是顯示管理器在登陸以後開啓一個X Session,而且在這個X Session運行gnome-session
會話管理器。GNOME Session會正式運行gnome-shell
,至此咱們就看到熟悉的壁紙熟悉的桌面了。
GNOME Shell的中心,也就是窗口管理器Mutter,因此這就是*utter系列的第一個出場了。窗口管理器最主要的功能就是讓X的窗口有標題欄(不知你們有沒有見過那些沒有標題欄的窗口,在重啓GNOME Shell的間隙大概能見到),因而能最大化最小化移動,還能在工做區之間轉換。在這些窗口裏面有兩個特殊的窗口:一個位於全部其它窗口的底部,它顯示一張壁紙,興許還有點圖標;還有一個位於全部其它窗口的頂層,它顯示Top Bar,Activities,Legacy Tray,興許還有iBus輸入法。
GNOME Shell做爲桌面環境和Mutter其實已經難分難解。gnome-shell加載了libmutter.so,彷佛還有一說是gnome-shell已經被開發成了Mutter的插件這樣的形式而存在,能夠看出Mutter實際上是高可定製的。總而言之,窗口管理功能交給了Mutter以後,剛纔說那兩個特殊窗口,就是靠JS寫出來的了,必定程度上咱們甚至能夠認爲GNOME Shell的本體其實也就只有那兩個特殊窗口。
這兩個特殊窗口的繪製,跟普通窗口並沒有差異,反正到最後仍是會被解釋成X11協議的顯示命令被送到X Server。因此咱們能夠自由地採用GTK,QT,或者Clutter。Clutter雖然沒有GTK的歷史長,可是也已經磨練了至關長的時間了(差很少10年了)。它引入了一個叫作Actor的概念(事實上至關於GtkWidget麼),反正也就是盒模型,同時提供了CSS樣式支持。很殘念地,咱們如今須要爲兩個界面庫維護兩套CSS了。
與GTK不一樣,Clutter自己不提供任何的控件,它只提供Actor,一個盒子。剩下的就靠你本身發揮想象力了。正如HTML自己也能夠不提供控件(雖然它提供了),你只要經過本身寫CSS和JS就能模擬出來按鈕文本框標籤。固然,這些事情不用咱們本身作,Shell Toolkit(ST)已經幫咱們封裝好了一堆經常使用的控件。
不管是作什麼,GNOME的動向都是方向明確的。它想要把一切都換成自家的,換成帶硬件加速的,包括Xorg,也要換成Wayland。
就先抱怨到這裏吧w。水平有限,如有紕漏歡迎指出。
在這裏還要感謝 @mengzhuo 先生對插件的高效審校。