pygobject を使う

GTK4 と GStreamer の資料収集。

https://qiita.com/ousttrue/items/ac591be1654615e1b178

から分けた。

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

https://github.com/GNOME/pygobject/tree/master/examples

https://bitwalk.blogspot.com/p/pygobject.html

https://python-gtk-3-tutorial.readthedocs.io/en/latest/

## minimum

```py
# 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
https://python-gtk-3-tutorial.readthedocs.io/en/latest/gallery.html

### Gtk.TreeView
https://python-gtk-3-tutorial.readthedocs.io/en/latest/treeview.html

https://palepoli.skr.jp/tips/pygobject/treeview.php

C言語

https://docs.gtk.org/gtk3/treeview-tutorial.html

### Gtk.DrawingArea

https://palepoli.skr.jp/wp/2021/05/03/gtk4-python-001/

https://athenajc.gitbooks.io/python-gtk-3-api/content/gtk-group/gtkdrawingarea.html

### GLArea(OpenGL)

https://gist.github.com/TurBoss/78dd883ba045d311695d7b30eab8a5be

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

https://www.gtk.org/docs/language-bindings/python/

https://lazka.github.io/pgi-docs/

reference

https://docs.gtk.org/gtk4/

Gtk4初手にオススメ

https://zetcode.com/python/gtk/ 

Gtk4チュートリアル

https://github.com/Taiko2k/GTK4PythonTutorial

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

https://gtk-rs.org/gtk4-rs/stable/latest/book/introduction.html

Gnome向け。動かない。libadwaita

https://github.com/Taiko2k/GTK4PythonTutorial

## GTK3との違い

https://docs.gtk.org/gtk4/migrating-3to4.html

https://palepoli.skr.jp/wp/2021/05/03/gtk4-python-001/

https://qiita.com/katsuko0303/items/7eba4a0b0b070f38774b#gtkcontainergtkbin

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

GTK4で無くなった
* Gtk.main_quit 
* show_all()
* Gtk.main()

## minimum

```py
# 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)
```

継承方式

```py
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

https://github.com/GNOME/gtk/blob/main/examples/squares.py

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

https://github.com/GStreamer/gst-python/tree/master/examples

https://lifestyletransfer.com/how-to-launch-gstreamer-pipeline-in-python/

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

https://github.com/gkralik/python-gst-tutorial

  - https://www.freedesktop.org/software/gstreamer-sdk/data/media/

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

https://brettviren.github.io/pygst-tutorial-org/pygst-tutorial.html#sec-1

## GstGL

https://coral.googlesource.com/edgetpuvision/+/refs/heads/master/plugins/python/glsvgoverlaysink.py

https://gitlab.collabora.com/ao2/gstgl-examples

http://ishikawa-vision.org/~kyamagu/cgi-bin/moin.cgi/VideoTexture/

# Gtk と GStreamer の連携

https://gist.github.com/lubosz/d6209998907d122462a3


Window 全体が VIDEO OVERLAY されちゃう

https://github.com/gkralik/python-gst-tutorial/blob/master/basic-tutorial-5.py

## on_realize

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

```python: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 はこのライブラリのユーザー。

https://pygobject.readthedocs.io/en/latest/

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

https://www.slideshare.net/yurenju/python-and-gobject-introspection

```
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` のインストール時に作成されます。

https://gi.readthedocs.io/en/latest/tools/index.html

:::note
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`。

https://qiita.com/groonga/items/71b145b37d77bd160bf2

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

https://pypi.org/project/PyGObject-stubs/

## 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"
```

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

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

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

## xml から型ヒントを作る

https://github.com/ousttrue/gi_tool

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

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

```c
// 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 は便利だけど他言語と乖離してドキュメントが読みにくくなる弱点がある。

## 参考

https://pod.hatenablog.com/entry/2019/07/25/005334

## DynamicImporter

```py:gi.repository.__init__.py
import sys

from ..importer import DynamicImporter

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

del DynamicImporter
del sys
```

```c
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

https://github.com/GNOME/pygobject/tree/master/gi/overrides

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