5353 */
5454abstract class GObject
5555{
56+ /**
57+ */
58+ private static array $ handleTable = [];
59+ private static int $ nextIndex = 0 ;
60+
5661 /**
5762 * A pointer to the underlying GObject.
5863 *
@@ -117,21 +122,26 @@ public function unref(): void
117122 */
118123 public function signalConnect (string $ name , Closure $ callback ): void
119124 {
120- $ marshal = self ::buildMarshal ($ name , $ callback );
125+ echo "signalConnect: \n" ;
126+
127+ $ marshal = self ::getMarshal ($ name );
128+ $ handle = self ::getHandle ($ callback );
121129
130+ $ sig = \FFI ::arrayType (FFI ::ctypes ("GCallback " ), [1 ]);
131+ $ c_callback = \FFI ::new ($ sig );
132+ $ c_callback [0 ] = $ marshal ;
133+
122134 $ id = FFI ::gobject ()->g_signal_connect_data ($ this ->pointer ,
123135 $ name ,
124- $ marshal ,
125- null ,
136+ $ c_callback [ 0 ] ,
137+ $ handle ,
126138 null ,
127139 0 );
128140 if ($ id === 0 ) {
129141 throw new Exception ("unable to connect signal $ name " );
130142 }
131143
132- // the marshaller must not be GCed
133- // FIXME ... _references must be copied to all child objects in call()
134- $ this ->_references [] = $ marshal ;
144+ echo "signalConnect: done \n" ;
135145 }
136146
137147 /* Ideally, we'd use the "user" pointer of signal_connect to hold the
@@ -140,32 +150,71 @@ public function signalConnect(string $name, Closure $callback): void
140150 * build a custom closure for every signal connect with the callback
141151 * embedded within it.
142152 */
143- private static function buildMarshal (string $ name , Closure $ callback ):
144- Closure
153+ private static function getMarshal (string $ name ) : CData
145154 {
146155 switch ($ name ) {
147156 case 'preeval ' :
148157 case 'eval ' :
149158 case 'posteval ' :
150- return static function (
151- CData $ image_pointer ,
152- CData $ progress_pointer ,
153- ?CData $ user
154- ) use (&$ callback ): void {
155- $ image = new Image ($ image_pointer );
159+ $ marshal = static function (
160+ CData $ imagePointer ,
161+ CData $ progressPointer ,
162+ CData $ handle ) : void {
163+ $ image = new Image ($ imagePointer );
156164 // Image() will unref on gc, so we must ref
157- FFI ::gobject ()->g_object_ref ($ image_pointer );
165+ FFI ::gobject ()->g_object_ref ($ imagePointer );
158166
159167 // FIXME ... maybe wrap VipsProgress as a php class?
160168 $ progress = \FFI ::cast (FFI ::ctypes ("VipsProgress " ),
161- $ progress_pointer );
169+ $ progressPointer );
170+
171+ $ callback = self ::fromHandle ($ handle );
162172
163173 $ callback ($ image , $ progress );
164174 };
165175
166- default :
167- throw new Exception ("unsupported signal $ name " );
176+ $ sig = \FFI ::arrayType (FFI ::ctypes ("GCallback_progress " ), [1 ]);
177+ $ c_callback = \FFI ::new ($ sig );
178+ $ c_callback [0 ] = $ marshal ;
179+
180+ return \FFI ::cast (FFI ::ctypes ("GCallback " ), $ c_callback [0 ]);
181+
182+ case 'read ' :
183+ if (FFI ::atLeast (8 , 9 )) {
184+ $ marshal = function (
185+ CData $ sourcePointer ,
186+ CData $ bufferPointer ,
187+ int $ bufferLength ,
188+ CData $ handle ) : int {
189+ echo "hello from read marshal! \n" ;
190+ $ callback = self ::fromHandle ($ handle );
191+ $ result = 0 ;
192+
193+ $ returnBuffer = $ callback ($ bufferLength );
194+ if ($ returnBuffer !== null ) {
195+ $ result = strlen ($ returnBuffer );
196+ \FFI ::memcpy ($ bufferPointer ,
197+ $ returnBuffer ,
198+ $ result
199+ );
200+ }
201+
202+ return $ result ;
203+ };
204+
205+ $ sig = \FFI ::arrayType (FFI ::ctypes ("GCallback_read " ), [1 ]);
206+ $ c_callback = \FFI ::new ($ sig );
207+ $ c_callback [0 ] = $ marshal ;
208+
209+ echo "c_callback[0] = " ;
210+ print_r ($ c_callback [0 ]);
211+ echo "\n" ;
212+
213+ return \FFI ::cast (FFI ::ctypes ("GCallback " ), $ c_callback [0 ]);
214+ }
168215 }
216+
217+ throw new Exception ("unsupported signal $ name " );
169218 }
170219
171220 private static function getMarshaler (string $ name , Closure $ callback ): ?Closure
@@ -285,6 +334,28 @@ private static function getMarshaler(string $name, Closure $callback): ?Closure
285334 return null ;
286335 }
287336 }
337+
338+ private static function getHandle ($ object ) : CData
339+ {
340+ $ index = self ::$ nextIndex ;
341+ self ::$ nextIndex += 1 ;
342+
343+ self ::$ handleTable [$ index ] = $ object ;
344+
345+ // hide the index inside a void*
346+ $ x = \FFI ::new (FFI ::ctypes ("GType " ));
347+ $ x ->cdata = $ index ;
348+
349+ return \FFI ::cast ("void* " , $ x );
350+ }
351+
352+ private static function fromHandle ($ handle )
353+ {
354+ // recover the index from a void*
355+ $ index = $ handle ->cdata ;
356+
357+ return self ::$ handleTable [$ index ];
358+ }
288359}
289360
290361/*
0 commit comments