2015年6月15日月曜日

GTKでドロップを設定する。

ブログを書き始めた時点で詰まっていること。
それはGTKでのドラッグアンドドロップだ。

ドロップしてシグナルを発生させることはできるのだけれども、
肝心のドロップしたファイルのデータを取り出せない・・・



今のところここのサイトで勉強中。
 入門GTK+(PDF)
 GTK+でdrag and drop
    Drag and Dropリファレンス

詳細はこれらのサイトにお任せするとして、大まかに言えばドロップ側に必要なことは

  1. 受け入れるデータ型をGtkTargetEntry構造体型で宣言しておく。
  2. gtk_signal_connect()やgtk_builder_connect_signals()でシグナルを準備。
  3. gtk_drag_dest_set()でウィジェットにドロップができるようにする。
  4. 各種シグナルごとの動作を設定。

とのこと。

1〜3まではOK。
4もシグナルを発生させることはできるけれども、データを取り出そうとすると

 g_print("data->target = %s\n" , gdk_atom_name( data->target)) ;

の部分で下記のエラーが発生。

 error: dereferencing pointer to incomplete type

ポインタ参照時に型が不一致ということらしい。
名前が間違っているとか、インクルード不足とかが主な原因だとか。

自分のコードを色々と調べては見たものの、イマイチどこに問題があるのかわからなかった。

んが、よくよく考えてみるとリンカーオプションがマズかったかもしれない。
と、いうのも今まで参考にしてきたサイトはGTK+のバージョンが現行のものより古いのだ。

そんなわけで
`pkg-config --cflags --libs gtk+-3.0 gmodule-2.0`
から
`pkg-config --cflags --libs gtk+-2.0 gmodule-2.0`
に変更したところ・・・

エラー無しでビルドが通るではないか!
実行するとこれとはまた別の問題ですんなり動いてくれないのだが、
こうゆうパターンだと気づくまでにまる1日かかってしまった・・・

結局、GTKのバージョンの問題だったのか?
ここまでの経緯は以下のとおり。


GTKのドロップの設定をしていると、受け入れるデータの設定をするのに
GtkTargetEntryという型の構造体の配列を作る必要がある・・・らしい。


リファレンスはたぶんコチラ↓にあるの内容。
 Selections

プロセス間のデータのやりとりのための関数に関係するらしい。

これによると定義は以下の通り。
struct GtkTargetEntry {
    gchar *target;    ←?
    guint  flags;       ←GtkTargetFlags列挙体のメンバから選択する。
    guint  info;     ←後でシグナルハンドラに渡される任意の値。
};


targetの部分はmime型で受け入れ可能な形式を書き込むことになっているらしいが、
リファレンスを見ると、mimeという単語が出てこない。
ちなみにmimeとは
MIME の基礎
拡張子とMIMEタイプ
Multipurpose Internet Mail Extensions


GDK3のDrag and Dropリファレンス
GTK+3のDrag and Dropリファレンス

よくわからないので、改めてGTK+3のdrag-data-receivedシグナルを調査する。
なんか今までとやってきたのとちょっと違う気がする・・・・
GtkTargetListを使っているところとか。

ちなみに
GTK+2のdrag-data-receivedシグナル
・・・うーん。

サンプルコードがあったので、シグナルのコールバックに置き換えて実行してみると、
どのみちerror: dereferencing pointer to incomplete typeのエラーが出る。
結局ふりだしに戻るw

きっと何かしらのファイルが足りないんだろな〜

コールバックの引数を調べていると
oid cb_drag_data_received(GtkWidget *widget,
        GdkDragContext *context,
        gint x,
        gint y,
        GtkSelectionData *data,
        guint info,
        guint time_,
        gpointer user_data) {
    gboolean result = FALSE;
    gboolean delete = FALSE;

GtkSelectionData *data
がうまく読みとれていない。
gtkwidget.hを確認すると、
typedef struct _GtkSelectionData   GtkSelectionData;
となっており、さらにgtkselection.hで
struct _GtkSelectionData
{
  GdkAtom       GSEAL (selection);
  GdkAtom       GSEAL (target);
  GdkAtom       GSEAL (type);
  gint          GSEAL (format);
  guchar       *GSEAL (data);
  gint          GSEAL (length);
  GdkDisplay   *GSEAL (display);

};
であった。

試しにコード内で直接このGtkSelectionData構造体をコールバックの直前で宣言してみると、
エラーのもとになっているのはGSEALという関数のようだ。
struct _GtkSelectionData
{
  GdkAtom       GSEAL (selection);
  GdkAtom       GSEAL (target);
  GdkAtom       GSEAL (type);
  gint          GSEAL (format);
  guchar       *GSEAL (data);
  gint          GSEAL (length);
  GdkDisplay   *GSEAL (display);

};

さらに下記のように書きなおしてみる。
typedef struct _GtkSelectionData   GtkSelectionData;
struct _GtkSelectionData

{
  GdkAtom       selection;
  GdkAtom       target;
  GdkAtom       type;
  gint         format;
  guchar       *data;
  gint         length;
  GdkDisplay   *display;
};

これだとエラーが起こらずにコンパイルできて実行にも問題がなかった。

それではGSEALとはなんぞや?
gtkconfig.hでは
/* gdkconfig.h
 *
 * This is a generated file.  Please modify `configure.in'
 */
.
.
.

define GSEAL(ident)      ident
.
.
.

となっている。

構造体を隠すためのマクロらしいのだが、それよりも
This is a generated file.  Please modify `configure.in'の一文が気になる。
つまりは`configure.in'を修正しろとのこと。




0 件のコメント:

コメントを投稿