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); |