diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c
index 42402f8fc59991b77e43645cb13c413aef9f5f60..4e6aeef8c82b91f318ad929174b609a6d487c5b1 100644
--- a/pd/src/g_traversal.c
+++ b/pd/src/g_traversal.c
@@ -67,12 +67,8 @@ void gstub_cutoff(t_gstub *gs)
     if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
 }
 
-/* call this to verify that a pointer is fresh, i.e., that it either
-points to real data or to the head of a list, and that in either case
-the object hasn't disappeared since this pointer was generated. 
-Unless "headok" is set,  the routine also fails for the head of a list. */
 
-int gpointer_check(const t_gpointer *gp, int headok)
+int gpointer_docheck(const t_gpointer *gp, int headok, int gobjok)
 {
     t_gstub *gs = gp->gp_stub;
     if (!gs) return (0);
@@ -85,7 +81,7 @@ int gpointer_check(const t_gpointer *gp, int headok)
     {
         if (!headok && !((t_scalar *)(gp->gp_un.gp_gobj)))
             return (0);
-        else if (gp->gp_un.gp_gobj &&
+        else if (!gobjok && gp->gp_un.gp_gobj &&
                  pd_class(&gp->gp_un.gp_gobj->g_pd) != scalar_class)
             return (0);
         else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid)
@@ -96,6 +92,22 @@ int gpointer_check(const t_gpointer *gp, int headok)
     else return (0);
 }
 
+/* call this to verify that a pointer is fresh, i.e., that it either
+points to real data or to the head of a list, and that in either case
+the object hasn't disappeared since this pointer was generated. 
+Unless "headok" is set,  the routine also fails for the head of a list.*/
+
+int gpointer_check(const t_gpointer *gp, int headok)
+{
+    return (gpointer_docheck(gp, headok, 0));
+}
+
+/* more general form for checking for pointers to gobjs */
+int gpointer_check_gobj(const t_gpointer *gp)
+{
+    return (gpointer_docheck(gp, 0, 1));
+}
+
 /* get the template for the object pointer to.  Assumes we've already checked
 freshness.  Returns 0 if head of list. */
 
diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c
index 52396fbd86bb2141020f4d71ff29eedab6a9e0cb..fe64dba3fc6a7dcf852a9517e99469744a54b374 100644
--- a/pd/src/x_interface.c
+++ b/pd/src/x_interface.c
@@ -128,10 +128,8 @@ static t_class *objectinfo_class;
 typedef struct _objectinfo {
     t_object x_obj;
     t_outlet *x_out2;
+    t_gpointer x_gp;
     t_canvas *x_canvas;
-    t_float x_index;
-    t_float x_depth;
-    t_gobj *x_test;
 } t_objectinfo;
 
 /* used by all the *info objects */
@@ -278,24 +276,87 @@ void canvasinfo_filename(t_canvasinfo *x, t_symbol *s, int argc, t_atom *argv)
     info_out((t_text *)x, s, 1, at);
 }
 
-void canvasinfo_hitbox(t_canvasinfo *x, t_floatarg xpos, t_floatarg ypos)
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf, int wholeword);
+
+void canvasinfo_find(t_canvasinfo *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
+    int i, match = 0;
+    t_atom at[1], *ap;
+    t_gpointer *gp = (t_gpointer *)t_getbytes(500 * sizeof(*gp));
+    t_gobj *y;
+    t_binbuf *searchbuf = binbuf_new();
+    t_binbuf *outbuf = binbuf_new();
+    binbuf_add(searchbuf, argc, argv);
+    for (y = c->gl_list; y && match < 500; y = y->g_next)
+    {
+        t_binbuf *objbuf;
+        /* if it's not t_object (e.g., a scalar), or if it is but
+           does not have any binbuf content, send a bang... */
+        if (pd_checkobject(&y->g_pd) &&
+            (objbuf = ((t_text *)y)->te_binbuf) &&
+            binbuf_match(objbuf, searchbuf, 1))
+        {
+            match++;
+            gpointer_init(gp+match-1);
+            gpointer_setglist(gp+match-1, c, y);
+            SETPOINTER(at, gp+match-1);
+            binbuf_add(outbuf, 1, at); 
+        }
+    }
+    if (match >= 500)
+        post("canvasinfo: warning: find is currently limited to 500 results. "
+             "Truncating the output to 500 elements...");
+    info_out((t_text *)x, s, binbuf_getnatom(outbuf), binbuf_getvec(outbuf));
+    for (i = 0, ap = binbuf_getvec(outbuf); i < binbuf_getnatom(outbuf); i++)
+    {
+        t_gpointer *gp = (ap+i)->a_w.w_gpointer;
+        gpointer_unset(gp);
+    }
+    binbuf_free(outbuf);
+    binbuf_free(searchbuf);
+    freebytes(gp, 500 * sizeof(*gp));
+}
+
+void canvasinfo_gobjs(t_canvasinfo *x, t_float xpos, t_float ypos,
+    int all)
 {
     t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
     int x1, y1, x2, y2, i, atom_count = 0;
-    t_atom at[500]; /* hack to avoid memory allocation. Maybe later... */
+    /* hack to avoid memory allocation. Maybe there's a way to use the
+       XLIST_ATOMS_ALLOCA macro? */
+    t_atom at[500];
+    t_gpointer *gp, *gvec;
+    gp = gvec = (t_gpointer *)t_getbytes(500 * sizeof (*gvec));
     t_gobj *y;
     for (y = c->gl_list, i = 0; y && atom_count < 500; y = y->g_next, i++)
     {
-        if (canvas_hitbox(c, y, xpos, ypos, &x1, &y1, &x2, &y2))
+        if (all || canvas_hitbox(c, y, xpos, ypos, &x1, &y1, &x2, &y2))
         {
-            SETFLOAT(at+atom_count, (t_float)i);
+            gpointer_init(gp);
+            gpointer_setglist(gp, c, y);
+            SETPOINTER(at+atom_count, gp);
             atom_count++;
+            gp++;
         }
     }
     if (atom_count >= 500)
         post("canvasinfo: warning: hitbox is currently limited to 500 objects. "
-             "Truncating the output to 500 indices...");
+             "Truncating the output to 500 elements...");
     info_out((t_text *)x, gensym("hitbox"), atom_count, at);
+    for (i = 0, gp = gvec; i < atom_count; i++, gp++)
+        gpointer_unset(gp);
+    freebytes(gvec, 500 * sizeof(*gvec));
+}
+
+void canvasinfo_bang(t_canvasinfo *x)
+{
+    canvasinfo_gobjs(x, 0, 0, 1);
+}
+
+void canvasinfo_hitbox(t_canvasinfo *x, t_floatarg xpos, t_floatarg ypos)
+{
+    canvasinfo_gobjs(x, xpos, ypos, 0);
 }
 
 void canvasinfo_name(t_canvasinfo *x, t_symbol *s, int argc, t_atom *argv)
@@ -382,6 +443,7 @@ void canvasinfo_setup(void)
         sizeof(t_canvasinfo),
         CLASS_DEFAULT, A_DEFFLOAT, 0);
 
+    class_addbang(canvasinfo_class, canvasinfo_bang);
     class_addmethod(canvasinfo_class, (t_method)canvasinfo_args,
         gensym("args"), A_GIMME, 0);
     class_addmethod(canvasinfo_class, (t_method)canvasinfo_args,
@@ -398,6 +460,8 @@ void canvasinfo_setup(void)
         gensym("editmode"), A_GIMME, 0);
     class_addmethod(canvasinfo_class, (t_method)canvasinfo_filename,
         gensym("filename"), A_GIMME, 0);
+    class_addmethod(canvasinfo_class, (t_method)canvasinfo_find,
+        gensym("find"), A_GIMME, 0);
     class_addmethod(canvasinfo_class, (t_method)canvasinfo_hitbox,
         gensym("hitbox"), A_DEFFLOAT, A_DEFFLOAT, 0);
     class_addmethod(canvasinfo_class, (t_method)canvasinfo_name,
@@ -996,22 +1060,32 @@ void classinfo_setup(void)
 
 /* -------------------------- objectinfo ------------------------------ */
 
-t_gobj *objectinfo_getobject(t_canvas *c, int index)
+int gpointer_check_gobj(const t_gpointer *gp);
+
+t_gobj *objectinfo_getobject(t_objectinfo *x)
 {
-    int i = index;
-    t_gobj *y = c->gl_list;
-    while(i-- && y)
-        y = y->g_next;
-    return y;
+//    if (gpointer_check_gobj(&x->x_gp))
+//        post("we passed the check in getobject");
+    /* needs to pass the check AND point to a gobj */
+    if (gpointer_check_gobj(&x->x_gp) && x->x_gp.gp_stub->gs_which == GP_GLIST)
+    {
+//        post("we passed total check");
+        return x->x_gp.gp_un.gp_gobj;
+    }
+    else
+        return 0;
 }
 
 void objectinfo_bang(t_objectinfo *x)
 {
-    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
     t_atom at[1];
     t_gpointer gp;
     gpointer_init(&gp);
-    gpointer_setglist(&gp, c, (t_gobj *)x);
+    gpointer_setglist(&gp, x->x_canvas, (t_gobj *)x);
+//    if (gpointer_check_gobj(&gp))
+//        post("creating pointer passed the check");
+//    else
+//        post("didn't create right");
     SETPOINTER(at, &gp);
     info_out((t_text *)x, &s_pointer, 1, at);
     gpointer_unset(&gp);
@@ -1019,10 +1093,12 @@ void objectinfo_bang(t_objectinfo *x)
 
 void objectinfo_float(t_objectinfo *x, t_floatarg f)
 {
+    /*
     t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
-    t_gobj *obj = objectinfo_getobject(c, (int)f);
+    t_gobj *obj = objectinfo_getobject(x);
     post("object is .%x", obj);
     x->x_test = obj;
+    */
 }
 
 void objectinfo_parseargs(t_objectinfo *x, int argc, t_atom *argv)
@@ -1043,6 +1119,7 @@ void objectinfo_parseargs(t_objectinfo *x, int argc, t_atom *argv)
         argv++;
     }
     */
+    /* another stopgap comment out...
     if (argc)
     {
         if (argv->a_type == A_FLOAT)
@@ -1050,16 +1127,15 @@ void objectinfo_parseargs(t_objectinfo *x, int argc, t_atom *argv)
         else
             pd_error(x, "expected float but didn't get a float");
     }
+    */
 }
 
 void objectinfo_boxtext(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
-    objectinfo_parseargs(x, argc, argv);
-    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
-    t_gobj *ob;
-   
-    if(ob = objectinfo_getobject(c, x->x_index))
+    t_gobj *ob = objectinfo_getobject(x);
+    if (ob)
     {
+//        post("it's an obj");
         int n = 0;
         t_atom *a = 0;
         t_binbuf *b;
@@ -1083,16 +1159,19 @@ void objectinfo_boxtext(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 
 void objectinfo_bbox(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
-    objectinfo_parseargs(x, argc, argv);
-    t_gobj *ob;
-    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
+    t_gobj *ob = objectinfo_getobject(x);
     int x1, y1, x2, y2;
-    if(ob = objectinfo_getobject(c, x->x_index))
+    if(ob)
     {
-        /* check for a getrectfn */
+      /* check for a getrectfn */
         if (ob->g_pd->c_wb && ob->g_pd->c_wb->w_getrectfn)
         {
             t_atom at[4];
+            /* objectinfo_getobject will only return a gobj* if the gstub
+               is a GP_GLIST, so we can safely fetch the glist from our
+               gpointer.  Not sure if gobj can ever be inside an array, but
+               if so I'm excluding those cases here... */
+            t_canvas *c = x->x_gp.gp_stub->gs_un.gs_glist;
             gobj_getrect(ob, c, &x1, &y1, &x2, &y2);
             SETFLOAT(at, (t_float)x1);
             SETFLOAT(at+1, (t_float)y1);
@@ -1112,11 +1191,9 @@ void objectinfo_bbox(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 void objectinfo_classname(t_objectinfo *x, t_symbol *s,
     int argc, t_atom *argv)
 {
-    objectinfo_parseargs(x, argc, argv);
+    t_gobj *ob = objectinfo_getobject(x);
     t_atom at[1];
-    t_gobj *ob;
-    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
-    if(ob = objectinfo_getobject(c, x->x_index))
+    if(ob)
     {
         char *classname = class_getname(ob->g_pd);
         SETSYMBOL(at, gensym(classname));
@@ -1126,17 +1203,44 @@ void objectinfo_classname(t_objectinfo *x, t_symbol *s,
         outlet_bang(x->x_out2);
 }
 
+void objectinfo_index(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_gobj *ob = objectinfo_getobject(x);
+    if(ob)
+    {
+        t_atom at[4];
+        t_gobj *y;
+        int i;
+        /* objectinfo_getobject will only return a gobj* if the gstub
+           is a GP_GLIST, so we can safely fetch the glist from our
+           gpointer.  Not sure if gobj can ever be inside an array, but
+           if so I'm excluding those cases here... */
+        t_canvas *c = x->x_gp.gp_stub->gs_un.gs_glist;
+        for (i = 0, y = c->gl_list; y; y = y->g_next, i++)
+        {
+            if (y == ob)
+            {
+                SETFLOAT(at, (t_float)i);
+                info_out((t_text *)x, s, 1, at);
+                return;
+            }
+        }
+        info_out((t_text *)x, s, 0, at);
+    }
+    else
+        outlet_bang(x->x_out2);
+}
+
 void objectinfo_xlets(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
-    objectinfo_parseargs(x, argc, argv);
+    t_gobj *ob = objectinfo_getobject(x);
     t_atom at[1];
-    t_gobj *ob;
-    t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
-    if(ob = objectinfo_getobject(c, x->x_index))
+    if(ob)
     {
+        /* we exclude scalars here because they are not patchable */
         if (pd_class(&ob->g_pd) != scalar_class)
         {
-            post("not a scalar...");
+//            post("not a scalar...");
             t_object *o = (t_object *)ob;
             int n = (s == gensym("inlets") ? obj_ninlets(o) : obj_noutlets(o));
             SETFLOAT(at, (t_float)n);
@@ -1146,6 +1250,7 @@ void objectinfo_xlets(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
     else
         outlet_bang(x->x_out2);
 }
+
 void objectinfo_print(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
     objectinfo_parseargs(x, argc, argv);
@@ -1155,11 +1260,8 @@ void objectinfo_print(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
 void *objectinfo_new(t_floatarg f)
 {
     t_objectinfo *x = (t_objectinfo *)pd_new(objectinfo_class);
-    t_glist *glist = (t_glist *)canvas_getcurrent();
-    x->x_canvas = (t_canvas*)glist_getcanvas(glist);
-    x->x_depth = f;
-    floatinlet_new(&x->x_obj, &x->x_index);
-    floatinlet_new(&x->x_obj, &x->x_depth);
+    x->x_canvas = canvas_getcurrent();
+    pointerinlet_new(&x->x_obj, &x->x_gp);
     outlet_new(&x->x_obj, &s_anything);
     x->x_out2 = outlet_new(&x->x_obj, &s_bang);
     return (void *)x;
@@ -1180,6 +1282,8 @@ void objectinfo_setup(void)
         gensym("boxtext"), A_GIMME, 0);
     class_addmethod(objectinfo_class, (t_method)objectinfo_classname,
         gensym("class"), A_GIMME, 0);
+    class_addmethod(objectinfo_class, (t_method)objectinfo_index,
+        gensym("index"), A_GIMME, 0);
     class_addmethod(objectinfo_class, (t_method)objectinfo_xlets,
         gensym("inlets"), A_GIMME, 0);
     class_addmethod(objectinfo_class, (t_method)objectinfo_xlets,