diff --git a/pd/doc/5.reference/canvasinfo-help.pd b/pd/doc/5.reference/canvasinfo-help.pd
index 58202f6cacdb207a8beaeab7baa7a70c1db1e9b5..c3f8db62fc23a0bcc6554ed09c43880e1913f96b 100644
--- a/pd/doc/5.reference/canvasinfo-help.pd
+++ b/pd/doc/5.reference/canvasinfo-help.pd
@@ -3,7 +3,7 @@
 14 -228856 -66577 0;
 #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header canvasinfo 3 12
 0 18 -204280 -1 0;
-#X obj 0 431 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
+#X obj 0 451 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
 -228856 -1 0;
 #N canvas 48 165 482 332 META 0;
 #X text 12 145 LIBRARY internal;
@@ -24,7 +24,7 @@ filename hitbox name pointer posonparent screenpos toplevel vis;
 0 13 -228856 -1 0;
 #X obj 0 563 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
 0 13 -228856 -1 0;
-#X obj 78 439 cnv 17 3 30 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
+#X obj 78 459 cnv 17 3 30 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
 -162280 0;
 #N canvas 196 385 428 108 Related_objects 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
@@ -36,15 +36,8 @@ filename hitbox name pointer posonparent screenpos toplevel vis;
 #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
 ;
 #X msg 39 48 print;
-#X text 80 47 print all attributes to the console;
-#X text 98 438 print;
-#X text 168 438 - print out each available message (other than "print")
-followed by a semicolon and the output for that method.;
-#X text 168 464 pdinfo's availabe methods are shown above \, with audio-device
-and midi-device message in subpatches.;
+#X text 98 458 print;
 #X text 99 503 list;
-#X text 169 503 - output varies depending on the message sent to [pdinfo].
-;
 #X obj 483 5 canvasinfo;
 #X text 11 20 get info about a canvas;
 #X obj 39 390 canvasinfo;
@@ -72,8 +65,6 @@ it was saved (0 = no \, 1 = yes);
 #X text 233 328 screen position of a visible canvas;
 #X msg 175 368 vis;
 #X text 203 368 whether a canvas is visible on the screen;
-#X text 132 89 full text of the object box for an abstraction or subpatch
-;
 #X text 181 244 see whether a coordinate lies on an object in the canvas
 ;
 #X text 123 130 directory for this canvas' environment;
@@ -130,8 +121,6 @@ so on (if they exist);
 #X connect 11 0 20 0;
 #X connect 19 0 11 0;
 #X restore 101 573 pd canvas_environment;
-#X text 111 68 list of dollarsign arguments for this canvas' environment
-;
 #N canvas 139 127 428 435 hitbox_and_coords 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
 14 -204280 -1 0;
@@ -198,20 +187,28 @@ on the canvas that includes the "x y" coordinates you send it:;
 #X text 81 541 1) float;
 #X text 169 541 - canvas stacking level (0 = this canvas \, 1 = parent
 \, etc.);
-#X connect 11 0 20 0;
-#X connect 20 0 48 0;
-#X connect 21 0 20 0;
-#X connect 22 0 20 0;
-#X connect 23 0 20 0;
-#X connect 25 0 20 0;
-#X connect 26 0 20 0;
-#X connect 28 0 20 0;
-#X connect 29 0 20 0;
-#X connect 31 0 20 0;
-#X connect 32 0 20 0;
-#X connect 33 0 20 0;
-#X connect 36 0 20 0;
-#X connect 37 0 20 0;
-#X connect 38 0 20 0;
-#X connect 41 0 20 0;
-#X connect 49 0 20 0;
+#X text 132 89 text of the object box for an abstraction or subpatch
+(raw);
+#X text 111 68 list of dollarsign argument values for this canvas;
+#X text 80 47 print all attributes directly to the console;
+#X text 168 458 - print all "method: value(s)" pairs directly to the
+console;
+#X text 169 503 - varies depending on the message sent to [canvasinfo]
+;
+#X connect 11 0 16 0;
+#X connect 16 0 43 0;
+#X connect 17 0 16 0;
+#X connect 18 0 16 0;
+#X connect 19 0 16 0;
+#X connect 21 0 16 0;
+#X connect 22 0 16 0;
+#X connect 24 0 16 0;
+#X connect 25 0 16 0;
+#X connect 27 0 16 0;
+#X connect 28 0 16 0;
+#X connect 29 0 16 0;
+#X connect 32 0 16 0;
+#X connect 33 0 16 0;
+#X connect 34 0 16 0;
+#X connect 37 0 16 0;
+#X connect 44 0 16 0;
diff --git a/pd/doc/5.reference/classinfo-help.pd b/pd/doc/5.reference/classinfo-help.pd
index 972146fd5eade0174aa9330439d8d8f04fc5f207..32769104809cc00c208db0884d8ff0968bf8954b 100644
--- a/pd/doc/5.reference/classinfo-help.pd
+++ b/pd/doc/5.reference/classinfo-help.pd
@@ -1,4 +1,4 @@
-#N canvas 425 49 555 619 10;
+#N canvas 0 19 555 619 10;
 #X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0
 14 -228856 -66577 0;
 #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header classinfo 3 12 0
@@ -36,7 +36,6 @@
 #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
 ;
 #X msg 53 61 print;
-#X text 94 60 print all attributes to the console;
 #X text 98 358 print;
 #X text 168 358 - print out each available message (other than "print")
 followed by a semicolon and the output for that method.;
@@ -45,7 +44,6 @@ followed by a semicolon and the output for that method.;
 ;
 #X msg 83 81 args;
 #X obj 53 264 print;
-#X text 11 20 get info about a class;
 #X obj 462 3 classinfo;
 #X obj 140 264 print reject_outlet;
 #X text 125 81 list of argument types accepted by the object;
@@ -98,14 +96,16 @@ as an argument;
 #X text 81 541 1) symbol;
 #X floatatom 96 210 5 0 0 0 - - -, f 5;
 #X msg 340 201 symbol canvas;
-#X connect 11 0 29 0;
-#X connect 17 0 29 0;
-#X connect 23 0 29 0;
-#X connect 25 0 29 0;
-#X connect 27 0 29 0;
-#X connect 29 0 18 0;
-#X connect 29 1 21 0;
-#X connect 30 0 29 1;
-#X connect 33 0 29 1;
-#X connect 50 0 29 0;
-#X connect 51 0 29 1;
+#X text 11 20 get info about a Pure Data class;
+#X text 94 60 print all attributes directly to the console;
+#X connect 11 0 27 0;
+#X connect 16 0 27 0;
+#X connect 21 0 27 0;
+#X connect 23 0 27 0;
+#X connect 25 0 27 0;
+#X connect 27 0 17 0;
+#X connect 27 1 19 0;
+#X connect 28 0 27 1;
+#X connect 31 0 27 1;
+#X connect 48 0 27 0;
+#X connect 49 0 27 1;
diff --git a/pd/doc/5.reference/objectinfo-help.pd b/pd/doc/5.reference/objectinfo-help.pd
index ad0ff73c964e19d5a0bb22d67d905660e5185271..ab76eeb69c0faf6b123ce23fc1d9f8369145b945 100644
--- a/pd/doc/5.reference/objectinfo-help.pd
+++ b/pd/doc/5.reference/objectinfo-help.pd
@@ -1,9 +1,9 @@
-#N canvas 0 19 555 619 10;
+#N canvas -9 19 555 619 10;
 #X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0
 14 -228856 -66577 0;
 #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header objectinfo 3 12
 0 18 -204280 -1 0;
-#X obj 0 403 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
+#X obj 0 396 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
 -228856 -1 0;
 #N canvas 456 104 482 506 META 0;
 #X text 12 175 LIBRARY internal;
@@ -21,13 +21,13 @@ to conform to the PDDP template for Pd version 0.42.;
 #X text 12 115 INLET_2 float;
 #X text 12 155 OUTLET_1 bang;
 #X restore 500 597 pd META;
-#X obj 0 478 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
+#X obj 0 491 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
 13 -228856 -1 0;
-#X obj 0 515 cnv 3 550 3 empty \$0-pddp.cnv.argument arguments 8 12
+#X obj 0 528 cnv 3 550 3 empty \$0-pddp.cnv.argument arguments 8 12
 0 13 -228856 -1 0;
-#X obj 0 555 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
+#X obj 0 565 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
 0 13 -228856 -1 0;
-#X obj 78 411 cnv 17 3 30 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
+#X obj 78 404 cnv 17 3 55 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
 -162280 0;
 #N canvas 102 481 428 108 Related_objects 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
@@ -37,22 +37,21 @@ to conform to the PDDP template for Pd version 0.42.;
 #X obj 72 36 classinfo;
 #X obj 142 36 canvasinfo;
 #X restore 101 597 pd Related_objects;
-#X obj 78 487 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
+#X obj 78 500 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
 -162280 0;
 #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
 ;
 #X msg 39 62 print;
 #X text 80 61 print all attributes to the console;
-#X msg 101 232 version;
-#X text 98 410 print;
-#X text 168 410 - print out each available message (other than "print")
+#X text 98 403 print;
+#X text 168 403 - print out each available message (other than "print")
 followed by a semicolon and the output for that method.;
-#X text 99 487 list;
-#X text 169 487 - output varies depending on the message sent to [pdinfo]
+#X text 99 500 list;
+#X text 169 500 - output varies depending on the message sent to [pdinfo]
 ;
 #X text 11 20 get info about a Pd object;
 #X obj 473 7 objectinfo;
-#X obj 39 323 objectinfo;
+#X obj 39 303 objectinfo;
 #X msg 72 92 bbox;
 #X text 114 91 list of coordinates-- x1 y1 x2 y2-- for the bounding
 rectangle of the object on the canvas.;
@@ -60,30 +59,28 @@ rectangle of the object on the canvas.;
 #X text 137 121 list of atoms that appear in the object box;
 #X msg 89 152 class;
 #X text 136 152 class of the object;
-#X msg 92 182 inlets;
-#X text 141 181 number of inlets the object has;
-#X msg 95 209 outlets;
-#X text 151 208 number of outlets the object has;
-#X floatatom 98 269 5 0 0 0 - - -, f 5;
-#X text 141 269 index number of the object you want to inspect;
-#X floatatom 104 299 5 0 0 0 - - -, f 5;
-#X text 141 299 canvas level: '0' for this canvas \, '1' for the parent
-canvas \, etc.;
-#X text 201 347 outputs a bang if there isn't an object at this index
+#X msg 112 212 inlets;
+#X text 161 211 number of inlets the object has;
+#X msg 115 239 outlets;
+#X text 171 238 number of outlets the object has;
+#X text 201 327 outputs a bang if there isn't an object at this index
 ;
-#X obj 39 372 print object-info;
-#X obj 96 347 print no-object;
-#X text 168 450 objectinfo's available methods are shown above.;
-#X text 81 532 1) float;
-#X text 169 532 canvas level;
-#X connect 11 0 20 0;
-#X connect 13 0 20 0;
-#X connect 20 0 36 0;
-#X connect 20 1 37 0;
-#X connect 21 0 20 0;
-#X connect 23 0 20 0;
-#X connect 25 0 20 0;
-#X connect 27 0 20 0;
-#X connect 29 0 20 0;
-#X connect 31 0 20 1;
-#X connect 33 0 20 2;
+#X obj 39 352 print object-info;
+#X obj 96 327 print no-object;
+#X text 168 438 objectinfo's available methods are shown above.;
+#X msg 99 182 index;
+#X text 146 182 z-order index of the object on the canvas;
+#X obj 78 464 cnv 17 3 25 empty \$0-pddp.cnv.let.0 1 5 9 0 16 -228856
+-162280 0;
+#X text 98 463 pointer;
+#X text 168 463 pointer to an object on the canvas;
+#X text 81 545 none;
+#X connect 11 0 19 0;
+#X connect 19 0 31 0;
+#X connect 19 1 32 0;
+#X connect 20 0 19 0;
+#X connect 22 0 19 0;
+#X connect 24 0 19 0;
+#X connect 26 0 19 0;
+#X connect 28 0 19 0;
+#X connect 34 0 19 0;
diff --git a/pd/doc/5.reference/pdinfo-help.pd b/pd/doc/5.reference/pdinfo-help.pd
index 848c778275781bc601a4d842fcb4320c57b09fbe..dcb3cc7de08135e77c2b0d9bdb8d6628e9f3eaa7 100644
--- a/pd/doc/5.reference/pdinfo-help.pd
+++ b/pd/doc/5.reference/pdinfo-help.pd
@@ -1,9 +1,9 @@
-#N canvas -9 19 555 619 10;
+#N canvas 0 19 555 619 10;
 #X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0
 14 -228856 -66577 0;
 #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header pdinfo 3 12 0 18
 -204280 -1 0;
-#X obj 0 353 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
+#X obj 0 363 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
 -228856 -1 0;
 #N canvas 34 81 482 506 META 0;
 #X text 12 175 LIBRARY internal;
@@ -33,7 +33,7 @@ version;
 0 13 -228856 -1 0;
 #X obj 0 527 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
 0 13 -228856 -1 0;
-#X obj 78 361 cnv 17 3 30 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
+#X obj 78 371 cnv 17 3 70 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
 -162280 0;
 #N canvas 102 481 428 108 Related_objects 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
@@ -45,24 +45,20 @@ version;
 -162280 0;
 #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
 ;
-#X text 11 20 get info from the global Pd instance that's running;
 #X obj 503 7 pdinfo;
-#X obj 39 291 pdinfo;
+#X obj 39 284 pdinfo;
 #X msg 39 60 print;
-#X text 80 59 print all attributes to the console;
-#X msg 101 230 version;
-#X obj 39 322 print pd-version;
-#X text 155 229 version of Pd that's running (MAJOR MINOR TEST);
-#X msg 95 207 samplerate;
-#X text 169 206 global samplerate;
-#X msg 78 120 dir;
-#X text 107 119 directory of the Pd executable;
-#X msg 72 90 blocksize;
-#X text 144 89 global blocksize;
-#X msg 92 180 pi;
-#X text 121 179 value of Pi;
-#X msg 89 150 dsp-status;
-#X text 164 150 whether dsp is turned on (0 = off \, 1 = on);
+#X msg 89 201 version;
+#X obj 39 315 print pd-version;
+#X text 143 200 version of Pd that's running (MAJOR MINOR TEST);
+#X msg 83 178 samplerate;
+#X text 157 177 global samplerate;
+#X msg 70 116 dir;
+#X text 99 115 directory of the Pd executable;
+#X msg 64 86 blocksize;
+#X text 136 85 global blocksize;
+#X msg 77 146 dsp-status;
+#X text 152 146 whether dsp is turned on (0 = off \, 1 = on);
 #N canvas 100 44 428 514 audio-attributes 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
 14 -204280 -1 0;
@@ -73,7 +69,6 @@ version;
 #X text 94 37 audio api that is currently in use;
 #X msg 42 72 audio-apilist;
 #X text 134 71 list of available audio apis;
-#X msg 65 102 audio-apilist-raw;
 #X text 179 102 audio apis for all platforms;
 #X msg 79 132 audio-inchannels;
 #X text 184 132 number of incoming audio channels;
@@ -94,20 +89,21 @@ version;
 #X text 193 414 list of output device names;
 #X text 179 203 returns: device_index no_of_channels;
 #X text 183 391 returns: device_index no_of_channels;
+#X msg 65 102 audio-apilist-all;
 #X connect 2 0 3 0;
 #X connect 4 0 2 0;
 #X connect 6 0 2 0;
-#X connect 8 0 2 0;
-#X connect 10 0 2 0;
-#X connect 13 0 14 0;
+#X connect 9 0 2 0;
+#X connect 12 0 13 0;
+#X connect 13 0 2 0;
 #X connect 14 0 2 0;
-#X connect 15 0 2 0;
-#X connect 17 0 2 0;
-#X connect 20 0 2 0;
-#X connect 22 0 2 0;
-#X connect 24 0 22 0;
-#X connect 25 0 2 0;
-#X restore 206 322 pd audio-attributes;
+#X connect 16 0 2 0;
+#X connect 19 0 2 0;
+#X connect 21 0 2 0;
+#X connect 23 0 21 0;
+#X connect 24 0 2 0;
+#X connect 28 0 2 0;
+#X restore 156 340 pd audio-attributes;
 #N canvas 125 83 428 395 midi-attributes 0;
 #X obj 1 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
 14 -204280 -1 0;
@@ -139,29 +135,37 @@ version;
 #X connect 15 0 2 0;
 #X connect 16 0 2 0;
 #X connect 17 0 2 0;
-#X restore 346 322 pd midi-attributes;
-#X text 98 360 print;
-#X text 168 360 - print out each available message (other than "print")
+#X restore 296 340 pd midi-attributes;
+#X text 98 370 print;
+#X text 168 370 - print out each available message (other than "print")
 followed by a semicolon and the output for that method.;
 #X text 99 459 list;
 #X text 81 504 none;
-#X text 168 400 pdinfo's available methods are shown above \, with
+#X text 168 410 pdinfo's available methods are shown above \, with
 audio-device and midi-device message in subpatches.;
 #X text 169 459 - output varies depending on the message sent to [pdinfo]
 ;
-#X msg 101 260 classtable;
-#X text 81 547 When using the "classtable" message \, note that some
+#X msg 101 253 classlist;
+#X text 155 305 Audio and MIDI specific messages are in the subpatches
+below:;
+#X text 81 547 When using the "classlist" message \, note that some
 external Pd classes don't have a name. These are currently listed simply
 as "anonymous-class" in the output.;
-#X text 175 259 (long) list of all classes that have been loaded in
-the running instance of Pd. (Note: not all classes can be created in
-an object box.);
-#X connect 13 0 17 0;
-#X connect 14 0 13 0;
-#X connect 16 0 13 0;
-#X connect 19 0 13 0;
-#X connect 21 0 13 0;
-#X connect 23 0 13 0;
-#X connect 25 0 13 0;
-#X connect 27 0 13 0;
-#X connect 37 0 13 0;
+#X text 175 252 (long) list of all class names that have been loaded
+in the running instance of Pd. (Note: not all classes can be created
+in an object box.);
+#X msg 92 227 canvaslist;
+#X text 166 226 list of pointers to toplevel canvases in running Pd
+instance;
+#X text 80 59 print all attributes directly to the console;
+#X text 11 20 get info from the Pd instance that is running your patch
+;
+#X connect 12 0 15 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 0;
+#X connect 17 0 12 0;
+#X connect 19 0 12 0;
+#X connect 21 0 12 0;
+#X connect 23 0 12 0;
+#X connect 33 0 12 0;
+#X connect 37 0 12 0;
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
index f9a45d520293cf7770144d5c068251177abb6ef6..796f1895f257310c07d29a1be02d27f63a8acb76 100644
--- a/pd/src/g_array.c
+++ b/pd/src/g_array.c
@@ -101,10 +101,10 @@ static void array_resize_and_redraw(t_array *array, t_glist *glist, int n)
     while (a2->a_gp.gp_stub->gs_which == GP_ARRAY)
         a2 = a2->a_gp.gp_stub->gs_un.gs_array;
     if (vis)
-        gobj_vis(&a2->a_gp.gp_un.gp_scalar->sc_gobj, glist, 0);
+        gobj_vis(a2->a_gp.gp_un.gp_gobj, glist, 0);
     array_resize(array, n);
     if (vis)
-        gobj_vis(&a2->a_gp.gp_un.gp_scalar->sc_gobj, glist, 1);
+        gobj_vis(a2->a_gp.gp_un.gp_gobj, glist, 1);
 }
 
 void word_free(t_word *wp, t_template *template);
@@ -841,7 +841,8 @@ void array_redraw(t_array *a, t_glist *glist)
 {
     while (a->a_gp.gp_stub->gs_which == GP_ARRAY)
         a = a->a_gp.gp_stub->gs_un.gs_array;
-    scalar_redraw(a->a_gp.gp_un.gp_scalar, glist);
+    t_scalar *sc = (t_scalar *)(a->a_gp.gp_un.gp_gobj);
+    scalar_redraw(sc, glist);
 }
 
     /* routine to get screen coordinates of a point in an array */
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index ebeb733f42be21ea922a48b436fa4a088d607fc6..4c6d9372d5b28a737313ffd4d0c56d7ac5551160 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -187,6 +187,13 @@ void canvas_getargs(int *argcp, t_atom **argvp)
     *argvp = e->ce_argv;
 }
 
+void canvas_getargs_after_creation(t_canvas *c, int *argcp, t_atom **argvp)
+{
+    t_canvasenvironment *e = canvas_getenv(c);
+    *argcp = e->ce_argc;
+    *argvp = e->ce_argv;
+}
+
 t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s)
 {
     t_symbol *ret;
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
index d847b51b0e1a8baeaee1014c787cce4720b6828b..90574b3deb26a43d3af2691081870e2c47a57334 100644
--- a/pd/src/g_canvas.h
+++ b/pd/src/g_canvas.h
@@ -612,7 +612,7 @@ int array_joc; /* for "jump on click" array inside a graph */
 /* --------------------- gpointers and stubs ---------------- */
 EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
 EXTERN void gstub_cutoff(t_gstub *gs);
-EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
+EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_gobj *x);
 EXTERN void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w);
 
 /* --------------------- scalars ------------------------- */
diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c
index f035bcf1638ab7dd18056c05b390d24cda63bb88..3483758fa0a2ac54e4cee17bdf12c6cac07f364f 100644
--- a/pd/src/g_scalar.c
+++ b/pd/src/g_scalar.c
@@ -225,7 +225,7 @@ t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym)
         (template->t_n - 1) * sizeof(*x->sc_vec));
     x->sc_gobj.g_pd = scalar_class;
     x->sc_template = templatesym;
-    gpointer_setglist(&gp, owner, x);
+    gpointer_setglist(&gp, owner, &x->sc_gobj);
     word_init(x->sc_vec, template, &gp);
     char buf[50];
     sprintf(buf, ".x%lx", (long unsigned int)x);
@@ -457,7 +457,7 @@ void scalar_select(t_gobj *z, t_glist *owner, int state)
     //t_canvas *templatecanvas = NULL;
     t_gpointer gp;
     gpointer_init(&gp);
-    gpointer_setglist(&gp, owner, x);
+    gpointer_setglist(&gp, owner, &x->sc_gobj);
     SETPOINTER(&at, &gp);
     if (tmpl = template_findbyname(templatesym))
     {
@@ -523,7 +523,7 @@ static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
         x->sc_y2 += dy;
     }
     gpointer_init(&gp);
-    gpointer_setglist(&gp, glist, x);
+    gpointer_setglist(&gp, glist, &x->sc_gobj);
     SETPOINTER(&at[0], &gp);
     SETFLOAT(&at[1], (t_float)dx);
     SETFLOAT(&at[2], (t_float)dy);
@@ -576,7 +576,7 @@ static void scalar_displace_withtag(t_gobj *z, t_glist *glist, int dx, int dy)
     //fprintf(stderr,"gotx=%d goty=%d\n", gotx, goty);
     scalar_getbasexy(x, &basex, &basey);
     gpointer_init(&gp);
-    gpointer_setglist(&gp, glist, x);
+    gpointer_setglist(&gp, glist, &x->sc_gobj);
     SETPOINTER(&at[0], &gp);
     SETFLOAT(&at[1], (t_float)dx);
     SETFLOAT(&at[2], (t_float)dy);
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index ecc5bb7ad4c895294edd14271a5a2b09eec4bb69..b106a95d4fb5fe02445e99acb8631ecf3ec67efc 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -282,7 +282,7 @@ static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
             (tto->t_n - 1) * sizeof(*x->sc_vec));
         x->sc_gobj.g_pd = scalar_class;
         x->sc_template = tfrom->t_sym;
-        gpointer_setglist(&gp, glist, x);
+        gpointer_setglist(&gp, glist, &x->sc_gobj);
             /* Here we initialize to the new template, but array and list
             elements will still belong to old template. */
         word_init(x->sc_vec, tto, &gp);
@@ -503,7 +503,7 @@ void template_notifyforscalar(t_template *template, t_glist *owner,
 {
     t_gpointer gp;
     gpointer_init(&gp);
-    gpointer_setglist(&gp, owner, sc);
+    gpointer_setglist(&gp, owner, &sc->sc_gobj);
     SETPOINTER(argv, &gp);
     template_notify(template, s, argc, argv);
     gpointer_unset(&gp);
@@ -3717,7 +3717,7 @@ static int draw_click(t_gobj *z, t_glist *glist,
         draw_motion_template = template;
         if (draw_motion_scalar)
             gpointer_setglist(&draw_motion_gpointer, draw_motion_glist,
-                draw_motion_scalar);
+                &draw_motion_scalar->sc_gobj);
         else gpointer_setarray(&draw_motion_gpointer,
                 draw_motion_array, draw_motion_wp);
         glist_grab(glist, z, draw_motion, 0, xpix, ypix);
@@ -4323,7 +4323,7 @@ static int curve_click(t_gobj *z, t_glist *glist,
         curve_motion_template = template;
         if (curve_motion_scalar)
             gpointer_setglist(&curve_motion_gpointer, curve_motion_glist,
-                curve_motion_scalar);
+                &curve_motion_scalar->sc_gobj);
         else gpointer_setarray(&curve_motion_gpointer,
                 curve_motion_array, curve_motion_wp);
         glist_grab(glist, z, curve_motion, 0, xpix, ypix);
@@ -6551,7 +6551,7 @@ static int drawnumber_click(t_gobj *z, t_glist *glist,
             drawnumber_motion_symbol = ((x->x_flags & DRAW_SYMBOL) != 0);
             if (drawnumber_motion_scalar)
                 gpointer_setglist(&drawnumber_motion_gpointer, 
-                    drawnumber_motion_glist, drawnumber_motion_scalar);
+                    drawnumber_motion_glist, &drawnumber_motion_scalar->sc_gobj);
             else gpointer_setarray(&drawnumber_motion_gpointer,
                     drawnumber_motion_array, drawnumber_motion_wp);
            glist_grab(glist, z, drawnumber_motion, drawnumber_key,
@@ -6977,7 +6977,7 @@ static int drawsymbol_click(t_gobj *z, t_glist *glist,
             drawsymbol_motion_symbol = ((x->x_flags & DRAW_SYMBOL) != 0);
             if (drawsymbol_motion_scalar)
                 gpointer_setglist(&drawsymbol_motion_gpointer, 
-                    drawsymbol_motion_glist, drawsymbol_motion_scalar);
+                    drawsymbol_motion_glist, &drawsymbol_motion_scalar->sc_gobj);
             else gpointer_setarray(&drawsymbol_motion_gpointer,
                     drawsymbol_motion_array, drawsymbol_motion_wp);
            glist_grab(glist, z, drawsymbol_motion, drawsymbol_key,
@@ -7439,7 +7439,7 @@ static int drawimage_click(t_gobj *z, t_glist *glist,
             drawimage_motion_sprite = ((x->x_flags & DRAW_SPRITE) != 0);
             if (drawimage_motion_scalar)
                 gpointer_setglist(&drawimage_motion_gpointer, 
-                    drawimage_motion_glist, drawimage_motion_scalar);
+                    drawimage_motion_glist, &drawimage_motion_scalar->sc_gobj);
             else gpointer_setarray(&drawimage_motion_gpointer,
                     drawimage_motion_array, drawimage_motion_wp);
            glist_grab(glist, z, drawimage_motion, drawimage_key,
diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c
index 731ecbdd0c087af745a4c3062f6873e4ded67965..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);
@@ -83,13 +79,35 @@ int gpointer_check(const t_gpointer *gp, int headok)
     }
     else if (gs->gs_which == GP_GLIST)
     {
-        if (!headok && !gp->gp_un.gp_scalar) return (0);
-        else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
-        else return (1);
+        if (!headok && !((t_scalar *)(gp->gp_un.gp_gobj)))
+            return (0);
+        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)
+            return (0);
+        else
+            return (1);
     }
     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. */
 
@@ -98,7 +116,7 @@ static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
     t_gstub *gs = gp->gp_stub;
     if (gs->gs_which == GP_GLIST)
     {
-        t_scalar *sc = gp->gp_un.gp_scalar;
+        t_scalar *sc = (t_scalar *)(gp->gp_un.gp_gobj);
         if (sc)
             return (sc->sc_template);
         else return (0);
@@ -133,13 +151,13 @@ void gpointer_unset(t_gpointer *gp)
     }
 }
 
-void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
+void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_gobj *x)
 {
     t_gstub *gs;
     if (gs = gp->gp_stub) gstub_dis(gs);
     gp->gp_stub = gs = glist->gl_stub;
     gp->gp_valid = glist->gl_valid;
-    gp->gp_un.gp_scalar = x;
+    gp->gp_un.gp_gobj = x;
     gs->gs_refcount++;
 }
 
@@ -157,7 +175,7 @@ void gpointer_init(t_gpointer *gp)
 {
     gp->gp_stub = 0;
     gp->gp_valid = 0;
-    gp->gp_un.gp_scalar = 0;
+    gp->gp_un.gp_gobj = 0;
 }
 
 /* ---------------------- pointers ----------------------------- */
@@ -236,7 +254,7 @@ static void ptrobj_vnext(t_ptrobj *x, t_float f)
             "ptrobj_vnext: next-selected only works for a visible window");
         return;
     }
-    gobj = &gp->gp_un.gp_scalar->sc_gobj;
+    gobj = gp->gp_un.gp_gobj;
     
     if (!gobj) gobj = glist->gl_list;
     else gobj = gobj->g_next;
@@ -251,7 +269,7 @@ static void ptrobj_vnext(t_ptrobj *x, t_float f)
         t_scalar *sc = (t_scalar *)gobj;
         t_symbol *templatesym = sc->sc_template;
 
-        gp->gp_un.gp_scalar = sc; 
+        gp->gp_un.gp_gobj = &sc->sc_gobj; 
         for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
         {
             if (to->to_type == templatesym)
@@ -431,7 +449,7 @@ static void get_pointer(t_get *x, t_gpointer *gp)
         return;
     }
     if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
-    else vec = gp->gp_un.gp_scalar->sc_vec;
+    else vec = ((t_scalar *)(gp->gp_un.gp_gobj))->sc_vec;
     for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
     {
         int onset, type;
@@ -552,20 +570,20 @@ static void set_bang(t_set *x)
         return;
     if (gs->gs_which == GP_ARRAY)
         vec = gp->gp_un.gp_w;
-    else vec = gp->gp_un.gp_scalar->sc_vec;
+    else vec = ((t_scalar *)(gp->gp_un.gp_gobj))->sc_vec;
     if (x->x_issymbol)
         for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
             template_setsymbol(template, vp->gv_sym, vec, vp->gv_w.w_symbol, 1);
     else for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
         template_setfloat(template, vp->gv_sym, vec, vp->gv_w.w_float, 1);
     if (gs->gs_which == GP_GLIST)
-        scalar_redraw(gp->gp_un.gp_scalar, gs->gs_un.gs_glist);  
+        scalar_redraw((t_scalar *)(gp->gp_un.gp_gobj), gs->gs_un.gs_glist);  
     else
     {
         t_array *owner_array = gs->gs_un.gs_array;
         while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
             owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
-        scalar_redraw(owner_array->a_gp.gp_un.gp_scalar,
+        scalar_redraw((t_scalar *)(owner_array->a_gp.gp_un.gp_gobj),
             owner_array->a_gp.gp_stub->gs_un.gs_glist);  
     }
 }
@@ -654,7 +672,7 @@ static void elem_float(t_elem *x, t_float f)
         return;
     }
     if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
-    else w = gparent->gp_un.gp_scalar->sc_vec;
+    else w = ((t_scalar *)(gparent->gp_un.gp_gobj))->sc_vec;
     if (!template)
     {
         pd_error(x, "element: couldn't find template %s", templatesym->s_name);
@@ -761,7 +779,7 @@ static void getsize_pointer(t_getsize *x, t_gpointer *gp)
         return;
     }
     if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
-    else w = gp->gp_un.gp_scalar->sc_vec;
+    else w = ((t_scalar *)(gp->gp_un.gp_gobj))->sc_vec;
     
     array = *(t_array **)(((char *)w) + onset);
     outlet_float(x->x_obj.ob_outlet, (t_float)(array->a_n));
@@ -824,7 +842,7 @@ static void setsize_float(t_setsize *x, t_float f)
         return;
     }
     if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
-    else w = gp->gp_un.gp_scalar->sc_vec;
+    else w = ((t_scalar *)(gp->gp_un.gp_gobj))->sc_vec;
 
     if (!template)
     {
@@ -869,7 +887,7 @@ static void setsize_float(t_setsize *x, t_float f)
     if (gs->gs_which == GP_GLIST)
     {
         if (glist_isvisible(gs->gs_un.gs_glist))
-            gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);  
+            gobj_vis(gp->gp_un.gp_gobj, gs->gs_un.gs_glist, 0);  
     }
     else
     {
@@ -877,7 +895,7 @@ static void setsize_float(t_setsize *x, t_float f)
         while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
             owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
         if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
-            gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
+            gobj_vis(owner_array->a_gp.gp_un.gp_gobj,
                 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);  
     }
         /* now do the resizing and, if growing, initialize new scalars */
@@ -901,7 +919,7 @@ static void setsize_float(t_setsize *x, t_float f)
     if (gs->gs_which == GP_GLIST)
     {
         if (glist_isvisible(gs->gs_un.gs_glist))
-            gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);  
+            gobj_vis(gp->gp_un.gp_gobj, gs->gs_un.gs_glist, 1);  
     }
     else
     {
@@ -909,7 +927,7 @@ static void setsize_float(t_setsize *x, t_float f)
         while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
             owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
         if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
-            gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
+            gobj_vis(owner_array->a_gp.gp_un.gp_gobj,
                 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);  
     }
 }
@@ -1013,7 +1031,7 @@ static void append_float(t_append *x, t_float f)
         pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
         return;
     }
-    oldsc = gp->gp_un.gp_scalar;
+    oldsc = (t_scalar *)(gp->gp_un.gp_gobj);
     
     if (oldsc)
     {
@@ -1026,7 +1044,7 @@ static void append_float(t_append *x, t_float f)
         glist->gl_list = &sc->sc_gobj;
     }
 
-    gp->gp_un.gp_scalar = sc;
+    gp->gp_un.gp_gobj = (t_gobj *)sc;
     vec = sc->sc_vec;
     for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
     {
@@ -1106,7 +1124,7 @@ static void sublist_pointer(t_sublist *x, t_gpointer *gp)
         return;
     }
     if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
-    else w = gp->gp_un.gp_scalar->sc_vec;
+    else w = ((t_scalar *)(gp->gp_un.gp_gobj))->sc_vec;
     
     gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
 
diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h
index 5f6f1e1e2f9e27c66ba2715bfc0d645aab55a506..d36eee4e08578466b17b73495a0a1f5efa136ec4 100644
--- a/pd/src/m_pd.h
+++ b/pd/src/m_pd.h
@@ -111,7 +111,8 @@ typedef struct _gpointer           /* pointer to a gobj in a glist */
 {
     union
     {   
-        struct _scalar *gp_scalar;  /* scalar we're in (if glist) */
+        struct _gobj *gp_gobj;      /* header for the t_text or
+                                       scalar we're in (if glist) */
         union word *gp_w;           /* raw data (if array) */
     } gp_un;
     int gp_valid;                   /* number which must match gpointee */
diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c
index 479da8f4c0b10ec63f535fdfbb0a2161f40f86ad..0f0085ae80dfd98dffae1fca1146654cf74776ba 100644
--- a/pd/src/x_interface.c
+++ b/pd/src/x_interface.c
@@ -128,9 +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_objectinfo;
 
 /* used by all the *info objects */
@@ -190,6 +189,8 @@ t_canvas *canvas_climb(t_canvas *c, int level)
   }
 }
 
+void canvas_getargs_after_creation(t_canvas *c, int *argcp, t_atom **argvp);
+
 void canvasinfo_args(t_canvasinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
     t_canvas *c = canvas_climb(x->x_canvas, x->x_depth);
@@ -205,12 +206,24 @@ void canvasinfo_args(t_canvasinfo *x, t_symbol *s, int argc, t_atom *argv)
     }
     else
     {
-        n = binbuf_getnatom(b);
-        a = binbuf_getvec(b);
         if (s == gensym("args"))
-            info_out((t_text *)x, s, n-1, a+1);
+        {
+            canvas_getargs_after_creation(c, &n, &a);
+            info_out((t_text *)x, s, n, a);
+        }
         else
+        {
+            /* For "boxtext" have to escape semi, comma, dollar, and
+               dollsym atoms, which is what binbuf_addbinbuf does.
+               Otherwise the user could pass them around or save them
+               unescaped, which might cause trouble. */
+            t_binbuf *escaped = binbuf_new();
+            binbuf_addbinbuf(escaped, b);
+            n = binbuf_getnatom(escaped);
+            a = binbuf_getvec(escaped);
             info_out((t_text *)x, s, n, a);
+            binbuf_free(escaped);
+        }
     }
 }
 
@@ -277,24 +290,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)
@@ -381,6 +457,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,
@@ -397,6 +474,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,
@@ -469,7 +548,31 @@ void pdinfo_audio_api(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
     info_out((t_text *)x, s, 1, at);
 }
 
-void pdinfo_classtable(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
+void pdinfo_canvaslist(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_canvas *c;
+    int j, i = 0;
+    t_binbuf *outbuf = binbuf_new();
+    t_atom at[1];
+    for (c = canvas_list; c; c = c->gl_next)
+        i++;
+    t_gpointer *gp = (t_gpointer *)t_getbytes(i * sizeof(*gp));
+    for (c = canvas_list, i = 0; c; c = c->gl_next, i++)
+    {
+        gpointer_init(gp+i);
+        gpointer_setglist(gp+i, c, 0);
+        SETPOINTER(at, gp+i);
+        binbuf_add(outbuf, 1, at); 
+    }
+    info_out((t_text *)x, s, binbuf_getnatom(outbuf), binbuf_getvec(outbuf));
+    binbuf_free(outbuf);
+    for (j = 0; j < i; j++)
+        gpointer_unset(gp+j);
+    freebytes(gp, i * sizeof(*gp));
+}
+
+/* maybe this should be the bang method? */
+void pdinfo_classlist(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
     int size = classtable_size();
     if (info_to_console)
@@ -493,7 +596,7 @@ void pdinfo_audioin(t_pdinfo *x, t_symbol *s, int argc, t_atom *arg)
 //        char i
 }
 
-void pdinfo_audio_api_list_raw(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
+void pdinfo_audio_api_list_all(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
 {
     t_atom at[7];
     int i;
@@ -729,14 +832,6 @@ void pdinfo_version(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
     info_out((t_text *)x, s, 3, at);
 }
 
-void pdinfo_pi(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
-{
-    t_atom at[1];
-    const t_float Pi = 3.141592653589793;
-    SETFLOAT(at, Pi);
-    info_out((t_text *)x, s, 1, at);
-}
-
 void pdinfo_print(t_pdinfo *x)
 {
     info_print((t_text *)x);
@@ -760,8 +855,8 @@ void pdinfo_setup(void)
         gensym("audio-api"), A_DEFFLOAT, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_audio_apilist,
         gensym("audio-apilist"), A_GIMME, 0);
-    class_addmethod(pdinfo_class, (t_method)pdinfo_audio_api_list_raw,
-        gensym("audio-apilist-raw"), A_GIMME, 0);
+    class_addmethod(pdinfo_class, (t_method)pdinfo_audio_api_list_all,
+        gensym("audio-apilist-all"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_audio_inchannels,
         gensym("audio-inchannels"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_audio_dev,
@@ -780,8 +875,10 @@ void pdinfo_setup(void)
         gensym("blocksize"), A_GIMME, 0);
     /* this needs a better name-- the user doesn't have to know the
        name used in the implementation */
-    class_addmethod(pdinfo_class, (t_method)pdinfo_classtable,
-        gensym("classtable"), A_GIMME, 0);
+    class_addmethod(pdinfo_class, (t_method)pdinfo_canvaslist,
+        gensym("canvaslist"), A_GIMME, 0);
+    class_addmethod(pdinfo_class, (t_method)pdinfo_classlist,
+        gensym("classlist"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_dir,
         gensym("dir"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_dsp,
@@ -798,8 +895,6 @@ void pdinfo_setup(void)
         gensym("midi-outdev"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_midi_listdevs,
         gensym("midi-outdevlist"), A_GIMME, 0);
-    class_addmethod(pdinfo_class, (t_method)pdinfo_pi,
-        gensym("pi"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_audio_samplerate,
         gensym("samplerate"), A_GIMME, 0);
     class_addmethod(pdinfo_class, (t_method)pdinfo_version,
@@ -995,18 +1090,45 @@ 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_float(t_floatarg f)
+void objectinfo_bang(t_objectinfo *x)
 {
+    t_atom at[1];
+    t_gpointer gp;
+    gpointer_init(&gp);
+    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);
+}
 
+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(x);
+    post("object is .%x", obj);
+    x->x_test = obj;
+    */
 }
 
 void objectinfo_parseargs(t_objectinfo *x, int argc, t_atom *argv)
@@ -1027,6 +1149,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)
@@ -1034,16 +1157,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;
@@ -1056,9 +1178,16 @@ void objectinfo_boxtext(t_objectinfo *x, t_symbol *s, int argc, t_atom *argv)
         }
         else
         {
-            n = binbuf_getnatom(b);
-            a = binbuf_getvec(b);
+            /* We have to escape semi, comma, dollar, and dollsym atoms,
+               which is what binbuf_addbinbuf does.  Otherwise the user
+               could pass them around or save them unescaped, which might 
+               cause trouble. */
+            t_binbuf *escaped = binbuf_new();
+            binbuf_addbinbuf(escaped, b);
+            n = binbuf_getnatom(escaped);
+            a = binbuf_getvec(escaped);
             info_out((t_text *)x, s, n, a);
+            binbuf_free(escaped);
         }
     }
     else
@@ -1067,16 +1196,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);
@@ -1096,11 +1228,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));
@@ -1110,17 +1240,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);
@@ -1130,6 +1287,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);
@@ -1139,11 +1297,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;
@@ -1156,6 +1311,7 @@ void objectinfo_setup(void)
         sizeof(t_objectinfo),
         CLASS_DEFAULT, A_DEFFLOAT, 0);
 
+    class_addbang(objectinfo_class, objectinfo_bang);
     class_addfloat(objectinfo_class, objectinfo_float);
     class_addmethod(objectinfo_class, (t_method)objectinfo_bbox,
         gensym("bbox"), A_GIMME, 0);
@@ -1163,6 +1319,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,