ClutterActor on GtkContainer

Clutter は魅力的ではあるが描写の全部を自前で用意する必要がある。
つまり GtkButton, GtkListView のような Widget は無い。

それなら ClutterActor を GtkContainer 上に pack できればよくね?
やってみると普通に拒否、全くの別物だからそりゃ当然の話だ。

しかし GNOME3 自体はしっかり連携している。
知らないだけで何か方法があるはずだ。

/usr/lib64/girepository-1.0
をよく見ると GtkClutter というものがある。

Clutter Gtk integration on Vimeo

WPF のような新規ウイジェットではなく GTK+ をエフェクトするみたい。
そりゃ GTK+3 自体が新規だし元から連携していてもおかしくない。

Clutter-Gtk 1.0.2 Reference Manual

どうやら GtkClutterWindow は GtkWindow のサブクラス。
ClutterActor が表面に張り付いている状態って認識でいいのかな?
Python からは get_stage() で ClutterStage が取得できそうである。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
from gi.repository import Gtk, Clutter, GtkClutter, ClutterX11

def quit(widget, data=None):
    Gtk.main_quit()

#ClutterX11.set_use_argb_visual(True)
#ClutterX11.set_display(ClutterX11.get_default_display())
#ClutterX11.disable_event_retrieval()
Clutter.init(sys.argv)

w = GtkClutter.Window()
w.connect("destroy", quit)
w.set_title("GtkClutter.Window")
w.resize(300, 200)

stage = w.get_stage()
stage.set_size(300.0, 200.0)
w.show_all()
Gtk.main()

WARNING 出まくり、初期化とか色々やってみたけど駄目だった。
とりあえず get_stage() だけはできている、使い方が悪いのだろう。
ついでにこの場合 delete-event ではなく destroy 指定でないと終了しない。

直感でやっても上手くいかない、もっと良い方法は無いだろうかと検索。

Stage Widget

gtk_clutter_embed_new ()
で作成した Object なら Gtk+ コンテナに入れられるようだ。
試すと上手くいったので ClutterGst でやってみる。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
from gi.repository import Gtk, Clutter, GtkClutter, ClutterGst

class ClutterEmbedTest(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # Video Texture
        tx = ClutterGst.VideoTexture()
        tx.set_uri("file:///home/sasakima-nao/movie/bike/ninjya1000_1.mp4")
        # Create the Clutter Widget
        embed = GtkClutter.Embed.new()
        embed.connect("size-allocate", self.on_size_allocate, tx)
        # ClutterStage
        stage = embed.get_stage()
        stage.add_actor(tx)
        # Buttons
        play = Gtk.Button(stock=Gtk.STOCK_MEDIA_PLAY)
        play.connect("clicked", self.on_play, tx)
        # packing
        vbox = Gtk.VBox()
        vbox.pack_start(embed, True, True, 0)
        vbox.pack_start(play, False, False, 0)
        self.add(vbox)
        self.set_title("ClutterEmbedTest")
        self.connect("delete-event", self.on_quit)
        self.show_all()

    def on_size_allocate(self, widget, allocation, tx):
        w = widget.get_allocation().width
        h = widget.get_allocation().height
        tx.set_size(w, h)

    def on_play(self, widget, tx):
        tx.set_playing(True)

    def on_quit(self, widget, data=None):
        Gtk.main_quit()

if __name__ == '__main__':
    # initialized
    Clutter.init(sys.argv)
    ClutterGst.init(0, "")
    ClutterEmbedTest()
    Gtk.main()

よしコレなら何も警告は出ない。
警告が出ないようガンバった WPF 3.0 アプリが 3.5 で無意味にされた過去が…
初心者はワケワカだろうけど、こんな苦労も数年後には無意味になるのでしょう。

やはり親ウインドウサイズに連動しないので size-allocate シグナルを利用。
ClutterActor のサイズは float だけど int のままサイズ変更できた。
コレで GTK+ Widget と ClutterActor の共存アプリケーションができる。

アスペクト比保持とかはどうやるんだろう?
というか最初のビデオでは GTK+ widget にエフェクトが掛かっていたような…
まだ先は長い、リファレンスマニュアル無しで作るのは狂気だがコレが楽しい。