3838
3939namespace Jcupitt \Vips ;
4040
41+ use Closure ;
42+ use FFI \CData ;
43+
4144/**
4245 * This class holds a pointer to a GObject and manages object lifetime.
4346 *
@@ -55,7 +58,7 @@ abstract class GObject
5558 *
5659 * @internal
5760 */
58- private \ FFI \ CData $ pointer ;
61+ private CData $ pointer ;
5962
6063 /**
6164 * Wrap a GObject around an underlying vips resource. The GObject takes
@@ -69,7 +72,7 @@ abstract class GObject
6972 *
7073 * @internal
7174 */
72- public function __construct (\ FFI \ CData $ pointer )
75+ public function __construct (CData $ pointer )
7376 {
7477 $ this ->pointer = \FFI ::cast (FFI ::ctypes ("GObject " ), $ pointer );
7578 }
@@ -94,7 +97,50 @@ public function unref(): void
9497 FFI ::gobject ()->g_object_unref ($ this ->pointer );
9598 }
9699
97- // TODO signal marshalling to go in
100+ public function signalConnect (string $ name , Closure $ callback ): void
101+ {
102+ static $ marshalers = null ;
103+
104+ if ($ marshalers === null ) {
105+ $ imageProgressCb = static function (CData $ vi , CData $ progress , CData $ handle ) {
106+ FFI ::gobject ()->g_object_ref ($ vi );
107+ $ image = new Image ($ vi );
108+ $ progress = \FFI ::cast (FFI ::ctypes ('VipsProgress ' ), $ progress );
109+ $ handle ($ image , $ progress );
110+ };
111+ $ marshalers = ['preeval ' => $ imageProgressCb , 'eval ' => $ imageProgressCb , 'posteval ' => $ imageProgressCb ];
112+
113+ if (FFI ::atLeast (8 , 9 )) {
114+ $ marshalers ['read ' ] = static function (CData $ gObject , CData $ pointer , int $ length , CData $ handle ): int {
115+ $ buffer = \FFI ::string ($ pointer , $ length );
116+ return $ handle ($ buffer );
117+ };
118+ $ marshalers ['seek ' ] = static function (CData $ gObject , int $ offset , int $ whence , CData $ handle ): int {
119+ return $ handle ($ offset , $ whence );
120+ };
121+ $ marshalers ['write ' ] = static function (CData $ gObject , CData $ pointer , int $ length , CData $ handle ): int {
122+ $ buffer = \FFI ::string ($ pointer , $ length );
123+ return $ handle ($ buffer );
124+ };
125+ $ marshalers ['finish ' ] = static function (CData $ gObject , CData $ handle ): void {
126+ $ handle ();
127+ };
128+ }
129+
130+ if (FFI ::atLeast (8 , 13 )) {
131+ $ marshalers ['end ' ] = static function (CData $ gObject , CData $ handle ): int {
132+ return $ handle ();
133+ };
134+ }
135+ }
136+
137+ if (!isset ($ marshalers [$ name ])) {
138+ throw new Exception ("unsupported signal $ name " );
139+ }
140+
141+ $ go = \FFI ::cast (FFI ::ctypes ('GObject ' ), $ this ->pointer );
142+ FFI ::gobject ()->g_signal_connect_data ($ go , $ name , $ marshalers [$ name ], $ callback , null , 0 );
143+ }
98144}
99145
100146/*
0 commit comments