Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid having to redefine 'new' constructors when overloading initialize #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions samples/gtk_keep_wrapper.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require "../src/gtk/autorun"

class MyWidget < Gtk::Button
@foo : Int32?

def instantiate
self.label = "Default Label"
@foo = MyWidget.next_foo

keep_wrapper
end

@@foo = -1
def self.next_foo
@@foo += 1
end

def foo
@foo
end
end

w = Gtk::Window.new
w.add v=Gtk::VBox.new(false,0)

3.times do |i|
v.pack_start(mw=MyWidget.new, false, false, 1)

mw.label = "button#{i}"

mw.on_clicked do |b|
p b.as(MyWidget).foo
v.foreach do |c| p c.as(MyWidget).foo end
end
end

v.foreach do |c| p c end

w.connect "delete-event", ->Gtk.main_quit

w.show_all

18 changes: 3 additions & 15 deletions samples/gtk_subclasses.cr
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
require "../src/gtk"

class MyWindow < Gtk::ApplicationWindow
def self.new(app : Gtk::Application)
super
end

def initialize(ptr)
super(ptr)

def instantiate
self.border_width = 10
self.title = "Hello"
add Gtk::Label.new("Hello")
end
end

class MyApp < Gtk::Application
def self.new(id, flags : Gio::ApplicationFlags)
super
end

def initialize(ptr)
super(ptr)

def instantiate
on_activate do |application|
window = MyWindow.new(self)
window.connect "destroy", &->quit
Expand All @@ -31,4 +19,4 @@ class MyApp < Gtk::Application
end

app = MyApp.new("org.crystal.mysample", :flags_none)
app.run
app.run
2 changes: 1 addition & 1 deletion src/g_i_repository/info/callable_info.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module GIRepository
end

def convert_to_crystal(variable)
"#{@definition}.new(#{variable})"
"#{@definition}.cast(#{variable})"
end

def convert_from_crystal(variable)
Expand Down
5 changes: 4 additions & 1 deletion src/g_i_repository/info/function_info.cr
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ module GIRepository
io << "\n#{indent} GLib::Error.assert __error" if throws?

unless skip_return?
io << "\n#{indent} #{"cast " if constructor?}#{return_type.convert_to_crystal("__return_value")}"
io << "\n#{indent} ins=#{"cast " if constructor?}#{return_type.convert_to_crystal("__return_value")}"
io << " if __return_value" if may_return_null?
io << "\n#{indent} ins"
io << ".as(self)" if constructor?
io << " if __return_value" if may_return_null?
io << '\n'
else
io << "\n#{indent} nil\n"
Expand Down
6 changes: 4 additions & 2 deletions src/g_i_repository/info/type_info.cr
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ module GIRepository
when LibGIRepository::TypeTag::INTERFACE
interface = self.interface
case interface
when ObjectInfo, StructInfo, UnionInfo
when ObjectInfo
"#{interface.full_constant}.cast(#{variable})"
when StructInfo, UnionInfo
"#{interface.full_constant}.new(#{variable})"
else
variable
Expand All @@ -128,7 +130,7 @@ module GIRepository
def convert_from_crystal(variable)
case tag
when LibGIRepository::TypeTag::INTERFACE
pointer? ? "#{variable}.to_unsafe.as(Lib#{interface.full_constant}*)" : variable
pointer? ? "#{variable}.void_pointer.as(Lib#{interface.full_constant}*)" : variable
when LibGIRepository::TypeTag::ARRAY,
LibGIRepository::TypeTag::GLIST,
LibGIRepository::TypeTag::GSLIST,
Expand Down
4 changes: 2 additions & 2 deletions src/g_i_repository/wrapper_generator.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ module GIRepository
def write_constructor(libname, io, indent="")
io.puts "#{indent} @pointer : Void*"
io.puts "#{indent} def initialize(pointer : #{ptr_type(libname)})"
io.puts "#{indent} @pointer = pointer.as(Void*)"
io.puts "#{indent} @pointer = pointer.as(Void*)"
io.puts "#{indent} end"
io.puts
end

def write_to_unsafe(libname, io, indent="")
io.puts "#{indent} def to_unsafe"
io.puts "#{indent} def to_unsafe : #{ptr_type(libname)}"
io.puts "#{indent} @pointer.not_nil!.as(#{ptr_type(libname)})"
io.puts "#{indent} end"
io.puts
Expand Down
102 changes: 102 additions & 0 deletions src/g_object/wrapped.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
module GObject
module WrappedType
GOBJECT_IS_WRAPPED_TAG = "__crystal_gobject_wrapper_id__"

@@n_wrapped = UInt64.new(-1)
@@wrapped = Hash(UInt64?, GObject::WrappedType?).new

def self.set_wrapped(ins)
@@n_wrapped += 1

ins.set_data_full(GOBJECT_IS_WRAPPED_TAG, Pointer(UInt64).new(@@n_wrapped+1).as(Void*), ->(d : Void*){
GObject::WrappedType.unwrap(d.address-1)
nil
})

@@n_wrapped
end

def self.keep_wrapper(ins)
if ins.has_wrapper?
id = ins.wrapper_id
else
id = set_wrapped ins
end

@@wrapped[id] = ins
end

def self.unwrap(id : UInt64)
@@wrapped.delete id
end

def self.wrapper(id : UInt64?)
@@wrapped[id]
rescue KeyError
nil
end

def self.wrapper(ptr)
if id=wrapper_id(ptr.as(LibGObject::Object*))
wrapper(id)
end
end

def self.wrapper_id(ptr) : UInt64?
addr = LibGObject.object_get_data(ptr.as(LibGObject::Object*), GObject::WrappedType::GOBJECT_IS_WRAPPED_TAG).address
if addr >= 0
addr-1
else
nil
end
end

def self.has_wrapper?(id : Int)
@@wrapped.has_key?(id)
end

def self.has_wrapper?(ptr)
@@wrapped.has_key?(wrapper_id(ptr.as(LibGObject::Object*)))
end

def set_data_full(key, data, cb)
LibGObject.object_set_data_full(@pointer.as(LibGObject::Object*), key.to_unsafe, data ? data : nil,cb)
data
end

def set_wrapped
return if !is_a?(GObject::Object)
unless has_wrapper?
GObject::WrappedType.set_wrapped self
end
end

def has_wrapper?
return unless is_a?(GObject::Object)
GObject::WrappedType.has_wrapper?(@pointer.as(LibGObject::Object*))
end

def wrapper_id
if has_wrapper?
GObject::WrappedType.wrapper_id(@pointer.as(LibGObject::Object*))
end
end

def keep_wrapper
GObject::WrappedType.keep_wrapper self
end

def wrapper
GObject::WrappedType.wrapper(self)
end

def instantiate
raise "foo"
end
end
end

lib LibGObject
alias DestroyNotify = Void* -> Void
fun object_set_data_full = g_object_set_data_full(this : LibGObject::Object*, key : UInt8*, data : Void*, closure : LibGObject::DestroyNotify) : Void
end
44 changes: 38 additions & 6 deletions src/g_object/wrapped_type.cr
Original file line number Diff line number Diff line change
@@ -1,22 +1,54 @@
require "./wrapped.cr"

module GObject
module WrappedType
macro def_cast(libtype)
module WrappedType
def instantiate()
end

macro init(&b)
def instantiate
{{b.body}}
end
end

macro def_cast(libtype, type)
{% if libtype.resolve? %}
def self.cast(object) : self
new(object.to_unsafe.as({{libtype}}*))
def self.cast(object : GObject::WrappedType) : self
if object.has_wrapper?
if ins = object.wrapper
return ins.as(self)
end
end

ins = new(object.void_pointer.as({{libtype}}*)).as(self)
ins.set_wrapped
ins.instantiate
ins
end

def self.cast(ptr : Pointer({{libtype}}))
if ins=GObject::WrappedType.wrapper(ptr.as(LibGObject::Object*))
return ins.as(self)
end

new(ptr).as(self)
end
{% end %}
end

def void_pointer
@pointer
end

macro included
macro inherited
\{% begin %}
def_cast(Lib\{{@type}})
def_cast(Lib\{{@type}}, \{{@type}})
\{% end %}
end

\{% begin %}
def_cast(Lib\{{@type}})
def_cast(Lib\{{@type}}, \{{@type}})
\{% end %}
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/generated/g_object/type_info.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module GObject
@pointer = pointer.as(Void*)
end

def to_unsafe
def to_unsafe : LibGObject::TypeInfo*
@pointer.not_nil!.as(LibGObject::TypeInfo*)
end

Expand Down Expand Up @@ -104,7 +104,7 @@ module GObject
end

def value_table=(value : GObject::TypeValueTable)
to_unsafe.as(LibGObject::TypeInfo*).value.value_table = value.to_unsafe.as(LibGObject::TypeValueTable*)
to_unsafe.as(LibGObject::TypeInfo*).value.value_table = value.void_pointer.as(LibGObject::TypeValueTable*)
end

end
Expand Down
22 changes: 21 additions & 1 deletion src/gtk/gtk.cr
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,24 @@ module Gtk
run ARGC_UNSAFE, ARGV_UNSAFE
end
end
end
end

class Gtk::Container
def children
a = [] of Gtk::Widget

foreach(-> (c : LibGtk::Widget*, d : Void*) {
d.as(Array(Gtk::Widget)*).value << Gtk::Widget.cast(c)
nil
}, pointerof(a).as(Void*))

a
end

def foreach(&cb : Gtk::Widget -> _)
foreach(-> (c : LibGtk::Widget*, d : Void*) {
Proc(Gtk::Widget, Nil).new(d, Pointer(Void).null).call Gtk::Widget.cast(c)
nil
}, cb.pointer)
end
end