Skip to content

Commit 01da7e6

Browse files
committed
more fiddling
1 parent c3109d4 commit 01da7e6

File tree

2 files changed

+97
-19
lines changed

2 files changed

+97
-19
lines changed

src/FFI.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,12 @@ private static function init(): void
422422
void g_object_get_property (GObject* object,
423423
const char* name, GValue* value);
424424
425-
typedef void (*GCallback)(void*, void*, void*);
426425
typedef void (*GClosureNotify)(void* data, struct _GClosure *);
426+
427+
typedef void (*GCallback)(void);
428+
typedef void (*GCallback_progress)(void*,void*,void*);
429+
typedef gint64 (*GCallback_read)(void*,void*,gint64,void*);
430+
427431
long g_signal_connect_data (GObject* object,
428432
const char* detailed_signal,
429433
GCallback c_handler,
@@ -803,6 +807,9 @@ private static function init(): void
803807
"GObject" => self::$gobject->type("GObject*"),
804808
"GClosure" => self::$gobject->type("GClosure"),
805809
"GCallback" => self::$gobject->type("GCallback"),
810+
"GCallback_read" => self::$gobject->type("GCallback_read"),
811+
"GCallback_progress" => self::$gobject->type("GCallback_progress"),
812+
"GType" => self::$gobject->type("GType"),
806813
"GParamSpec" => self::$gobject->type("GParamSpec*"),
807814
"VipsObject" => self::$vips->type("VipsObject*"),
808815
"VipsOperation" => self::$vips->type("VipsOperation*"),

src/GObject.php

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
*/
5454
abstract 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

Comments
 (0)