From: Kenichi K. <ko...@ma...> - 2003-12-18 15:47:39
|
はじめまして、小宮と申します。 GtkBindingSet#add_signal を動くようにしてみました。gtkbindings.h の他の publich な API も動作をひととおり確認しています。 正直 Ruby 側のインタフェースはまだ納得がいっていないのですが、ひ とまず動くようになったので、コメントをいただければと思いパッチを 御送りします。 追加メソッド * Gtk::BindingSet.new Gtk::BindingSet#initialize をうまく実装できなかったので(※) new をオーバーライドしました。 * Gtk::BindingSet.find 処理内容を考慮してクラスメソッドに変更しました。 * Gtk::BindingSet.by_class gtk_binding_set_by_class()。 Gtk::Object.binding_set の方が 良いでしょうか? * Gtk::BindingSet.activate gtk_bindings_activate()。Gtk::Object#activate_binding とか の方が良いでしょうか? * Gtk::BindingSet#add_signal gtk_binding_entry_add_signal()。 シグナルに渡せるパラメータは Float, 整数、文字列のみ。to_int と to_str の順で変換を試みる。true/false は 1/0 に変換される。 削除メソッド * Gtk::BindingSet#entry_remove gtkbindings.h に public ではないと書かれていたので消しました。 ※ initialize をうまく実装できなかったというのは、始め initialize の中で G_INITIALIZE(self, binding_set) のようにしていたのです が、binding_set のコピーがラップされてしまってうまく動作しな かったという事です。私が Ruby/Gtk の C API をまだ把握していな いため正しいやり方を見落としているだけかもしれません。 ---- 小宮 # サンプルコード # TextView 内でスペースとバックスペース押すとそれぞれ上下に1画面 # づつスクロールする。"<space bar>" と書かれた二つのボタンはいず # れもクリックすると、TextView にスペースバーが押された際と同じ # シグナルを送る。Clear と書かれたボタンを押すとスペースバーの # バインディングが無効化される。 require 'gtk2' Gtk.init w = Gtk::Window.new s = Gtk::ScrolledWindow.new t = Gtk::TextView.new b1 = Gtk::Button.new("<space bar>") b2 = Gtk::Button.new("<space bar>") b3 = Gtk::Button.new("Clear") h = Gtk::HBox.new h.add b1 h.add b2 h.add b3 v = Gtk::VBox.new v.add h v.add s w.add v s.add t w.show_all w.name = "window1" v.name = "vbox1" s.name = "scrolled_window1" t.name = "text_view1" binding_set = Gtk::BindingSet.new("my_binding") binding_set.add_path(Gtk::PathType::WIDGET, "window1.*.text_view1", Gtk::PathPriorityType::APPLICATION) binding_set.add_signal(Gdk::Keyval::GDK_BackSpace, 0, "move_cursor", Gtk::MOVEMENT_PAGES, -1, false); buf = t.buffer 100.times do |i| buf.insert_at_cursor("#{i}\n") end t.editable = false t.set_size_request(200,200) s1 = Gtk::BindingSet.by_class(Gtk::TextView) s1.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", Gtk::MOVEMENT_PAGES, 1, false); b1.signal_connect("clicked") do s1.activate(Gdk::Keyval::GDK_space, 0, t) end b2.signal_connect("clicked") do Gtk::BindingSet.activate(t, Gdk::Keyval::GDK_space, 0) end b3.signal_connect("clicked") do s1.entry_clear(Gdk::Keyval::GDK_space, 0) end w.signal_connect("destroy") do Gtk.main_quit end Gtk.main diff -u -r bak/ruby-gnome2/gtk/src/rbgtkbindingset.c ruby-gnome2/gtk/src/rbgtkbindingset.c --- bak/ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-08-31 03:40:02.000000000 +0900 +++ ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-12-18 23:26:17.000000000 +0900 @@ -13,6 +13,7 @@ #define RVAL2MOD(mods) RVAL2GFLAGS(mods, GDK_TYPE_MODIFIER_TYPE) + /*****************************************/ static GtkBindingSet* gtk_bindingset_copy(const GtkBindingSet* bin) @@ -28,10 +29,12 @@ gtk_bindingset_get_type(void) { static GType our_type = 0; - if (our_type == 0) - our_type = g_boxed_type_register_static ("GtkBindingSet", + if (our_type == 0) { + our_type = g_boxed_type_register_static ("GtkBindingSet", (GBoxedCopyFunc)gtk_bindingset_copy, (GBoxedFreeFunc)g_free); + rbgobj_boxed_not_copy_obj(our_type); + } return our_type; } /*****************************************/ @@ -39,15 +42,57 @@ #define _SELF(s) (GtkBindingSet*)(RVAL2BOXED(s, GTK_TYPE_BINDING_SET)) static VALUE +binding_s_new(self, set_name) + VALUE self, set_name; +{ + VALUE obj = BOXED2RVAL(gtk_binding_set_new(RVAL2CSTR(set_name)), + GTK_TYPE_BINDING_SET); + return obj; +} + +static VALUE binding_initialize(self, set_name) VALUE self, set_name; { - RBGTK_INITIALIZE(self, gtk_binding_set_new(RVAL2CSTR(set_name))); return Qnil; } -/* -GtkBindingSet* gtk_binding_set_by_class (gpointer object_class); -*/ + +static VALUE +binding_s_by_class(self, klass) + VALUE self, klass; +{ + GType gtype; + gpointer gclass; + GtkBindingSet* binding_set; + + Check_Type(klass, T_CLASS); + + gtype = CLASS2GTYPE(klass); + + if (!G_TYPE_IS_CLASSED(gtype)) { + rb_raise(rb_eTypeError, "%s is not a classed GType", + rb_class2name(klass)); + } + gclass = g_type_class_ref(gtype); + if (!gclass) { + rb_raise(rb_eRuntimeError, "couldn't get class reference"); + } + if (!GTK_IS_OBJECT_CLASS(gclass)) { + g_type_class_unref(gclass); + rb_raise(rb_eTypeError, "%s is not a Gtk Object class", + rb_class2name(klass)); + } + + binding_set = gtk_binding_set_by_class(gclass); + if (!binding_set) { + g_type_class_unref(gclass); + rb_raise(rb_eRuntimeError, "couldn't get BindingSet from %s", + rb_class2name(klass)); + } + g_type_class_unref(gclass); + + return BOXED2RVAL(binding_set, GTK_TYPE_BINDING_SET); +} static VALUE binding_s_find(self, set_name) @@ -57,11 +102,14 @@ GTK_TYPE_BINDING_SET); } -/* Move to Gtk::Object -gboolean gtk_bindings_activate (GtkObject *object, - guint keyval, - GdkModifierType modifiers); -*/ +static VALUE +binding_s_activate(self, object, keyval, modifiers) + VALUE self, keyval, modifiers, object; +{ + return gtk_bindings_activate(GTK_OBJECT(RVAL2GOBJ(object)), + NUM2UINT(keyval), + RVAL2MOD(modifiers)) ? Qtrue : Qfalse; +} static VALUE binding_activate(self, keyval, modifiers, object) @@ -81,14 +129,61 @@ return self; } -/* -void gtk_binding_entry_add_signal (GtkBindingSet *binding_set, - guint keyval, - GdkModifierType modifiers, - const gchar *signal_name, - guint n_args, - ...); -*/ +static VALUE +binding_entry_add_signal(argc, argv, self) + int argc; + VALUE* argv; + VALUE self; +{ + VALUE keyval, modifiers, signame, rest; + struct RArray *params; + long i; + VALUE param; + GSList *slist, *free_slist; + + slist = NULL; + + rb_scan_args(argc, argv, "3*", &keyval, &modifiers, &signame, &rest); + + params = RARRAY(rest); + for (i=0; i<params->len; i++) { + GtkBindingArg *arg; + + arg = g_new0 (GtkBindingArg, 1); + slist = g_slist_prepend (slist, arg); + + param = params->ptr[i]; + if (TYPE(param) == T_FLOAT) { + arg->arg_type = G_TYPE_DOUBLE; + arg->d.double_data = NUM2DBL(param); + } else if (rb_respond_to (param, rb_intern("to_str"))) { + arg->arg_type = G_TYPE_STRING; + arg->d.string_data = StringValueCStr(param); + } else if (rb_respond_to (param, rb_intern("to_int"))) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = NUM2LONG(param); + } else if (param == Qfalse) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = 0; + } else if (param == Qtrue) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = 1; + } else { + rb_raise(rb_eTypeError, "could n't convert an argument to long, float or string"); + } + } + slist = g_slist_reverse (slist); + gtk_binding_entry_add_signall (_SELF(self), NUM2UINT(keyval), RVAL2MOD(modifiers), + StringValueCStr(signame), slist); + free_slist = slist; + while (slist) { + g_free (slist->data); + slist = slist->next; + } + g_slist_free (free_slist); + + return self; +} static VALUE binding_add_path(self, path_type, path_pattern, priority) @@ -100,40 +195,18 @@ return self; } -static VALUE -binding_entry_remove(self, keyval, modifiers) - VALUE self, keyval, modifiers; -{ - gtk_binding_entry_remove(_SELF(self), NUM2UINT(keyval), - RVAL2MOD(modifiers)); - - return self; -} - -/* -static VALUE -binding_entry_add_signall(self, keyval, modifiers, signal_name, binding_args) - VALUE self, keyval, modifiers, signal_name, binding_args; -{ - gtk_binding_entry_add_signall(_SELF(self), NUM2UINT(keyval), - NUM2INT(modifiers), RVAL2CSTR(signal_name), - - guint keyval, - GdkModifierType modifiers, - const gchar *signal_name, - GSList *binding_args); -guint gtk_binding_parse_binding (GScanner *scanner); -*/ - void Init_gtk_bindings() { VALUE gBinding = G_DEF_CLASS(GTK_TYPE_BINDING_SET, "BindingSet", mGtk); + + rb_define_singleton_method(gBinding, "by_class", binding_s_by_class, 1); rb_define_method(gBinding, "initialize", binding_initialize, 1); - rb_define_method(gBinding, "find", binding_s_find, 1); + rb_define_singleton_method(gBinding, "new", binding_s_new, 1); + rb_define_singleton_method(gBinding, "find", binding_s_find, 1); + rb_define_singleton_method(gBinding, "activate", binding_s_activate, 3); rb_define_method(gBinding, "activate", binding_activate, 3); rb_define_method(gBinding, "entry_clear", binding_entry_clear, 2); + rb_define_method(gBinding, "add_signal", binding_entry_add_signal, -1); rb_define_method(gBinding, "add_path", binding_add_path, 3); - rb_define_method(gBinding, "entry_remove", binding_entry_remove, 2); - } |
From: Masao M. <mu...@hi...> - 2003-12-18 17:47:55
|
むとうです。 小宮さん、はじめまして。 激しく疲れてるのでコメントだけです。 もしよろしければコメント吸収版のパッチを もう一度投げていただけないでしょうか。 #すみません、ちと風邪気味&デスマーチ気味で....。 On Fri, 19 Dec 2003 00:48:09 +0900 (JST) Kenichi Komiya <ko...@ma...> wrote: > はじめまして、小宮と申します。 > > GtkBindingSet#add_signal を動くようにしてみました。gtkbindings.h > の他の publich な API も動作をひととおり確認しています。 それは助かります。 > 追加メソッド > > * Gtk::BindingSet.new > Gtk::BindingSet#initialize をうまく実装できなかったので(※) > new をオーバーライドしました。 (順番入れ替えてます) > ※ initialize をうまく実装できなかったというのは、始め initialize > の中で G_INITIALIZE(self, binding_set) のようにしていたのです > が、binding_set のコピーがラップされてしまってうまく動作しな > かったという事です。私が Ruby/Gtk の C API をまだ把握していな > いため正しいやり方を見落としているだけかもしれません。 なるほど。 ただ、newをオーバーライドするとGtk::BindingSetのサブクラスを作るのが 難しくなってしまうので、できればinitializeのままで行きたいところですね。 そこで、申し訳ないのですが、以下の2つを確認してみていただけないで しょうか。 (案1) rbgobj_boxed_not_copy_obj(GTK_TYPE_BINDING_SET); をInit_gtk_bindings()の先頭あたりで宣言する。 (案2) gtk_bindingset_copy(const GtkBindingSet* bin)の方をいじる。 static GtkBindingSet* gtk_bindingset_copy(const GtkBindingSet* bin) { /* not copy here */ return bin; } 一応、案1>案2の優先度です。どちらも上記以外は元(initialize)のままです。 #どちらも、逆にコピーが必要そうな場所があったら明示的に #g_newしないといけない場所が出てくるかもしれません。 > * Gtk::BindingSet.find > 処理内容を考慮してクラスメソッドに変更しました。 すみません、これ、バグでした....。 > * Gtk::BindingSet.by_class > gtk_binding_set_by_class()。 Gtk::Object.binding_set の方が > 良いでしょうか? 確かにそうですね。 しかも、使用目的を考えると、引数を省略可能にして以下のようにも 書けたりすると良さげですがどうでしょう。 #書けるのかな(^^;)。 class MyTreeView < Gtk::TreeView bset = binding_set bset.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", Gtk::MOVEMENT_PAGES, 1, false) def initialize : end end > * Gtk::BindingSet.activate > gtk_bindings_activate()。Gtk::Object#activate_binding とか > の方が良いでしょうか? Gtk::Object#bindings_activateというのがあるのでそちらを使うと よろしいかと。 > * Gtk::BindingSet#add_signal > gtk_binding_entry_add_signal()。 > > シグナルに渡せるパラメータは Float, 整数、文字列のみ。to_int > と to_str の順で変換を試みる。true/false は 1/0 に変換される。 > + arg->d.string_data = StringValueCStr(param); は念のためRVAL2CSTRを使ってください。 > + } else if (rb_respond_to (param, rb_intern("to_str"))) { > + } else if (rb_respond_to (param, rb_intern("to_int"))) { は微妙ですねぇ(^^;)。 to_intの方は、GLib::EnumかGLib::FlagsかInteger型の時、って限定 した方が良さそうな気がしますがどうでしょうか。 to_strの方は、極端な話to_sにしちゃってif文の優先度を下げるようにするとか。 true/falseのところはGTK+のソースを読むと、G_TYPE_LONGではなく G_TYPE_BOOLEANを明示的に使っているところが多いのですが、 こちらもそうした方が良いのではないでしょうか。 > 削除メソッド > > * Gtk::BindingSet#entry_remove > gtkbindings.h に public ではないと書かれていたので消しました。 おぉ、気づきませんでした。ありがとうございます。 でも、APIドキュメントにはあるんですねぇ、自動生成したからかなぁ。 あと、サンプルコードの方も頂いちゃいたいのですがよろしいでしょうか? --- .:% Masao Mutoh<mu...@hi...> |
From: Kenichi K. <ko...@ma...> - 2003-12-18 23:45:52
|
小宮です。 > もしよろしければコメント吸収版のパッチを > もう一度投げていただけないでしょうか。 了解しました。後程パッチをお送りします。 > #すみません、ちと風邪気味&デスマーチ気味で....。 お大事に&お疲れさまです。私の方は急ぎませんのでお時間のある時に見てい ただければ結構です。 > なるほど。 > ただ、newをオーバーライドするとGtk::BindingSetのサブクラスを作るのが > 難しくなってしまうので、できればinitializeのままで行きたいところですね。 > > そこで、申し訳ないのですが、以下の2つを確認してみていただけないで > しょうか。 > > (案1) > rbgobj_boxed_not_copy_obj(GTK_TYPE_BINDING_SET); > をInit_gtk_bindings()の先頭あたりで宣言する。 既に gtk_bindingset_get_type()が最初に呼ばれた時にこれをするようにして ますが、rbgobj_boxed_initialize()はフラグを無視してコピーするのでうま く行きませんでした。newをオーバーライドしたのは rbgobj_boxed_initialize()ではなく、rbgobj_make_boxed()でインスタンスを 生成したかったからです。 > > (案2) > gtk_bindingset_copy(const GtkBindingSet* bin)の方をいじる。 > > static GtkBindingSet* > gtk_bindingset_copy(const GtkBindingSet* bin) > { > /* not copy here */ > return bin; > } > > 一応、案1>案2の優先度です。どちらも上記以外は元(initialize)のままです。 元のままというのはCVSのまま、つまり RBGTK_INITIALIZE(self, gtk_binding_set_new(RVAL2CSTR(set_name))); を呼ぶという意味でうしょうか?このままだとクラッシュしてたので G_INITIALIZE を呼ぶように変えてみたのですが… > > #どちらも、逆にコピーが必要そうな場所があったら明示的に > #g_newしないといけない場所が出てくるかもしれません。 GtkBindingSet GTK側でハッシュに登録して管理してるのでコピーしてしまう と動作がおかしくなるように思います。(最初コピーされていたので add_signal で登録されたエントリーをactivateした際クラッシュしてました。) > > * Gtk::BindingSet.by_class > > gtk_binding_set_by_class()。 Gtk::Object.binding_set の方が > > 良いでしょうか? > > 確かにそうですね。 > しかも、使用目的を考えると、引数を省略可能にして以下のようにも > 書けたりすると良さげですがどうでしょう。 > #書けるのかな(^^;)。 > > class MyTreeView < Gtk::TreeView > bset = binding_set > bset.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", > Gtk::MOVEMENT_PAGES, 1, false) > > def initialize > : > end > end ではこうします。もともとこう書けた方が良いかな、とは思ったのですが本来 の Gtk と違うクラスにメソッドを持っていってしまうのがアリなのか分から なかったので見送りました。 > > > * Gtk::BindingSet.activate > > gtk_bindings_activate()。Gtk::Object#activate_binding とか > > の方が良いでしょうか? > > Gtk::Object#bindings_activateというのがあるのでそちらを使うと > よろしいかと。 見落してました。これは消します。 > > > * Gtk::BindingSet#add_signal > > gtk_binding_entry_add_signal()。 > > > > シグナルに渡せるパラメータは Float, 整数、文字列のみ。to_int > > と to_str の順で変換を試みる。true/false は 1/0 に変換される。 > > > + arg->d.string_data = StringValueCStr(param); > > は念のためRVAL2CSTRを使ってください。 RVAL2CSTRだとStringValuePtr相当みたいですが、渡した文字列は内部で g_strdup されるので StringValueCStr したいところです。 > > > + } else if (rb_respond_to (param, rb_intern("to_str"))) { > > + } else if (rb_respond_to (param, rb_intern("to_int"))) { > > は微妙ですねぇ(^^;)。 > to_intの方は、GLib::EnumかGLib::FlagsかInteger型の時、って限定 > した方が良さそうな気がしますがどうでしょうか。 > to_strの方は、極端な話to_sにしちゃってif文の優先度を下げるようにするとか。 Ruby 的に整数、文字列が期待されている文脈では to_int, to_str を呼ぶと いう習慣なのかなと思ってこうしてみたのですが… 優先順位は逆にしても良いと思いますが、to_s を暗黙の変換に使うのは本来 の使用目的からはずれると思うので、to_str しないなら何もしない方が良い と思いますがどうでしょうか? > > true/falseのところはGTK+のソースを読むと、G_TYPE_LONGではなく > G_TYPE_BOOLEANを明示的に使っているところが多いのですが、 > こちらもそうした方が良いのではないでしょうか。 ここは G_TYPE_LONG でないとまずいんです。 gtk_bindings_entry_add_singall() の中では G_TYPE_LONG, G_TYPE_DOUBLE, G_TYPE_STRING の3通りにしか対応していないので。 gtk_bindings_entry_add_singal() (lがないやつ)の方でも G_TYPE_BOOLEAN を G_TYPE_LONG に変換して l つきのやつに渡してます。 > あと、サンプルコードの方も頂いちゃいたいのですがよろしいでしょうか? はい。 ---- 小宮 健一 |
From: Masao M. <mu...@hi...> - 2003-12-20 05:45:26
|
むとうです。 On Fri, 19 Dec 2003 08:46:23 +0900 Kenichi Komiya <ko...@ma...> wrote: > 小宮です。 > > > なるほど。 > > ただ、newをオーバーライドするとGtk::BindingSetのサブクラスを作るのが > > 難しくなってしまうので、できればinitializeのままで行きたいところですね。 > > > > そこで、申し訳ないのですが、以下の2つを確認してみていただけないで > > しょうか。 > > > > (案1) > > rbgobj_boxed_not_copy_obj(GTK_TYPE_BINDING_SET); > > をInit_gtk_bindings()の先頭あたりで宣言する。 > > 既に gtk_bindingset_get_type()が最初に呼ばれた時にこれをするようにして > ますが、rbgobj_boxed_initialize()はフラグを無視してコピーするのでうま > く行きませんでした。newをオーバーライドしたのは > rbgobj_boxed_initialize()ではなく、rbgobj_make_boxed()でインスタンスを > 生成したかったからです。 ほんとだ。じゃぁ、案2でしょうね。 > > > > (案2) > > gtk_bindingset_copy(const GtkBindingSet* bin)の方をいじる。 > > > > static GtkBindingSet* > > gtk_bindingset_copy(const GtkBindingSet* bin) > > { > > /* not copy here */ > > return bin; > > } > > > > 一応、案1>案2の優先度です。どちらも上記以外は元(initialize)のままです。 > > 元のままというのはCVSのまま、つまり > > RBGTK_INITIALIZE(self, gtk_binding_set_new(RVAL2CSTR(set_name))); > > を呼ぶという意味でうしょうか?このままだとクラッシュしてたので G_INITIALIZE > を呼ぶように変えてみたのですが… おっと、見落としてましたがRBGTK_INITIALIZE使ってますね、これ(汗。 G_INITIALIZEにしないとダメです。 RBGTK_INITIALIZEはGtk::Objectのサブクラスにのみ有効です。 #ってこれもドキュメント化しとかないとだめですね。 ちなみに、案2でもダメでした? 案2は、g_boxed_copyの実体の振る舞いをgtk_binding_set_copyに変えるので 基本的にg_boxed_copyが呼び出されてもコピーはされなくなります。 そうなると、逆にBOXED2RVAL等で今までコピーしていたものがコピーされなく なるのでそれが必要な場合は自前でg_newする必要がありますが、GtkBindingSet の実装ではその必要はあまりなさそうな気がしてます。 > > #どちらも、逆にコピーが必要そうな場所があったら明示的に > > #g_newしないといけない場所が出てくるかもしれません。 ただ、実はこの辺の設計は失敗したなぁと思ってる部分で、実はGBoxedな オブジェクトは初期化時にコピーを取らなくても良いモノが結構あるんですよね。 なので一段落(1.0リリース後?)に見直しかけようかなぁと。 #で、案1,案2の方法を後付けしたというか。 > GtkBindingSet GTK側でハッシュに登録して管理してるのでコピーしてしまう > と動作がおかしくなるように思います。(最初コピーされていたので > add_signal で登録されたエントリーをactivateした際クラッシュしてました。) ということで案2でいけると思うんですけどどうでしょう。 > > class MyTreeView < Gtk::TreeView > > bset = binding_set > > bset.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", > > Gtk::MOVEMENT_PAGES, 1, false) > > > > def initialize > > : > > end > > end > > ではこうします。もともとこう書けた方が良いかな、とは思ったのですが本来 > の Gtk と違うクラスにメソッドを持っていってしまうのがアリなのか分から > なかったので見送りました。 基本的にはナシなのですが、理由があり議論した後でしたらアリ、 というスタンスです。 あと、忘れてたんですが、上記例ではbinding_setを呼び出す前にregister_type を呼ぶ必要がありますね。 > > > * Gtk::BindingSet.activate > > > gtk_bindings_activate()。Gtk::Object#activate_binding とか > > > の方が良いでしょうか? > > > > Gtk::Object#bindings_activateというのがあるのでそちらを使うと > > よろしいかと。 > > 見落してました。これは消します。 一応、インプリメントしていないメソッドも残して置いていただいて、 インプリしない理由とか書いておくと後々良いと思うんですよね。 例えば、上記は、Move to Gtk::Objectとか。Movedかな(^^;)。 > > > * Gtk::BindingSet#add_signal > > > gtk_binding_entry_add_signal()。 > > > > > > シグナルに渡せるパラメータは Float, 整数、文字列のみ。to_int > > > と to_str の順で変換を試みる。true/false は 1/0 に変換される。 > > > > > + arg->d.string_data = StringValueCStr(param); > > > > は念のためRVAL2CSTRを使ってください。 > > RVAL2CSTRだとStringValuePtr相当みたいですが、渡した文字列は内部で > g_strdup されるので StringValueCStr したいところです。 StringValueCStrって単にStringValuePtrに\0が入っていないかチェックする かどうかというのが追加されているだけですよね。 g_strdupされると、結局、\0の前までしかコピーされないから、その前に チェックしてあげようと言う意図でしょうか。 (そうだとして)親切は親切ですがここでそこまでやる必要あるかなぁと。 あと、もう一点、RVAL2CSTRを使う理由はRuby側の互換性対策している というのがあります。StringValueCStrを使う場合は、ruby-1.6.x対応を 別途しないといけないですしそれは面倒くさいなぁと。 > > > + } else if (rb_respond_to (param, rb_intern("to_str"))) { > > > + } else if (rb_respond_to (param, rb_intern("to_int"))) { > > > > は微妙ですねぇ(^^;)。 > > to_intの方は、GLib::EnumかGLib::FlagsかInteger型の時、って限定 > > した方が良さそうな気がしますがどうでしょうか。 > > to_strの方は、極端な話to_sにしちゃってif文の優先度を下げるようにするとか。 > > Ruby 的に整数、文字列が期待されている文脈では to_int, to_str を呼ぶと > いう習慣なのかなと思ってこうしてみたのですが… > > 優先順位は逆にしても良いと思いますが、to_s を暗黙の変換に使うのは本来 > の使用目的からはずれると思うので、to_str しないなら何もしない方が良い > と思いますがどうでしょうか? なるほど。それならto_strということで残しましょうか。 あと、エラーメッセージですが、C言語を知っている人を想定した メッセージになってますよね。 "could n't convert an argument to long, float or string" StringかNumeric(IntegerかFloatでも良いけど)かGLib::Enum/GLib::Flagsを 入れてください、的なメッセージの方が親切かも。 > > true/falseのところはGTK+のソースを読むと、G_TYPE_LONGではなく > > G_TYPE_BOOLEANを明示的に使っているところが多いのですが、 > > こちらもそうした方が良いのではないでしょうか。 > > ここは G_TYPE_LONG でないとまずいんです。 なるほど、そうなんですか。勉強になりました。 > > あと、サンプルコードの方も頂いちゃいたいのですがよろしいでしょうか? > > はい。 どうもです。 -- .:% Masao Mutoh<mu...@hi...> |
From: Kenichi K. <ko...@ma...> - 2003-12-20 14:21:39
|
小宮です。 > むとうです。 > > > > > > (案2) > > > gtk_bindingset_copy(const GtkBindingSet* bin)の方をいじる。 > > > > > > static GtkBindingSet* > > > gtk_bindingset_copy(const GtkBindingSet* bin) > > > { > > > /* not copy here */ > > > return bin; > > > } (中略) > > GtkBindingSet GTK側でハッシュに登録して管理してるのでコピーしてしまう > > と動作がおかしくなるように思います。(最初コピーされていたので > > add_signal で登録されたエントリーをactivateした際クラッシュしてました。) > > ということで案2でいけると思うんですけどどうでしょう。 大丈夫でした。rbgobj_boxed_not_copy_obj() はまぎらわしいので消しておきました。 > > > class MyTreeView < Gtk::TreeView > > > bset = binding_set > > > bset.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", > > > Gtk::MOVEMENT_PAGES, 1, false) > > > > > > def initialize > > > : > > > end > > > end > > > > ではこうします。もともとこう書けた方が良いかな、とは思ったのですが本来 > > の Gtk と違うクラスにメソッドを持っていってしまうのがアリなのか分から > > なかったので見送りました。 > > 基本的にはナシなのですが、理由があり議論した後でしたらアリ、 > というスタンスです。 > > あと、忘れてたんですが、上記例ではbinding_setを呼び出す前にregister_type > を呼ぶ必要がありますね。 う〜む、どうやら 名詞_動詞 という命名規則に今一なじめないのは私だけで はないようですね ^^;; ともかく、この辺を反映させたサンプルを用意しました。 > > > > > * Gtk::BindingSet.activate > > > > gtk_bindings_activate()。Gtk::Object#activate_binding とか > > > > の方が良いでしょうか? > > > > > > Gtk::Object#bindings_activateというのがあるのでそちらを使うと > > > よろしいかと。 > > > > 見落してました。これは消します。 > > 一応、インプリメントしていないメソッドも残して置いていただいて、 > インプリしない理由とか書いておくと後々良いと思うんですよね。 > 例えば、上記は、Move to Gtk::Objectとか。Movedかな(^^;)。 ファイルの上の方に以下のように書いておきましたがいかがでしょうか?。 - gtk_bindings_activate() is mapped to Gtk::Object#bindings_activate. - gtk_binding_set_by_class() is mapped to Gtk::Object.binding_set # うぅ、ここにも動詞_名詞が… > > > > > * Gtk::BindingSet#add_signal > > > > gtk_binding_entry_add_signal()。 > > > > > > > > シグナルに渡せるパラメータは Float, 整数、文字列のみ。to_int > > > > と to_str の順で変換を試みる。true/false は 1/0 に変換される。 > > > > > > > + arg->d.string_data = StringValueCStr(param); > > > > > > は念のためRVAL2CSTRを使ってください。 > > > > RVAL2CSTRだとStringValuePtr相当みたいですが、渡した文字列は内部で > > g_strdup されるので StringValueCStr したいところです。 > > StringValueCStrって単にStringValuePtrに\0が入っていないかチェックする > かどうかというのが追加されているだけですよね。 > g_strdupされると、結局、\0の前までしかコピーされないから、その前に > チェックしてあげようと言う意図でしょうか。 > (そうだとして)親切は親切ですがここでそこまでやる必要あるかなぁと。 > あと、もう一点、RVAL2CSTRを使う理由はRuby側の互換性対策している > というのがあります。StringValueCStrを使う場合は、ruby-1.6.x対応を > 別途しないといけないですしそれは面倒くさいなぁと。 了解しました。互換性の方が大事ですね。私は手元に 1.6.x 環境がないので 動作を確認できていませんが… > あと、エラーメッセージですが、C言語を知っている人を想定した > メッセージになってますよね。 > > "could n't convert an argument to long, float or string" > > StringかNumeric(IntegerかFloatでも良いけど)かGLib::Enum/GLib::Flagsを > 入れてください、的なメッセージの方が親切かも。 では、 irb(main):007:0> open(Object.new) TypeError: cannot convert Object into String なので can not conver Object into String, Numeric, GLib::Enum/GLib::Flags or True/False としてみました。 サンプルコードで Page#initialize の中で super を super() としないと SEGV していました。原因は rbgobj_object.c:gobj_initialize で params_hash がハッシュかどうか確認していない事でした。似たようなところ もう一箇所とあわせてパッチをつけておきます。 小宮 #!/usr/local/bin/ruby =begin bindings.rb - Ruby/GTK sample script. Copyright (c) 2002,2003 Ruby-GNOME2 Project Team This program is licenced under the same licence as Ruby-GNOME2. $Id: $ =end =begin Usage: bindings.rb <filename> Following key bindings are effective in the TextView area. <space> : scroll down by one page <backspace> : scroll up by one page j : move cursor donw by one line k : move cursor up by one line clicking buttons cause following effect "space" : same as pressing <space> in text view area. "back_space" : same as pressing <backspace> in text view area. "cancel j/k" : disable 'j' and 'k' binding =end require 'gtk2' Gtk.init class Pager < Gtk::TextView type_register("Pager") # widget's key binding can be defined like this binding_set.add_signal(Gdk::Keyval::GDK_space, 0, "move_cursor", Gtk::MOVEMENT_PAGES, 1, false) binding_set.add_signal(Gdk::Keyval::GDK_BackSpace, 0, "move_cursor", Gtk::MOVEMENT_PAGES, -1, false) def initialize(path) @path = path super() @buffer = self.buffer load self.editable = false self.set_size_request(400, 400) end def load open(@path).read.each do |line| @buffer.insert_at_cursor(line) end @buffer.place_cursor(@buffer.start_iter) end end path = ARGV[0] || __FILE__ window = Gtk::Window.new window.name = "pager_window" sw = Gtk::ScrolledWindow.new vbox = Gtk::VBox.new hbox = Gtk::HBox.new pager = Pager.new(path) hbox.add button1 = Gtk::Button.new("space") hbox.add button2 = Gtk::Button.new("back_space") hbox.add button3 = Gtk::Button.new("cancel j/k") button1.signal_connect("clicked") do Pager.binding_set.activate(Gdk::Keyval::GDK_space, 0, pager) end button2.signal_connect("clicked") do pager.bindings_activate(Gdk::Keyval::GDK_BackSpace, 0) end # Key bindings can be attached to any widget by # Gtk::BindingSet#add_path # see RC Files section of GTK+ documentation for more detail. bset = Gtk::BindingSet.new("j_and_k") bset.add_signal(Gdk::Keyval::GDK_j, 0, "move_cursor", Gtk::MOVEMENT_DISPLAY_LINES, 1, false) bset.add_signal(Gdk::Keyval::GDK_k, 0, "move_cursor", Gtk::MOVEMENT_DISPLAY_LINES, -1, false) bset.add_path(Gtk::PathType::WIDGET, "pager_window.*.Pager", Gtk::PathPriorityType::APPLICATION) button3.signal_connect("clicked") do bset.entry_clear(Gdk::Keyval::GDK_j, 0) bset.entry_clear(Gdk::Keyval::GDK_k, 0) end sw.add pager vbox.add hbox vbox.add sw window.add vbox window.show_all pager.grab_focus window.signal_connect("destroy") { Gtk.main_quit } Gtk.main diff -d -u -2 -p -r ruby-gnome2/glib/src/rbgobj_object.c ../ruby-gnome2/glib/src/rbgobj_object.c --- ruby-gnome2/glib/src/rbgobj_object.c 2003-11-07 01:53:43.000000000 +0900 +++ ../ruby-gnome2/glib/src/rbgobj_object.c 2003-12-20 22:38:44.000000000 +0900 @@ -65,4 +65,7 @@ gobj_s_gobject_new(argc, argv, self) rb_scan_args(argc, argv, "01", ¶ms_hash); + if (!NIL_P(params_hash)) + Check_Type(params_hash, T_HASH); + if (cinfo->klass != self) rb_raise(rb_eTypeError, "%s isn't registerd class", @@ -381,4 +384,7 @@ gobj_initialize(argc, argv, self) rb_scan_args(argc, argv, "01", ¶ms_hash); + if (!NIL_P(params_hash)) + Check_Type(params_hash, T_HASH); + gobj = rbgobj_gobject_new(RVAL2GTYPE(self), params_hash); diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgtkbindingset.c ../ruby-gnome2/gtk/src/rbgtkbindingset.c --- ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-08-31 03:40:02.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-12-20 22:47:15.000000000 +0900 @@ -10,4 +10,13 @@ ************************************************/ +/* + NOTE: + - gtk_bindings_activate() is mapped to + Gtk::Object#bindings_activate. + + - gtk_binding_set_by_class() is mapped to + Gtk::Object.binding_set + */ + #include "global.h" @@ -18,9 +27,6 @@ static GtkBindingSet* gtk_bindingset_copy(const GtkBindingSet* bin) { - GtkBindingSet* new_bin; - g_return_val_if_fail (bin != NULL, NULL); - new_bin = g_new(GtkBindingSet, 1); - *new_bin = *bin; - return new_bin; + /* GtkBindingSet should not be copied */ + return (GtkBindingSet*)bin; } @@ -43,10 +49,7 @@ binding_initialize(self, set_name) VALUE self, set_name; { - RBGTK_INITIALIZE(self, gtk_binding_set_new(RVAL2CSTR(set_name))); + G_INITIALIZE(self, gtk_binding_set_new(RVAL2CSTR(set_name))); return Qnil; } -/* -GtkBindingSet* gtk_binding_set_by_class (gpointer object_class); -*/ static VALUE @@ -58,10 +61,4 @@ binding_s_find(self, set_name) } -/* Move to Gtk::Object -gboolean gtk_bindings_activate (GtkObject *object, - guint keyval, - GdkModifierType modifiers); -*/ - static VALUE binding_activate(self, keyval, modifiers, object) @@ -82,12 +79,63 @@ binding_entry_clear(self, keyval, modifi } -/* -void gtk_binding_entry_add_signal (GtkBindingSet *binding_set, - guint keyval, - GdkModifierType modifiers, - const gchar *signal_name, - guint n_args, - ...); -*/ +static VALUE +binding_entry_add_signal(argc, argv, self) + int argc; + VALUE* argv; + VALUE self; +{ + VALUE keyval, modifiers, signame, rest; + struct RArray *params; + long i; + VALUE param; + GSList *slist, *free_slist; + + slist = NULL; + + rb_scan_args(argc, argv, "3*", &keyval, &modifiers, &signame, &rest); + + params = RARRAY(rest); + for (i=0; i<params->len; i++) { + GtkBindingArg *arg; + + arg = g_new0 (GtkBindingArg, 1); + slist = g_slist_prepend (slist, arg); + + param = params->ptr[i]; + if (TYPE(param) == T_FLOAT) { + arg->arg_type = G_TYPE_DOUBLE; + arg->d.double_data = NUM2DBL(param); + } else if (rb_respond_to (param, rb_intern("to_int"))) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = NUM2LONG(param); + } else if (param == Qfalse) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = 0; + } else if (param == Qtrue) { + arg->arg_type = G_TYPE_LONG; + arg->d.long_data = 1; + } else if (rb_respond_to (param, rb_intern("to_str"))) { + arg->arg_type = G_TYPE_STRING; + arg->d.string_data = RVAL2CSTR(param); + } else { + rb_raise(rb_eTypeError, + "can not conver %s into String, Numeric, " + "GLib::Enum/GLib::Flags or True/False", + rb_class2name(CLASS_OF(param))); + + } + } + slist = g_slist_reverse (slist); + gtk_binding_entry_add_signall (_SELF(self), NUM2UINT(keyval), RVAL2MOD(modifiers), + RVAL2CSTR(signame), slist); + free_slist = slist; + while (slist) { + g_free (slist->data); + slist = slist->next; + } + g_slist_free (free_slist); + + return self; +} static VALUE @@ -101,29 +149,4 @@ binding_add_path(self, path_type, path_p } -static VALUE -binding_entry_remove(self, keyval, modifiers) - VALUE self, keyval, modifiers; -{ - gtk_binding_entry_remove(_SELF(self), NUM2UINT(keyval), - RVAL2MOD(modifiers)); - - return self; -} - -/* -static VALUE -binding_entry_add_signall(self, keyval, modifiers, signal_name, binding_args) - VALUE self, keyval, modifiers, signal_name, binding_args; -{ - gtk_binding_entry_add_signall(_SELF(self), NUM2UINT(keyval), - NUM2INT(modifiers), RVAL2CSTR(signal_name), - - guint keyval, - GdkModifierType modifiers, - const gchar *signal_name, - GSList *binding_args); -guint gtk_binding_parse_binding (GScanner *scanner); -*/ - void Init_gtk_bindings() @@ -131,9 +154,9 @@ Init_gtk_bindings() VALUE gBinding = G_DEF_CLASS(GTK_TYPE_BINDING_SET, "BindingSet", mGtk); rb_define_method(gBinding, "initialize", binding_initialize, 1); - rb_define_method(gBinding, "find", binding_s_find, 1); + rb_define_singleton_method(gBinding, "find", binding_s_find, 1); rb_define_method(gBinding, "activate", binding_activate, 3); rb_define_method(gBinding, "entry_clear", binding_entry_clear, 2); + rb_define_method(gBinding, "add_signal", binding_entry_add_signal, -1); rb_define_method(gBinding, "add_path", binding_add_path, 3); - rb_define_method(gBinding, "entry_remove", binding_entry_remove, 2); } diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgtkobject.c ../ruby-gnome2/gtk/src/rbgtkobject.c --- ruby-gnome2/gtk/src/rbgtkobject.c 2003-08-21 02:07:04.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgtkobject.c 2003-12-20 20:35:47.000000000 +0900 @@ -121,4 +121,43 @@ gobj_bindings_activate(self, keyval, mod } +/* Move from Bindings */ +static VALUE +gobj_s_binding_set(self) + VALUE self; +{ + GType gtype; + gpointer gclass; + GtkBindingSet* binding_set; + + Check_Type(self, T_CLASS); + + gtype = CLASS2GTYPE(self); + + if (!G_TYPE_IS_CLASSED(gtype)) { + rb_raise(rb_eTypeError, "%s is not a classed GType", + rb_class2name(self)); + } + gclass = g_type_class_ref(gtype); + if (!gclass) { + rb_raise(rb_eRuntimeError, "couldn't get class reference"); + } + if (!GTK_IS_OBJECT_CLASS(gclass)) { + g_type_class_unref(gclass); + rb_raise(rb_eTypeError, "%s is not a Gtk Object class", + rb_class2name(self)); + } + + binding_set = gtk_binding_set_by_class(gclass); + if (!binding_set) { + g_type_class_unref(gclass); + rb_raise(rb_eRuntimeError, "couldn't get BindingSet from %s", + rb_class2name(self)); + } + g_type_class_unref(gclass); + + return BOXED2RVAL(binding_set, GTK_TYPE_BINDING_SET); +} + + void Init_gtk_object() @@ -126,4 +165,6 @@ Init_gtk_object() VALUE gObject = G_DEF_CLASS(GTK_TYPE_OBJECT, "Object", mGtk); + rb_define_singleton_method(gObject, "binding_set", gobj_s_binding_set, 0); + rb_define_method(gObject, "type_name", gobj_get_type_name, 0); rb_define_method(gObject, "flags", gobj_get_flags, 0); |
From: Kazuhiro N. <zn...@mb...> - 2003-12-21 13:36:00
|
西山和広です。 In <1071930126.6030.1.camel@onix> On Sat, 20 Dec 2003 23:22:07 +0900 Kenichi Komiya <ko...@ma...> wrote: > diff -d -u -2 -p -r ruby-gnome2/glib/src/rbgobj_object.c > ./ruby-gnome2/glib/src/rbgobj_object.c > --- ruby-gnome2/glib/src/rbgobj_object.c 2003-11-07 01:53:43.000000000 > +0900 > +++ ../ruby-gnome2/glib/src/rbgobj_object.c 2003-12-20 > 22:38:44.000000000 +0900 > @@ -65,4 +65,7 @@ gobj_s_gobject_new(argc, argv, self) > rb_scan_args(argc, argv, "01", ¶ms_hash); > > + if (!NIL_P(params_hash)) > + Check_Type(params_hash, T_HASH); > + > if (cinfo->klass != self) > rb_raise(rb_eTypeError, "%s isn't registerd class", 本題とは全然関係ないところですが、registeredのtypoでしょうか? -- |ZnZ(ゼット エヌ ゼット) |西山和広(Kazuhiro NISHIYAMA) |
From: Masao M. <mu...@hi...> - 2003-12-21 13:55:33
|
むとうです。 On Sun, 21 Dec 2003 22:35:52 +0900 Kazuhiro NISHIYAMA <zn...@mb...> wrote: > 西山和広です。 > > if (cinfo->klass != self) > > rb_raise(rb_eTypeError, "%s isn't registerd class", > > 本題とは全然関係ないところですが、registeredのtypoでしょうか? ほんとだ。全然気づきませんでした。どうもありがとうございます。 #私の方で直しておきました。 -- .:% Masao Mutoh<mu...@hi...> |
From: Masao M. <mu...@hi...> - 2003-12-20 15:24:07
|
むとうです。 On Sat, 20 Dec 2003 23:22:07 +0900 Kenichi Komiya <ko...@ma...> wrote: > 小宮です。 > > ということで案2でいけると思うんですけどどうでしょう。 > > 大丈夫でした。rbgobj_boxed_not_copy_obj() はまぎらわしいので消しておきました。 よかった。 ってことはrbgobj_boxed_not_copy_obj()って使えないのかな...。 やはりこの辺は一度整理しないとですねぇ(遠い目)。 > > あと、忘れてたんですが、上記例ではbinding_setを呼び出す前にregister_type > > を呼ぶ必要がありますね。 > > う〜む、どうやら 名詞_動詞 という命名規則に今一なじめないのは私だけで > はないようですね ^^;; おっと、type_registerでしたね。 これは最近メソッド名が変わったんです。まだ勘違いしてるな。 まぁ、でも、拡張ライブラリは元のライブラリにひきづられてしまうので やむを得ないかなと。 > ともかく、この辺を反映させたサンプルを用意しました。 おー、すばらしい。いただきます。 > > 一応、インプリメントしていないメソッドも残して置いていただいて、 > > インプリしない理由とか書いておくと後々良いと思うんですよね。 > > 例えば、上記は、Move to Gtk::Objectとか。Movedかな(^^;)。 > > ファイルの上の方に以下のように書いておきましたがいかがでしょうか?。 そうですね。了解です。 > - gtk_bindings_activate() is mapped to > Gtk::Object#bindings_activate. > > - gtk_binding_set_by_class() is mapped to > Gtk::Object.binding_set > > "could n't convert an argument to long, float or string" > > > > StringかNumeric(IntegerかFloatでも良いけど)かGLib::Enum/GLib::Flagsを > > 入れてください、的なメッセージの方が親切かも。 > > では、 > > irb(main):007:0> open(Object.new) > TypeError: cannot convert Object into String > > なので > > can not conver Object into String, Numeric, GLib::Enum/GLib::Flags or > True/False > > としてみました。 良いと思います。 #True/Falseってtrue/falseのTypoですよね? > サンプルコードで Page#initialize の中で super を super() としないと > SEGV していました。原因は rbgobj_object.c:gobj_initialize で > params_hash がハッシュかどうか確認していない事でした。似たようなところ > もう一箇所とあわせてパッチをつけておきます。 > > 小宮 ありがたく、取り込ませていただきました。 Ruby/GLibの方もやっちゃったのでまずかったらフォローしてください>さかいさん。 それでは。 -- .:% Masao Mutoh<mu...@hi...> |
From: Masao M. <mu...@hi...> - 2003-12-20 15:32:56
|
小宮さん むとうです。 取り込んだ後になんですが(^^;)。 サンプルを試したところ、固まりました。 手順はひたすらspaceとbackspaceを押して上へ行ったり 下へ行ったりする事を繰り返したら出ました。 GCされちゃってるのかなぁと思ってGtk.mainの直前に GC.startをやるようにしたところやはり落ちました。 ひとまずご報告ということで。 -- .:% Masao Mutoh<mu...@hi...> |
From: Kenichi K. <ko...@ma...> - 2003-12-21 00:01:56
|
小宮です。 > むとうです。 > > 取り込んだ後になんですが(^^;)。 > > サンプルを試したところ、固まりました。 > > 手順はひたすらspaceとbackspaceを押して上へ行ったり > 下へ行ったりする事を繰り返したら出ました。 > GCされちゃってるのかなぁと思ってGtk.mainの直前に > GC.startをやるようにしたところやはり落ちました。 すいません、うっかりしていました。 rbgobj_boxed_initialize() が boxed_holder->own = TRUE してしまうので boxed_holder の中の GtkBindingSet のポインタが GC 時に free されてしま いますね。 案としては 案3 : rbgobj_boxed_not_copy_obj() した上で、new を再定義して rbgobj_make_boxed() でインスタンスを作る。サブクラス化に 問題がないように initialize も呼ぶ。 案4 : free 用の関数ポインタとして何もしない関数を渡す 案5 : Ruby 側にオーナーシップがまったく無い状態に対応する新しいフラ グを RGObjClassFlag に追加する。(セットすると copy も free もしなくなる) 個人的には案5がよさそうに思うのですが、他のフラグの意味もまだ十分把握 していなので私の手にはあまります。GtkBindingSet 以外にも使い道が見付かっ た時点でやるのが良いかもしれません。 とりあえず楽そうな案4を実装してみました。手元では Gtk.main の前に GC.start を入れてもフリーズしなくなりました。 小宮 diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgtkbindingset.c ../ruby-gnome2/gtk/src/rbgtkbindingset.c --- ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-12-21 08:57:13.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgtkbindingset.c 2003-12-21 08:27:48.000000000 +0900 @@ -31,4 +31,11 @@ gtk_bindingset_copy(const GtkBindingSet* } +/*****************************************/ +static void +gtk_bindingset_free(GtkBindingSet* bin) +{ + /* GtkBindingSet should not be freed */ +} + GType gtk_bindingset_get_type(void) @@ -38,5 +45,5 @@ gtk_bindingset_get_type(void) our_type = g_boxed_type_register_static ("GtkBindingSet", (GBoxedCopyFunc)gtk_bindingset_copy, - (GBoxedFreeFunc)g_free); + (GBoxedFreeFunc)gtk_bindingset_free); return our_type; } |
From: Masao M. <mu...@hi...> - 2003-12-21 08:21:42
|
むとうです。 On Sun, 21 Dec 2003 09:02:26 +0900 Kenichi Komiya <ko...@ma...> wrote: > 小宮です。 > > > むとうです。 > > > > 取り込んだ後になんですが(^^;)。 > > > > サンプルを試したところ、固まりました。 > > > > 手順はひたすらspaceとbackspaceを押して上へ行ったり > > 下へ行ったりする事を繰り返したら出ました。 > > GCされちゃってるのかなぁと思ってGtk.mainの直前に > > GC.startをやるようにしたところやはり落ちました。 > > すいません、うっかりしていました。 > > rbgobj_boxed_initialize() が boxed_holder->own = TRUE してしまうので > boxed_holder の中の GtkBindingSet のポインタが GC 時に free されてしま > いますね。 > > 案としては > > 案3 : rbgobj_boxed_not_copy_obj() した上で、new を再定義して > rbgobj_make_boxed() でインスタンスを作る。サブクラス化に > 問題がないように initialize も呼ぶ。 > > 案4 : free 用の関数ポインタとして何もしない関数を渡す > > 案5 : Ruby 側にオーナーシップがまったく無い状態に対応する新しいフラ > グを RGObjClassFlag に追加する。(セットすると copy も free > もしなくなる) > > 個人的には案5がよさそうに思うのですが、他のフラグの意味もまだ十分把握 > していなので私の手にはあまります。GtkBindingSet 以外にも使い道が見付かっ > た時点でやるのが良いかもしれません。 なるほど。 小宮さんのオーナーシップの話に被るのですが、 1. GTK+側がメモリ管理しないので、 Ruby-GNOME2側が責任持ってメモリ管理する場合 2. GTK+側がメモリ管理するので、Ruby-GNOME2側はAPIを通して使うだけ の2通りがイマイチスッキリしない形で共存してるんですよね、GTK+って。 g_object_ref/unrefがあるのでGLib::Object系は良いんですけど、それ以外が。 まぁ、ミニマムに見ればそれぞれが必要な形に最適化されてるってことだとは 思うのですが。 あと、 3. GTK+側がメモリをアロケートするけど、freeはユーザ(Ruby-GNOME2)側 てのもあったような。 この辺は注意しないといけないんだろうけどよく忘れるところでもあるん ですよねぇ。もう少しどうにかならないモノかなぁ、GTK+側で。 > とりあえず楽そうな案4を実装してみました。手元では Gtk.main の前に > GC.start を入れてもフリーズしなくなりました。 いや、楽そうというのはあるのですが、このような対応は局所的で全く問題 無いと思っています。 このようなイリーガルな対応を全てRuby/GLib側で吸収するつもりは無いです。 というわけでそのままいただきました。どうもありがとうございます。 -- .:% Masao Mutoh<mu...@hi...> |
From: Kenichi K. <ko...@ma...> - 2003-12-21 06:39:16
|
小宮です。 > むとうです。 > > おっと、見落としてましたがRBGTK_INITIALIZE使ってますね、これ(汗。 > G_INITIALIZEにしないとダメです。 > RBGTK_INITIALIZEはGtk::Objectのサブクラスにのみ有効です。 > #ってこれもドキュメント化しとかないとだめですね。 同様に G_INITIALIZE を呼ぶべきところで RBGTK_INITIALIZE が呼ばれている ケースがあと三個所ありました。 TextTag と TextTagTable は動作を確認しましたが、Gdk::Colormap は 使い方がそもそもよくわからなかったのでコンパイルを通しただけです。 一応スクリプトを書いて網羅的にしらべたのでこのパターンはこれで終りだと 思います。 小宮 diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgdkcolormap.c ../ruby-gnome2/gtk/src/rbgdkcolormap.c --- ruby-gnome2/gtk/src/rbgdkcolormap.c 2003-10-03 21:51:01.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgdkcolormap.c 2003-12-21 15:28:22.000000000 +0900 @@ -26,5 +26,5 @@ gdkcmap_initialize(self, visual, allocat GdkColormap *cmap = gdk_colormap_new(GDK_VISUAL(RVAL2GOBJ(visual)), RTEST(allocate)); - RBGTK_INITIALIZE(self, cmap); + G_INITIALIZE(self, cmap); return Qnil; } diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgtktexttag.c ../ruby-gnome2/gtk/src/rbgtktexttag.c --- ruby-gnome2/gtk/src/rbgtktexttag.c 2003-08-21 02:07:04.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgtktexttag.c 2003-12-21 11:24:35.000000000 +0900 @@ -20,5 +20,5 @@ initialize(argc, argv, self) VALUE name; rb_scan_args(argc, argv, "01", &name); - RBGTK_INITIALIZE(self, gtk_text_tag_new(NIL_P(name) ? NULL : RVAL2CSTR(name))); + G_INITIALIZE(self, gtk_text_tag_new(NIL_P(name) ? NULL : RVAL2CSTR(name))); return Qnil; } diff -d -u -2 -p -r ruby-gnome2/gtk/src/rbgtktexttagtable.c ../ruby-gnome2/gtk/src/rbgtktexttagtable.c --- ruby-gnome2/gtk/src/rbgtktexttagtable.c 2003-06-27 00:15:32.000000000 +0900 +++ ../ruby-gnome2/gtk/src/rbgtktexttagtable.c 2003-12-21 12:03:37.000000000 +0900 @@ -10,5 +10,4 @@ ************************************************/ #include "global.h" - #define _SELF(self) (GTK_TEXT_TAG_TABLE(RVAL2GOBJ(self))) #define RVAL2TAG(t) (GTK_TEXT_TAG(RVAL2GOBJ(t))) @@ -18,5 +17,5 @@ txt_tt_initialize(self) VALUE self; { - RBGTK_INITIALIZE(self, gtk_text_tag_table_new()); + G_INITIALIZE(self, gtk_text_tag_table_new()); return Qnil; } |
From: Masao M. <mu...@hi...> - 2003-12-21 08:28:33
|
むとうです。 On Sun, 21 Dec 2003 15:39:47 +0900 Kenichi Komiya <ko...@ma...> wrote: > > 小宮です。 > > > むとうです。 > > > > おっと、見落としてましたがRBGTK_INITIALIZE使ってますね、これ(汗。 > > G_INITIALIZEにしないとダメです。 > > RBGTK_INITIALIZEはGtk::Objectのサブクラスにのみ有効です。 > > #ってこれもドキュメント化しとかないとだめですね。 > > 同様に G_INITIALIZE を呼ぶべきところで RBGTK_INITIALIZE が呼ばれている > ケースがあと三個所ありました。 > > TextTag と TextTagTable は動作を確認しましたが、Gdk::Colormap は > 使い方がそもそもよくわからなかったのでコンパイルを通しただけです。 > > 一応スクリプトを書いて網羅的にしらべたのでこのパターンはこれで終りだと > 思います。 うおー、助かります。 どうもありがとうございました。 ちなみに、スクリプトで網羅的にってことは、他のライブラリをチェックする ことも可能でしょうか? もし、簡単にできるようでしたらgnome, gnomecanvas, gtkhtml2, gtkglext あたりがRBGTK_INITIALIZEを使ってるのでチェックしてみて頂けると助かります。 それでは。 -- .:% Masao Mutoh<mu...@hi...> |
From: Kenichi K. <ko...@ma...> - 2003-12-21 10:56:32
|
小宮です。 > むとうです。 > > ちなみに、スクリプトで網羅的にってことは、他のライブラリをチェックする > ことも可能でしょうか? > もし、簡単にできるようでしたらgnome, gnomecanvas, gtkhtml2, gtkglext > あたりがRBGTK_INITIALIZEを使ってるのでチェックしてみて頂けると助かります。 > > それでは。 スクリプトといってもそんな大層なものではないので他のライブラリに適用す るのはちょっと難しです。 上の四つあわせても RBGTK_INITIALIZE を使っているところは 23 個所しかな いので目視チェックで十分な気がしますけど。 すいません、今日はちょっと気力が付きているのでまたそのうち。 小宮 |
From: Masao M. <mu...@hi...> - 2003-12-21 11:21:30
|
むとうです。 On Sun, 21 Dec 2003 19:57:02 +0900 Kenichi Komiya <ko...@ma...> wrote: > 小宮です。 > > > むとうです。 > > > > ちなみに、スクリプトで網羅的にってことは、他のライブラリをチェックする > > ことも可能でしょうか? > > もし、簡単にできるようでしたらgnome, gnomecanvas, gtkhtml2, gtkglext > > あたりがRBGTK_INITIALIZEを使ってるのでチェックしてみて頂けると助かります。 > > > > それでは。 > > スクリプトといってもそんな大層なものではないので他のライブラリに適用す > るのはちょっと難しです。 > > 上の四つあわせても RBGTK_INITIALIZE を使っているところは 23 個所しかな > いので目視チェックで十分な気がしますけど。 あ、いえいえ、それなら後々私の方でやりますので気にしないでください(^^;)。 それでは。 -- .:% Masao Mutoh<mu...@hi...> |