Dear list,
I found something that seems like a bug to me, but I’m still not sure, it could be something in my code. Could someone take a look and tell me if I’m doing something incorrectly?
The GUI object pasted below will sometimes crash on close when in a sub-patcher, but not in a top level patcher.
What is confusing to me is that the order of objects in the .pd file seems to make a difference.
On my system this patch crashes on close with a Segmentation Fault: 11:
#N canvas 627 164 450 300 10;
#N canvas 546 160 450 300 foo 0;
#X obj 117 115 basicgui;
#X obj 126 56 inlet;
#X connect 1 0 0 0;
#X restore 131 90 pd foo;
But this version of the same exact patch with only the creation order of objects in the file changed, does *not* crash:
#N canvas 627 164 450 300 10;
#N canvas 546 160 450 300 foo 0;
#X obj 126 56 inlet;
#X obj 117 115 basicgui;
#X connect 0 0 1 0;
#X restore 131 90 pd foo;
The crash log seems to point to a problem with the number of inlets while the linetraverser is running… but I’m not sure how to correct my code to avoid this.
Many thanks for any advice!
Rama
MacOS 10.10.2
Pd 0.46.6
Crash log:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 pd 0x0000000106e7f59c obj_ninlets + 76
1 pd 0x0000000106e29bb9 linetraverser_next + 569
2 pd 0x0000000106e2b232 canvas_deletelinesfor + 50
3 pd 0x0000000106e33fb5 text_delete + 37
4 pd 0x0000000106e504b7 gobj_delete + 87
5 pd 0x0000000106e2e485 glist_delete + 597
6 pd 0x0000000106e3168d graph_delete + 61
7 pd 0x0000000106e504b7 gobj_delete + 87
8 pd 0x0000000106e2e485 glist_delete + 597
9 pd 0x0000000106e2aefd canvas_free + 109
10 pd 0x0000000106e79d14 pd_free + 68
11 pd 0x0000000106e56869 canvas_menuclose + 265
12 pd 0x0000000106e7d07b pd_typedmess + 1515
13 pd 0x0000000106e4d6b1 guiconnect_anything + 65
14 pd 0x0000000106e7d23d pd_typedmess + 1965
15 pd 0x0000000106e839e7 binbuf_eval + 2215
16 pd 0x0000000106e8ef78 socketreceiver_read + 648
17 pd 0x0000000106e8e80d sys_domicrosleep + 557
18 pd 0x0000000106e8e5c8 sys_microsleep + 24
19 pd 0x0000000106e8ab89 m_pollingscheduler + 857
20 pd 0x0000000106e8a738 m_mainloop + 56
21 pd 0x0000000106e8b485 sys_main + 501
22 pd 0x0000000106e974e2 main + 34
23 libdyld.dylib 0x00007fff905975c9 start + 1
// basicgui.c object:
#include "m_pd.h"
#include "g_canvas.h"
typedef struct _basicgui
{
t_object ob;
t_glist *glist;
char io_tag[256];
int height, width, exists;
} t_basicgui;
static t_class *basicgui_class;
t_widgetbehavior basicgui_widget;
static void basicgui_getrect(t_gobj *z, t_glist *glist,int *xp1, int *yp1, int *xp2, int *yp2)
{
t_basicgui *x = (t_basicgui *)z;
*xp1 = text_xpix(&x->ob, glist);
*yp1 = text_ypix(&x->ob, glist);
*xp2 = *xp1 + x->width;
*yp2 = *yp1 + x->height;
x->glist = glist;
}
static void basicgui_displace(t_gobj *z, t_glist *glist, int dx, int dy)
{
t_basicgui *x = (t_basicgui *)z;
sys_vgui(".x%lx.c move %lxBOX %d %d\n", glist_getcanvas(glist), z, dx, dy );
x->ob.te_xpix += dx;
x->ob.te_ypix += dy;
int x1, x2, y1, y2;
basicgui_getrect(z, glist, &x1, &y1, &x2, &y2);
t_object *ob = pd_checkobject(&x->ob.te_pd);
if (ob){
glist_drawiofor(glist, ob, 0, x->io_tag, x->ob.te_xpix, x->ob.te_ypix, x2, y2);
canvas_fixlinesfor(glist, &x->ob);
}
}
static void basicgui_select(t_gobj *z, t_glist *glist, int state)
{}
static void basicgui_activate(t_gobj *z, t_glist *glist, int state)
{}
static void basicgui_delete(t_gobj *z, t_glist *glist)
{
printf("%s %p \n", __FUNCTION__, z);
t_canvas *canvas = glist_getcanvas(glist);
if(canvas->gl_editor)
{
printf("%s deleting %p \n", __FUNCTION__, z);
sys_vgui(".x%lx.c delete %lxBOX \n", glist_getcanvas(glist), z );
t_basicgui *x = (t_basicgui *)z;
t_object *ob = pd_checkobject(&x->ob.te_pd);
if(ob && glist_isvisible(glist))
{
glist_eraseiofor(glist, ob, x->io_tag);
canvas_deletelinesfor(canvas, ob);
}
}
}
void basicgui_drawElements(t_basicgui *x, t_gobj *z, t_glist *glist, int firstime)
{
int x1, x2, y1, y2;
basicgui_getrect(z, glist, &x1, &y1, &x2, &y2);
if(firstime)
{
sys_vgui(".x%lx.c create rectangle %d %d %d %d -outline \"blue\" -fill \"\" -tags %lxBOX \n", glist_getcanvas(glist), x1, y1, x2, y2, z);
}
else
{
if (glist_isvisible(glist))
sys_vgui(".x%lx.c coords %lxBOX %d %d %d %d \n", glist_getcanvas(glist), z, x1, y1, x2, y2);
}
t_object *ob = pd_checkobject(&x->ob.te_pd);
if (ob){
glist_drawiofor(glist, ob, firstime, x->io_tag, x1, y1, x2, y2);
}
if (firstime) /* raise cords over everything else */
sys_vgui(".x%lx.c raise cord\n", glist_getcanvas(glist));
x->exists = 1;
}
void basicgui_vis(t_gobj *z, t_glist *glist, int state)
{
// printf("%p %s state %d glist %p canvas %p\n", (t_basicgui *)z, __func__, state, glist, glist_getcanvas(glist));
t_basicgui *x = (t_basicgui *)z;
if(state)
{
basicgui_drawElements(x, z, glist, state);
}
else
{
if(x->exists)
{
basicgui_delete(z, glist);
x->exists = 0;
}
}
}
void basicgui_save(t_gobj *z, t_binbuf *b)
{
t_basicgui *x = (t_basicgui *)z;
binbuf_addv(b, "ssiis;", gensym("#X"),gensym("obj"), (t_int)x->ob.te_xpix, (t_int)x->ob.te_ypix, gensym("basicgui"));
}
void basicgui_bang(t_basicgui *x)
{
int x1, x2, y1, y2;
basicgui_getrect((t_gobj *)x, x->glist, &x1, &y1, &x2, &y2);
post("%x %s x1 %d y1 %d x2 %d y2 %d", x, __func__, x1, y1, x2, y2);
post("text pix x %d y %d", text_xpix(&x->ob, x->glist), text_ypix(&x->ob, x->glist));
}
void *basicgui_new(void)
{
t_basicgui *x = (t_basicgui *)pd_new(basicgui_class);
if(x)
{
x->glist = (t_glist *)canvas_getcurrent();
x->height = 10;
x->width = 30;
sprintf(x->io_tag, "%lxIOTAG", (long)x);
}
return (void *)x;
}
void basicgui_setup(void) {
basicgui_class = class_new(gensym("basicgui"),
(t_newmethod)basicgui_new,
0,
sizeof(t_basicgui),
CLASS_DEFAULT,
0);
class_addbang(basicgui_class, basicgui_bang);
basicgui_widget.w_getrectfn = basicgui_getrect;
basicgui_widget.w_displacefn = basicgui_displace;
basicgui_widget.w_deletefn = basicgui_delete;
basicgui_widget.w_visfn = basicgui_vis;
basicgui_widget.w_selectfn = NULL;
basicgui_widget.w_activatefn = NULL;
basicgui_widget.w_clickfn = NULL;
class_setsavefn(basicgui_class, basicgui_save);
class_setwidget(basicgui_class, &basicgui_widget);
}