如何解决在 GTK/GJS 应用和 Gnome Shell 扩展之间共享代码
我正在 GJS 中开发 GTK 应用程序,并且喜欢重用 GTK 的一部分
Gnome Shell 扩展中的代码。但是,我没有找到添加
Gtk.Widget
到我的 Gnome Shell 面板图标的菜单。
我尝试使用 Gtkclutter.Actor
中的 clutter-gtk
,但图书馆似乎
已经过时并且在 Wayland 或 X11 Gnome Shell 中都不起作用,因为它
需要 clutter 1.0
但看到 7
已加载。导入时
imports.gi.Gtkclutter
在扩展中,Gnome Shell 产生此错误:
Requiring Gtkclutter,version none: Requiring namespace 'clutter' version '1.0',but '7' is already loaded
。
这里有一些代码来证明 clutter-gtk
实际上有效,如果直接
通过 gjs
运行它;可能是因为我可以在这里强制执行 GTK 3.0。
gtkclutter.js:
imports.gi.versions.Gtk = '3.0' // fails if set to 4.0
const { Gtk,GLib,clutter,Gtkclutter } = imports.gi
// gtkUI returns a Gtk.Widget tree. This should be the reusable code.
function gtkUI() {
return new Gtk.Label({
label: '<span size="100000">?</span>',use_markup: true,})
}
// embedclutterActor returns a Gtk.Widget with an embedded clutter.Actor.
function embedclutterActor(clutter_actor) {
let embed = new Gtkclutter.Embed()
embed.get_stage().add_child(clutter_actor)
return embed
}
// embedGtkWidget returns a clutter.Actor with an embedded Gtk.Widget.
function embedGtkWidget(gtk_widget) {
return new Gtkclutter.Actor({ contents: gtk_widget })
}
class App {
constructor() {
this.title = 'Gtkclutter'
GLib.set_prgname(this.title)
}
onActivate() { this.window.show_all() }
onStartup() { this.buildUI() }
run(ARGV=[]) {
this.app = new Gtk.Application()
this.app.connect('activate',() => this.onActivate())
this.app.connect('startup',() => this.onStartup())
this.app.run(ARGV)
}
buildUI() {
let w = this.window = new Gtk.applicationwindow({
application: this.app,title: this.title,icon_name: 'face-smile',default_height: 160,default_width: 160,window_position: Gtk.WindowPosition.CENTER,})
// Just to demonstrate that Gtkclutter embedding works,we use both embeds here to create
// a Gtk.Widget from a clutter.Actor from the actual Gtk.Widget that we want to show.
Gtkclutter.init(null)
clutter.init(null)
w.add(embedclutterActor(embedGtkWidget(gtkUI())))
// In the actual GTK App,we would just have used `w.add(gtkUI())`
// and not imported clutter and Gtkclutter at all.
}
}
new App().run(ARGV)
这是 GTK 应用程序的配套扩展,尝试(但失败)
将 GTK 代码重用为 contents
的 Gtkclutter.Actor
。
extension.js:
const { clutter,Gtk,Gio,St } = imports.gi
let Gtkclutter = null // lazy import for debugging
const Main = imports.ui.main
const PanelMenu = imports.ui.panelMenu
const PopupMenu = imports.ui.popupMenu
const Me = imports.misc.extensionUtils.getCurrentExtension()
const VERSION = 'dev-version' // filled during install
const NAME = 'GtkclutterExt'
// gtkUI returns a Gtk.Widget tree. This should be the reusable code.
function gtkUI() {
return new Gtk.Button({ child: Gtk.Label({
label: `<span size="100000">?</span>`,})})
}
// stUI returns an Gnome Shell widget tree that works only in Gnome Shell.
function stUI(icon_name='face-sad') {
return new St.Icon({ icon_name })
}
function statusIcon(icon_name) {
let Box = new St.BoxLayout()
let icon = new St.Icon({ icon_name,style_class: 'system-status-icon emotes-icon' })
Box.add_child(icon)
Box.add_child(PopupMenu.arrowIcon(St.Side.BottOM))
return Box
}
class Ext {
constructor() { this.panel_widget = null }
enable() {
log(`enabling extension ${Me.uuid}`)
try {
// Use St only for the status icon and the menu container (not the menu content).
let btn = this.panel_widget = new PanelMenu.Button(0.0,NAME,false)
let item = new PopupMenu.PopupBaseMenuItem({ reactive: false,can_focus: false })
btn.menu.addMenuItem(item)
Main.panel.addToStatusArea(NAME,btn)
try { Gtkclutter = imports.gi.Gtkclutter }
catch (e) { log(`Failed to load clutter-gtk,err=${e.message}`) }
if (Gtkclutter) {
// Using St for the status icon is OK,since it is only used by the extension.
btn.add_child(statusIcon('face-happy'))
// But for the menu,I like to reuse my GTK code from the GTK app.
// That is what Gtkclutter was designed for,I believe.
item.actor.add_child(new Gtkclutter.Actor({ contents: gtkUI() }))
} else {
// As fallback we show our mood regarding Gtkclutter support in Gnome Shell ;)
btn.add_child(statusIcon('face-sad'))
item.actor.add_child(stUI('face-angry'))
}
} catch (e) {
log(`Failed to enable ${Me.uuid},err=${e.message}`)
}
}
disable() {
debug(`disabling extension ${Me.uuid}`)
if (this.panel_widget == null) return
this.panel_widget.destroy()
this.panel_widget = null
}
}
function init() { return new Ext() }
我知道 clutter-gtk
已经过时了(参见 https://gitlab.gnome.org/GNOME/clutter-gtk),
但我没有找到更好的方法将 GTK 提升到我的扩展中。
问题
- Gnome Shell 是否提供类似于
Gtkclutter.Actor
的东西,允许 扩展程序员重用他们的 GJS/GTK 代码? - 您认为重用 GTK/GJS 代码的替代方法是什么?
- 如果 GTK 是一个通用的跨平台库,为什么 Gnome Shell 没有 支持开箱即用? (额外问题?,更多是出于好奇)
解决方法
TL;DR您不能在 GNOME Shell 扩展中使用 GTK 小部件。
GNOME Shell 中使用的工具包是 Clutter,而不是 GTK。 Clutter 是 Mutter 的内部库,而 GTK3 仅在 GNOME Shell 中用于少数实用程序。
Clutter 曾经是一个独立的库,但现在专门作为 Mutter 的合成器工具包开发。 GTK 是一个应用程序工具包,不适合在合成器中使用。
独立的 Clutter 项目现在实际上是无人维护的,这使得 GtkClutter 几乎没有变化。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。