/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

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