@@ -238,6 +238,14 @@ typedef struct pdlua_proxyclock
238238 struct pdlua * owner ; /**< Object to forward messages to. */
239239 t_clock * clock ; /** Pd clock to use. */
240240} t_pdlua_proxyclock ;
241+
242+ /** Proxy canvas object data. */
243+ typedef struct pdlua_proxycanvas
244+ {
245+ t_pd pd ; /**< Minimal Pd object. */
246+ t_symbol * p_sym ; /**< The name of the canvas. */
247+ struct pdlua * p_parent ; /**< The parent object. */
248+ } t_pdlua_proxycanvas ;
241249/* prototypes*/
242250
243251static const char * pdlua_reader (lua_State * L , void * rr , size_t * size );
@@ -263,6 +271,12 @@ static t_pdlua_proxyclock *pdlua_proxyclock_new (struct pdlua *owner);
263271static void pdlua_proxyclock_setup (void );
264272/** Dump an array of atoms into a Lua table. */
265273static void pdlua_pushatomtable (int argc , t_atom * argv );
274+ /** Proxy canvas 'anything' method. */
275+ static void pdlua_proxycanvas_anything (t_pdlua_proxycanvas * p , t_symbol * s , int argc , t_atom * argv );
276+ /** Proxy canvas allocation and initialization. */
277+ static t_pdlua_proxycanvas * pdlua_proxycanvas_new (struct pdlua * owner , t_symbol * name );
278+ /** Register the proxy canvas class with Pd. */
279+ static void pdlua_proxycanvas_setup (void );
266280/** Pd object constructor. */
267281static t_pdlua * pdlua_new (t_symbol * s , int argc , t_atom * argv );
268282/** Pd object destructor. */
@@ -346,12 +360,15 @@ void pdlua_setup (void);
346360struct pdlua_proxyinlet ;
347361struct pdlua_proxyreceive ;
348362struct pdlua_proxyclock ;
363+ struct pdlua_proxycanvas ;
349364/** Proxy inlet class pointer. */
350365static t_class * pdlua_proxyinlet_class ;
351366/** Proxy receive class pointer. */
352367static t_class * pdlua_proxyreceive_class ;
353368/** Proxy clock class pointer. */
354369static t_class * pdlua_proxyclock_class ;
370+ /** Proxy canvas class pointer. */
371+ static t_class * pdlua_proxycanvas_class ;
355372
356373/** Lua file reader callback. */
357374static const char * pdlua_reader
@@ -378,6 +395,64 @@ static const char *pdlua_reader
378395 }
379396}
380397
398+ static void pdlua_proxycanvas_anything (t_pdlua_proxycanvas * p , t_symbol * s , int argc , t_atom * argv ) {
399+ #if !PLUGDATA
400+ // Early returns for invalid conditions
401+ if (!p -> p_parent ) return ;
402+ if (s != gensym ("motion" )) return ;
403+ if (argc != 3 ) return ;
404+
405+ t_pdlua * x = p -> p_parent ;
406+ if (!x -> has_gui || x -> gfx .mouse_down ) return ;
407+
408+ float new_x = atom_getfloat (argv );
409+ float new_y = atom_getfloat (argv + 1 );
410+
411+ int zoom = glist_getzoom (x -> canvas );
412+ int obj_x = text_xpix (& x -> pd , x -> canvas );
413+ int obj_y = text_ypix (& x -> pd , x -> canvas );
414+
415+ int xpos = (new_x - obj_x ) / zoom ;
416+ int ypos = (new_y - obj_y ) / zoom ;
417+
418+ int inside = (xpos >= 0 && xpos < x -> gfx .width &&
419+ ypos >= 0 && ypos < x -> gfx .height );
420+
421+ // Handle state changes first
422+ if (!inside && x -> gfx .mouse_inside ) {
423+ pdlua_gfx_mouse_exit (x , xpos , ypos );
424+ x -> gfx .mouse_inside = 0 ;
425+ } else if (inside && !x -> gfx .mouse_inside ) {
426+ pdlua_gfx_mouse_enter (x , xpos , ypos );
427+ x -> gfx .mouse_inside = 1 ;
428+ }
429+
430+ // Only then send move event if we're inside
431+ if (inside ) {
432+ pdlua_gfx_mouse_move (x , xpos , ypos );
433+ }
434+
435+ x -> gfx .mouse_x = new_x ;
436+ x -> gfx .mouse_y = new_y ;
437+ #endif
438+ }
439+
440+ static t_pdlua_proxycanvas * pdlua_proxycanvas_new (t_pdlua * x , t_symbol * s ) {
441+ t_pdlua_proxycanvas * p = (t_pdlua_proxycanvas * )pd_new (pdlua_proxycanvas_class );
442+ p -> pd = pdlua_proxycanvas_class ;
443+ p -> p_sym = s ;
444+ p -> p_parent = x ;
445+ pd_bind (& p -> pd , p -> p_sym );
446+ return p ;
447+ }
448+
449+ static void pdlua_proxycanvas_free (t_pdlua_proxycanvas * p ) {
450+ if (!p ) return ;
451+ if (p -> p_sym ) {
452+ pd_unbind (& p -> pd , p -> p_sym );
453+ }
454+ }
455+
381456/** Proxy inlet 'anything' method. */
382457static void pdlua_proxyinlet_anything
383458(
@@ -494,6 +569,18 @@ static void pdlua_proxyclock_setup(void)
494569 pdlua_proxyclock_class = class_new (gensym ("pdlua proxy clock" ), 0 , 0 , sizeof (t_pdlua_proxyclock ), 0 , 0 );
495570}
496571
572+ /** Setup the proxy class for canvas events. */
573+ static void pdlua_proxycanvas_setup (void )
574+ {
575+ pdlua_proxycanvas_class = class_new (
576+ gensym ("pdlua proxy canvas" ), 0 ,
577+ (t_method )pdlua_proxycanvas_free ,
578+ sizeof (t_pdlua_proxycanvas ), 0 , 0 );
579+ if (pdlua_proxycanvas_class )
580+ class_addanything (pdlua_proxycanvas_class , (t_method )pdlua_proxycanvas_anything );
581+ PDLUA_DEBUG ("pdlua proxy canvas setup done" , 0 );
582+ }
583+
497584/** Dump an array of atoms into a Lua table. */
498585static void pdlua_pushatomtable
499586(
@@ -714,9 +801,24 @@ static t_pdlua *pdlua_new
714801 if (lua_islightuserdata (__L (), -1 ))
715802 {
716803 object = lua_touserdata (__L (), -1 );
804+
805+ // Create canvas proxy if we have GUI
806+ if (object -> has_gui ) {
807+ t_canvas * parent_canvas = glist_getcanvas (object -> canvas );
808+ char buf [MAXPDSTRING ];
809+ snprintf (buf , MAXPDSTRING - 1 , ".x%lx" , (unsigned long )parent_canvas );
810+ object -> gfx .proxycanvas = pdlua_proxycanvas_new (object , gensym (buf ));
811+ if (!object -> gfx .proxycanvas ) {
812+ pd_error (NULL , "pdlua: failed to create canvas proxy" );
813+ pd_free ((t_pd * )object );
814+ lua_pop (__L (), 2 );
815+ return NULL ;
816+ }
817+ }
818+
717819 lua_pop (__L (), 2 );/* pop the userdata and the global "pd" */
718820 PDLUA_DEBUG2 ("pdlua_new: before returning object %p stack top %d" , object , lua_gettop (__L ()));
719- return object ;
821+ return object ;
720822 }
721823 else
722824 {
@@ -800,6 +902,14 @@ static void pdlua_motion(t_gobj *z, t_floatarg dx, t_floatarg dy,
800902 int ypos = (x -> gfx .mouse_y - text_ypix (& x -> pd , x -> canvas )) / zoom ;
801903 pdlua_gfx_mouse_up (x , xpos , ypos );
802904 x -> gfx .mouse_down = 0 ;
905+
906+ // After mouse up, check if we need to send exit
907+ int inside = (xpos >= 0 && xpos < x -> gfx .width &&
908+ ypos >= 0 && ypos < x -> gfx .height );
909+ if (!inside && x -> gfx .mouse_inside ) {
910+ pdlua_gfx_mouse_exit (x , xpos , ypos );
911+ x -> gfx .mouse_inside = 0 ;
912+ }
803913 return ;
804914 }
805915#endif
@@ -835,11 +945,11 @@ static int pdlua_click(t_gobj *z, t_glist *gl, int xpos, int ypos, int shift, in
835945 {
836946 pdlua_gfx_mouse_up (x , xpix , ypix );
837947 x -> gfx .mouse_down = 0 ;
838- } else {
839- x -> gfx .mouse_x = xpos ;
840- x -> gfx .mouse_y = ypos ;
841- pdlua_gfx_mouse_move (x , xpix , ypix );
842948 }
949+ // no move events generated here
950+ // Let the proxy handle all move events
951+ x -> gfx .mouse_x = xpos ;
952+ x -> gfx .mouse_y = ypos ;
843953 }
844954 return 1 ;
845955 } else
@@ -3072,7 +3182,10 @@ void pdlua_setup(void)
30723182 PDLUA_DEBUG ("pdlua pdlua_proxyreceive_setup done" , 0 );
30733183 pdlua_proxyclock_setup ();
30743184 PDLUA_DEBUG ("pdlua pdlua_proxyclock_setup done" , 0 );
3075- if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class )
3185+ pdlua_proxycanvas_setup ();
3186+ PDLUA_DEBUG ("pdlua pdlua_proxycanvas_setup done" , 0 );
3187+
3188+ if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class || ! pdlua_proxycanvas_class )
30763189 {
30773190 pd_error (NULL , "lua: error creating proxy classes" );
30783191 pd_error (NULL , "lua: loader will not be registered!" );
0 commit comments