LoginSignup
0
0

More than 1 year has passed since last update.

pygobject を使う

Last updated at Posted at 2022-11-14

GTK4 と GStreamer の資料収集。

から分けた。

GTK3 gi.require_version('Gtk', '3.0')

minimum

# gtk3
import gi

gi.require_version("Gtk", "3.0") # 👈
from gi.repository import Gtk

win = Gtk.Window()
win.connect("destroy", Gtk.main_quit) # 👈
win.show_all() # 👈
Gtk.main() # 👈

widgets

Gtk.TreeView

C言語

Gtk.DrawingArea

GLArea(OpenGL)

GTK4 gi.require_version('Gtk', '4.0')

reference

Gtk4初手にオススメ

Gtk4チュートリアル

rust の GTK4。python 向けの GTK3 より参考になるかも

Gnome向け。動かない。libadwaita

GTK3との違い

  • gi.require_version('Gtk', '3.0') => '4.0'

GTK4で無くなった

  • Gtk.main_quit
  • show_all()
  • Gtk.main()

minimum

# gtk4
import gi

gi.require_version("Gtk", "4.0")
from gi.repository import Gtk

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app)
    btn = Gtk.Button(label="Hello, World!")
    btn.connect('clicked', lambda x: win.close())
    win.set_child(btn)
    win.present()


app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)

継承方式

import gi

gi.require_version('Gtk', '4.0')
from gi.repository import Gtk


class Window(Gtk.ApplicationWindow):

    def __init__(self, app) -> None:
        super().__init__(application=app)


class Application(Gtk.Application):

    def __init__(self) -> None:
        super().__init__()

    def do_activate(self):
        win = Window(self)
        win.present()


app = Application()
app.run()

GSK / Graphene

do_snapshot

GStreamer gi.require_version('Gst', '1.0')

オススメ(sintel_trailer-480p.webm への URL をローカルにダウンロードして "file:///" に書き換えないと動かなかった。Gtk3 -> Gtk4 の書き換え必要)

python2 + gtk2? 。読み替えが必要。

GstGL

Gtk と GStreamer の連携

Window 全体が VIDEO OVERLAY されちゃう

on_realize

Windows上のGtk4でのWindowハンドル取得例。

gst_gtk4_windows.py
    # this function is called when the GUI toolkit creates the physical window
    # that will hold the video
    # at this point we can retrieve its handler and pass it to GStreamer
    # through the XOverlay interface
    def on_realize(self, widget: Gtk.DrawingArea):
        window_handle = self.get_native().get_surface().get_handle()
        # pass it to playbin, which implements XOverlay and will forward
        # it to the video sink
        self.player.playbin.set_window_handle(window_handle)

pygobject と gobject-introspection

gobject-introspection(libgirepository) が GLIB(GObject) のリフレクションライブラリのようで、
pygobject はこのライブラリのユーザー。

gobject-introspection が動作するには対象の dll に対して gir とそこから生成される typelib が正しく配置される必要がある。
あとから gir と typelib を追加すると pygobject の使えるオブジェクトが増える。

ls C:/gnome/share/gir-1.0/
DBus-1.0.gir         GdkPixbuf-2.0.gir    Pango-1.0.gir        freetype2-2.0.gir
DBusGLib-1.0.gir     GdkPixdata-2.0.gir   PangoCairo-1.0.gir   gir-1.2.rnc
GIRepository-2.0.gir GdkWin32-4.0.gir     PangoFT2-1.0.gir     libxml2-2.0.gir
GL-1.0.gir           Gio-2.0.gir          PangoFc-1.0.gir      win32-1.0.gir
GLib-2.0.gir         Graphene-1.0.gir     PangoOT-1.0.gir      xfixes-4.0.gir
GModule-2.0.gir      Gsk-4.0.gir          Vulkan-1.0.gir       xft-2.0.gir
GObject-2.0.gir      Gtk-4.0.gir          cairo-1.0.gir        xlib-2.0.gir
Gdk-4.0.gir          HarfBuzz-0.0.gir     fontconfig-2.0.gir   xrandr-1.3.gir

ls c:/gnome/lib/girepository-1.0
DBus-1.0.typelib         Gio-2.0.typelib          cairo-1.0.typelib
DBusGLib-1.0.typelib     Graphene-1.0.typelib     fontconfig-2.0.typelib
GIRepository-2.0.typelib Gsk-4.0.typelib          freetype2-2.0.typelib
GL-1.0.typelib           Gtk-4.0.typelib          libxml2-2.0.typelib
GLib-2.0.typelib         HarfBuzz-0.0.typelib     win32-1.0.typelib
GModule-2.0.typelib      Pango-1.0.typelib        xfixes-4.0.typelib
GObject-2.0.typelib      PangoCairo-1.0.typelib   xft-2.0.typelib
Gdk-4.0.typelib          PangoFT2-1.0.typelib     xlib-2.0.typelib
GdkPixbuf-2.0.typelib    PangoFc-1.0.typelib      xrandr-1.3.typelib
GdkPixdata-2.0.typelib   PangoOT-1.0.typelib
GdkWin32-4.0.typelib     Vulkan-1.0.typelib

この gir と typelib を生成するためのツールは、gobject-introspection のインストール時に作成されます。

g-ir-compiler で gir から typelib を作る。

pygobject(libgirepository) は typelib を参照していて、gir は見ていないぽい。

gtk や gstreamer など gir と typelib を生成して python から使いたいライブラリは、gobject-introspection より後にビルドする必要があります。

gir のファイルパスは %PREFIX%/shared/gir-1.0/

typelib のファイルパスは %PREFIX%/lib/girepository-1.0
環境変数は GI_TYPELIB_PATH

language server

pygobject のインテリセンスが効くようにする。

Gtk 4.0 の型ヒントを生成する

> git clone https://github.com/pygobject/pygobject-stubs
> cd pygobject-stubs
pygobject-stubs> py .\tools\generate.py Gtk 4.0 > "C:\Python311\Lib\site-packages\gi-stubs\repository\Gtk.pyi"

python で対象モジュールを実際に import して生成しています。

import gi
gi.rquire_version('Gtk', '4.0')
from gi.repository import Gtk

for key in dir(Gtk):
    value = getattr(Gtk, key)
    # value の情報を調べる

xml から型ヒントを作る

GObject の場合 gir ファイルから stub を生成できる。
vscode から使うときにいい感じになった。

extension module の関数は型情報がありません。
pylance とかは __doc__に仕込んだものを見つけてくれるかもしれない。

// C の Python 関数定義
// def func(*args, **keys): と見える
static PyObject *func(PyObject *self, PyObject *args); 

C 言語など実装側では型情報分かっているので、そこから stub を作ってやると使い勝手が良くなります(bpy や qt など)。

import 時の挙動

DynamicImporter で typelib 情報から python module を動的にロードしている。

  • gi.require_version('Gtk', '3.0')
  • from gi.repository import Gtk # namespace Gtk
  • DynamicImporter typelib (lib/girepository-1.0/Gtk-3.0.typelib)
  • override(python で便利関数追加など)

といった感じで動く。
override は便利だけど他言語と乖離してドキュメントが読みにくくなる弱点がある。

参考

DynamicImporter

gi.repository.__init__.py
import sys

from ..importer import DynamicImporter

sys.meta_path.append(DynamicImporter('gi.repository')) # 👈

del DynamicImporter
del sys
int main(void) {
  GError *error = NULL;
  auto repository = g_irepository_get_default();
  g_irepository_require(repository, "GLib", "2.0", {}, &error);
  if (error) {
    g_error("ERROR: %s\n", error->message);
    return 1;
  }

  auto info = g_irepository_find_by_name(repository, "GLib", "MainLoop");
  if (!info) {
    g_error("ERROR: %s\n", "Could not find GLib.MainLoop");
    return 1;
  }

  auto type = g_base_info_get_type(info);
  if (!type) {
    g_error("ERROR: %s\n", "Could not find GLib.MainLoop type");
    return 2;
  }

site-packages.gi.overrides

GIR からの自動生成に、手書きの python で型を拡張して便利関数を生やしている。
new 関数は gir 由来なのに対して、コンストラクター init や演算子オーバーロードなど。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0