PageRenderTime 40ms CodeModel.GetById 31ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

/src/wrappers/gobject/library/g_object_factory.e

http://github.com/tybor/Liberty
Specman e | 186 lines | 103 code | 22 blank | 61 comment | 9 complexity | 0241ebc83ccf9cd137ddcac57d9369a4 MD5 | raw file
  1indexing
  2	description: "Retrieve a G_OBJECT wrapper from the pointer stored in the C low-level Gobject's ."
  3	copyright: "(C) 2006 Paolo Redaelli "
  4	license: "LGPL v2 or later"
  5	date: "$Date:$"
  6	revision: "$Revision:$"
  7
  8deferred class G_OBJECT_FACTORY [ITEM -> G_OBJECT]
  9	-- A factory for G_OBJECTS. Given a pointer to a valid GObject C 
 10	-- data structure it return the fittest wrapper.
 11
 12	-- If the underlying C object ("C") has already been wrapped by an
 13	-- Eiffel object ("E"), `wrapper' will be "E". When "E" - the first,
 14	-- wrapper for "C" was created a back-reference to "E" was stored
 15	-- into "C"; see G_OBJECT's `store_eiffel_wrapper' for the details.
 16
 17	-- If "C" does not have an associated wrapper the inheritance tree of
 18	-- GObject system type is climbed until a creation agent is found in the
 19	-- dictionary `creation_agents'; both GType and actual type name are looked
 20	-- upon.  this dictionary is filled with proper agents during the
 21	-- initialization of the Eiffel wrapper library.
 22
 23	-- At initialization time each library wrapper that implements
 24	-- non-deferred G_OBJECT heirs is required to create an "archetype"
 25	-- object of each effective type and "connect" it to the underlying
 26	-- GType. This is done creating the archetype with the `dummy'
 27	-- creation procedure; it takes care of storing a reference to
 28	-- itself in the proper GType.
 29
 30	-- Actually the Eiffel type system is stretched a little: we
 31	-- re-wrap `g_object_get_qdata' as `g_object_get_eiffel_wrapper ', changing
 32	-- the signature of the result from POINTER to ITEM, to avoid an
 33	-- ugly type-convertion (aka cast) on the Eiffel side.
 34
 35inherit 
 36	WRAPPER_FACTORY[ITEM]
 37
 38insert
 39	G_OBJECT_EXTERNALS
 40	G_TYPE_EXTERNALS
 41	SHARED_CREATION_DICTIONARY
 42	SHARED_EIFFEL_KEY
 43	EXCEPTIONS undefine copy,is_equal end 
 44
 45feature {WRAPPER,WRAPPER_HANDLER}
 46	existant_wrapper (a_pointer: POINTER): ITEM is
 47			-- Retrieve the eiffel wrapper object from gobject's
 48			-- `a_pointer' or Void when it does not have a wrapper conforming
 49			-- to ITEM (i.e. if you ask for GTK_RADIO_BUTTON when it is
 50			-- actually a GTK_BUTTON Result is still Void).
 51
 52			-- Useful when you precisely know the type of a wrapper but
 53			-- you still want to avoid wrapper duplication; i.e.:
 54
 55			-- pointer := get_foo(handle)
 56			-- Result := factory.existant_wrapper(pointer)
 57			-- if Result=Void then create Result.from_external_pointer(pointer) end
 58		require pointer_is_gobject: g_is_object(a_pointer)=1
 59		do
 60			Result ?= g_object_get_eiffel_wrapper (a_pointer, eiffel_key.quark)
 61		end
 62
 63	existant_wrapper_or_void (a_pointer: POINTER): ITEM is
 64		do
 65			if a_pointer.is_not_null then
 66				Result := existant_wrapper(a_pointer)
 67			end
 68		end
 69
 70	wrapper (a_pointer: POINTER): ITEM is
 71			-- The eiffel wrapper object for gobject's `a_pointer'. It the
 72			-- GObject does not have a wrapper, Result is created using an
 73			-- agent function from creation_agents dictionary using
 74			-- `a_pointer'. These creation agents are registered by the
 75			-- library at startup.
 76
 77			-- TODO: If REsult is created the underlying GObject is reffed
 78		require else pointer_is_gobject: g_is_object(a_pointer)=1
 79		do
 80			Result := unreffed_wrapper(a_pointer)
 81			Result.ref
 82		end
 83	
 84	unreffed_wrapper (a_pointer: POINTER): ITEM is
 85			-- A non-referred wrapper. See `wrapper' for further
 86			-- informations
 87		require pointer_is_gobject: g_is_object(a_pointer)/=0
 88		local
 89			generic_function: FUNCTION[TUPLE[POINTER],G_OBJECT] 
 90			function: FUNCTION[TUPLE[POINTER],ITEM]
 91			typename: STRING; type: like g_type --; fundamental_type_found: BOOLEAN
 92		do
 93			create typename.from_external_copy(g_object_type_name(a_pointer))
 94			debug	
 95				std_error.put_string(once "G_OBJECT_FACTORY.wrapper(") std_error.put_pointer(a_pointer)
 96				std_error.put_string(once "): is a ") std_error.put_string(typename)
 97			end
 98			Result := existant_wrapper (a_pointer)
 99			if Result/=Void then
100				debug 
101					std_error.put_string(once " wrapped by a ")
102					std_error.put_line(Result.generator)
103				end
104			else
105				-- Climb the hierarchy until we find and a creation
106				-- function. Starting examining the parent class of the
107				-- object; we already know that current class does not
108				-- have a function.
109				from 
110					type :=g_object_type(a_pointer) 
111					generic_function := creation_agents.reference_at(typename)
112					function ?= generic_function
113				until Result/=Void or else g_type_is_fundamental(type)
114				loop
115					if function=Void then 
116						debug
117							std_error.put_string(" "+typename+" ("+type.out+") does not have a creation function agent; ")
118						end
119						type:=g_type_parent(type)
120						typename.from_external_copy(g_object_type_name(a_pointer))
121						if g_type_is_fundamental(type) then 
122							raise("G_OBJECT_FACTORY.(unreffed_)wrapper: %
123							%I climbed GObject hierarchy to find a class known by Eiffel %
124							%but I come to the fundamental type: no known wrapper.") 
125						end
126						generic_function := creation_agents.reference_at(typename)
127						function ?= generic_function
128					else 
129						debug
130							std_error.put_line("Invoking "+function.out+" for "+typename+" ("+type.out+").")
131						end
132						Result:=function.item([a_pointer])
133					end
134				end
135			end
136		end
137
138	unreffed_wrapper_or_void (a_pointer: POINTER): ITEM is
139			-- A (unreffed) wrapper for `a_pointer' or Void if `a_pointer' is
140			-- default_pointer (NULL in C). See `wrapper_or_void' for 
141			-- further informations
142		do
143			if a_pointer.is_not_null then
144				Result := unreffed_wrapper(a_pointer)
145			end
146		ensure void_case: a_pointer.is_null implies Result = Void
147		end
148
149	has_eiffel_wrapper_stored (a_pointer: POINTER): BOOLEAN is
150			-- Have `a_pointer' already been wrapped?
151
152			-- Note: if True, the cost of this query is the same of a
153			-- call to `wrapper'. So a code pattern like:
154
155			-- if has(c_pointer) 
156			-- then Result:=wrapper(c_pointer)
157			-- else create Result.from_external_pointer(c_pointer) 
158			-- end
159
160			-- is on average twice slower than the equivalent:
161			-- "Result:=wrapper(c_pointer)".
162
163			-- This feature is actually useful only in pre and 
164			-- postconditions.
165		do
166			Result := (g_object_get_qdata (a_pointer, eiffel_key.quark).is_not_null)
167		end
168
169	type_name_from_gobject_pointer (a_pointer: POINTER): STRING is
170			-- Retrieve the type name from gobject's `a_pointer'.
171		require
172			pointer_not_null: a_pointer.is_not_null
173		do
174			-- TODO: use a CONST_STRING... currently the following violates some precondtions in STRING
175			create {CONST_STRING} Result.from_external(g_object_type_name(a_pointer))
176			-- we fallback to a less efficient
177			-- create Result.from_external_copy(g_object_type_name(a_pointer))
178		end
179
180feature {} -- External call
181	g_object_get_eiffel_wrapper (a_object: POINTER; a_quark: INTEGER_32): G_OBJECT is
182			-- This function gets back the Eiffel wrapper stored using `g_object_set_qdata'
183		external "C use <glib-object.h>"
184		alias "g_object_get_qdata"
185		end
186end