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