旧 #temanote

Linux大好き。だけど進捗ありません。

紬ちゃんマスコット 〜Linux / Gtkmm編〜

前回がこちら

temama.hatenablog.com

OpenGLに挫折し、GTKを利用するも謎のエラーで断念。

その後DxLib + なんちゃってWinAPIでゴリ押したところで終わりました。
 

今回はGTKのエラーを解消して制作を進めていきたいと思います(願望)
 


エラーの壁

前回詰んだエラーがこちら

g++ -o mascot_tsumugi main.cxx `pkg-config gtkmm-3.0 --cflags --libs`

main.cxx:6:16: error: ‘GC’ is not a member of ‘Gdk’
Glib::RefPtr< Gdk::GC > m_gc;
^
main.cxx:6:16: error: ‘GC’ is not a member of ‘Gdk’
main.cxx:6:24: error: template argument 1 is invalid
Glib::RefPtr< Gdk::GC > m_gc;
^
main.cxx: In member function ‘virtual void MyDrawArea::on_realize()’:
main.cxx:32:14: error: ‘Gdk::GC’ has not been declared
m_gc = Gdk::GC::create( get_window() );
^
main.cxx: In member function ‘virtual bool MyDrawArea::on_expose_event(GdkEventExpose*)’:
main.cxx:40:16: error: ‘class Gdk::Window’ has no member named ‘draw_pixbuf’
get_window()->draw_pixbuf(
^
main.cxx:42:19: error: ‘RGB_DITHER_NONE’ is not a member of ‘Gdk’
width, height, Gdk::RGB_DITHER_NONE, 0, 0 );
^
make: *** [mascot_tsumugi] エラー 1

確認していきましょう。


まずオプションでつけた`gtk-config gtkmm-3.0 --cflags --libs`。

そのままbashで実行すると色々出てきました。どうやら勝手に探してきてくれるような感じです。

この中からgrepでGdkを探すと6つほどヒットしました。

多分問題ないと思います。

 
エラーはすべてGdkクラス絡みっぽい。


よくわからんのでまたteratailに投げました。

teratail.com

回答お待ちしております(宣伝

 

解決

gtkmm-3.0を2.4にすると通りました。
Gtkmm-3.0は互換性ないっぽいですね。消しとこ。

これでやっと先に奨める。
いざ実行。

 いない。




と思ってたら

いました。
ウィンドウが小さくて見えなかっただけでした。天使。


ウィンドウの透明化

さて写経プログラミングなのであんまり理解できてないけどウィンドウ透明化しよう。
調べた結果、Gtk::Window::set_opacityで不透明度を設定できるらしい。

早速設定。

なんか寧々√思い出してすこし悲しくなりました。


どうやらウィンドウごと透明にするのはNG。
考えてみたらウィンドウ透明にしてもタイトルバーの判定は残ってるし、透明部分クリックしたらマスコットがアクティブになりますしね。


非短形非矩形ウィンドウ



こんなこと言ってると



訂正を頂いた。



そしてこれ。

反省してます。本当に。
ひくけい。

でも間違える人多いみたいですね。


とのこと。

死体蹴り





気を取り直して。

透明部分が邪魔なら非矩形ウィンドウにすればいいじゃない。
DxLib版もあれ非矩形ウィンドウなんだなぁ…簡単に作れるので実感沸かなかった。


とりあえずGtkmmで非矩形ウィンドウを作る方法を探します。



が、ない。
見当たらない。

仕方がない、自分で探します。


バージョンの壁

まず非矩形ウィンドウってどうやって作るんだ!?ってなります。
octworks.orz.hm
WinAPIですが、きっと仕組みは同じ。

画像データからリージョン(領域)データを作成

リージョンデータを元にウィンドウ成形

こんな流れ。
ならばこれらをやってくれるメソッドgtkmmから探せば良い。

gtkmm: Gtk::Widget Class Reference
英語リファレンス。僕の天敵。
まぁ中国語資料よりマシですので頑張ります。

shapeで検索したところ
void Gtk::Widget::shape_combine_region ( const ::Cairo::RefPtr< const ::Cairo::Region > & region )
なんてメソッドがありました。これかな?

何とか行けそうと思ってましたがその下
since gtkmm 3.0;

うん。エラー出たバージョンですね。

ついでにCairoクラスとか新しい名前も出始めました。
調べてやるしかないですね。



なんと情報提供。びっくり。
感謝です。


そろそろ本気出す

僕に残された道は2つ

1, gtkmm-2.4で非矩形ウィンドウを作る
 なんかできるらしいんですが、詳しいやり方が出てこないので非常につらみ。

2, gtkmm-3.0を使えるようにする
 こっちのほうが現実的かな。そうすればNaMACHANさんから頂いた情報もきっと使えるし。

というわけでgtkmm-3.0を使って頑張っていく方向で行きます。


さてあのエラーと向き合わなければいけないのですが
そもそもエラー出してるGdk::GCってなんぞや?と。

調べてみたらGLContextの略っぽいですね。ただ公式リファレンス漁ってもよくわかりませんでした。

Gtk+3.0について調べているうちにグラフィック関連がCairoに!(ガバガバ意訳)みたいな情報に辿り着いた。

ほう、ならばCairoだ。
ファイルから画像を読み込んで表示(cairomm編)
Cairo編も載せてくれてました。感謝。


写経してmake。

通る。

しかし紬は顔を出してくれない。


試しにgtkmm-2.4でmake。
紬が出る。


またか。


これはもう本格的に一からgtkmm-3.0を勉強する必要がありそうだ。
やってやろう。


勉強用に選んだサイトがこちら
Programming with gtkmm 3

公式講座(もちろん英語)。
正直つらいけど頑張ります。

しょっぱなからautoがエラー吐いて詰みそうになったけど頑張ります。
(autoはC++11からなので -std=c++11 をつけたら通った)

全ては紬のため。


ようやくスタートライン


心温まるミスを経て

ついにgtkmm-3.0のサンプルソースが動きました()
ようやくサンプル動くとかクソザコ過ぎィ!

写経元はこちら
Drawing Images


ここからようやく非矩形ウィンドウ化です。

そこでNaMACHANさんに教えていただいたリンク先を参考にしていきます。

#if GTK_CHECK_VERSION(2,91,0)
  GdkPixbuf *pixbuf = NULL;
  GdkPixbufAnimation *anime = NULL;
  switch(gtk_image_get_storage_type(GTK_IMAGE(image))) {
    case GTK_IMAGE_PIXBUF:
      pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));
      break;
    case GTK_IMAGE_ANIMATION:
      anime = gtk_image_get_animation(GTK_IMAGE(image));
      pixbuf = gdk_pixbuf_animation_get_static_image(anime);
      break;
    default:
      break;
  }
  cairo_surface_t *img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 
    gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf));
  cairo_t *cr = cairo_create(img);
  gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
  cairo_paint(cr);
  cairo_region_t *mask = gdk_cairo_region_create_from_surface(img);
  gtk_widget_shape_combine_region(gwin_message, mask);
  cairo_region_destroy(mask);
  cairo_destroy(cr);
  cairo_surface_destroy(img);
#else
  GdkBitmap *bitmap = NULL;
  gdk_pixbuf_render_pixmap_and_mask(gdk_pixbuf_new_from_file(icon, NULL), 
NULL, &bitmap, 128);
  gtk_widget_shape_combine_mask(gwin_message, bitmap, 0, 0);
#endif

こんなソースがあった。
GTK+(C言語向けラッパー)なのでこのままでは使えない。


まずは何やってるのか推測します。

#if GTK_CHECK_VERSION(2,91,0)
  GdkPixbuf *pixbuf = NULL; //バッファ
  GdkPixbufAnimation *anime = NULL; //アニメーション?多分関係ない

  switch(gtk_image_get_storage_type(GTK_IMAGE(image))) { //多分関係ない
    case GTK_IMAGE_PIXBUF: //きっとここ
      pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));
      break;

    case GTK_IMAGE_ANIMATION: //多分これは違う
      anime = gtk_image_get_animation(GTK_IMAGE(image));
      pixbuf = gdk_pixbuf_animation_get_static_image(anime);
      break;
    default:
      break;
  }

  cairo_surface_t *img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 
    gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); //表面どうのこうの
  cairo_t *cr = cairo_create(img); //作る
  gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); //画像セットかな
  cairo_paint(cr); //描画
  cairo_region_t *mask = gdk_cairo_region_create_from_surface(img); //多分非矩形ウィンドウの形とってる
  gtk_widget_shape_combine_region(gwin_message, mask); //非矩形ウィンドウ作成かな
  cairo_region_destroy(mask); //さっき取った非矩形ウィンドウの形データ消す
  cairo_destroy(cr); //えっ これも消すの
  cairo_surface_destroy(img); //描画したら使ったもの全部消すらしい。

#else //GTK+3.0使えるのでこれ以降は関係なし?
  GdkBitmap *bitmap = NULL;
  gdk_pixbuf_render_pixmap_and_mask(gdk_pixbuf_new_from_file(icon, NULL), 
    NULL, &bitmap, 128);
  gtk_widget_shape_combine_mask(gwin_message, bitmap, 0, 0);
#endif

こんな感じに。

さらにメインの処理っぽいのを抜き出します。

GdkPixbuf *pixbuf = NULL; //バッファ
pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image)); //読み出し

cairo_surface_t *img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 
  gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); //表面どうのこうの
cairo_t *cr = cairo_create(img); //作る
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); //画像セットかな
cairo_paint(cr); //描画
cairo_region_t *mask = gdk_cairo_region_create_from_surface(img); //多分非矩形ウィンドウの形とってる
gtk_widget_shape_combine_region(gwin_message, mask); //非矩形ウィンドウ作成かな
cairo_region_destroy(mask); //さっき取った非矩形ウィンドウの形データ消す
cairo_destroy(cr); //えっ これも消すの
cairo_surface_destroy(img); //描画したら使ったもの全部消すらしい。

そんな難しいことはしていないけど、対応したクラスとメソッドを探しだすのめんどい…
紬のためなので頑張ります。


紬不足による疲労感

1日半くらいgtkmmの公式リファレンスを漁ったが、一向に理解できる気配がない。


たまに情報飛んできます。とてもありがたい。

今更ながら「___::RefPtr< "クラス名" >」ってなんだろ…と思っておりました。
C++をクラス付近で投げ出したため理解してませんでした。

改めてテンプレートクラスの章をよんでやっとこさ理解。
Gtk、Cairoを中心に調べてましたが、Glib::RefPtrが多用されてるのでGlibも調べてみます。

というか最初から猫C++読みながらやるべきだった…


流石に長くなりすぎたので次エントリにします。