--- g_canvas.c	2011-03-19 18:55:04.000000000 -0400
+++ g_canvas.c	2011-05-25 11:47:53.838118003 -0400
@@ -1410,6 +1410,170 @@
         dirresult, nameresult, size, bin));
 }
 
+void canvas_doget(t_symbol *dest, t_symbol *s, int argc, t_atom *argv)
+{
+    if (dest)
+    {
+	if (dest->s_thing)
+	    typedmess(dest->s_thing, s, argc, argv);
+    }
+    else {
+	startpost("%s", s->s_name);
+	if (argc > 0)
+	    postatom(argc, argv);
+	endpost();
+    }
+}
+
+void canvas_get(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *what = 0, *dest = 0, *attr;
+    t_int all = 0;
+    if (!argc || argc == 0 || argv[0].a_w.w_symbol == gensym("*"))
+	all = 1;
+    if (argc == 1)
+        what = argv[0].a_w.w_symbol;
+    else if (argc > 1)
+    {
+	if (argv[1].a_type == A_SYMBOL)
+	{
+            what = argv[0].a_w.w_symbol;
+            dest = argv[1].a_w.w_symbol;
+	}
+	else
+	{
+	    pd_error(x, "canvas_get: receive symbol must be symbol-atom");
+	}
+    }
+    if (what == (attr=gensym("args")) || all)
+    {
+        t_canvasenvironment *ce = x->gl_env;
+	int n = ce->ce_argc;
+	t_atom *at = ce->ce_argv;
+	canvas_doget(dest, attr, n, at);
+    }
+    if (what == (attr=gensym("coords")) || all)
+    {
+	t_int gop = x->gl_isgraph + x->gl_hidetext;
+        t_atom at[9];
+        SETFLOAT(at, (x->gl_isgraph) ? x->gl_x1 : 0);
+        SETFLOAT(at+1, (x->gl_isgraph) ? x->gl_y1 : 0);
+        SETFLOAT(at+2, (x->gl_isgraph) ? x->gl_x2 : 0);
+        SETFLOAT(at+3, (x->gl_isgraph) ? x->gl_y2 : 0);
+	SETFLOAT(at+4, (x->gl_isgraph) ? x->gl_pixwidth : 0);
+	SETFLOAT(at+5, (x->gl_isgraph) ? x->gl_pixheight : 0);
+	SETFLOAT(at+6, (x->gl_isgraph) ? gop : 0);
+	SETFLOAT(at+7, (x->gl_isgraph) ? x->gl_xmargin : 0);
+	SETFLOAT(at+8, (x->gl_isgraph) ? x->gl_ymargin : 0);
+	canvas_doget(dest, attr, 9, at);
+    }
+    if (what == (attr=gensym("dir")) || all)
+    {
+	t_canvas *c = canvas_getrootfor(x);
+	t_symbol *dir = canvas_getdir(c);
+        t_atom at[1];
+	SETSYMBOL(at, dir);
+	canvas_doget(dest, attr, 1, at);
+    }
+
+    if (what == (attr=gensym("dirty")) || all)
+    {
+        t_int d = x->gl_dirty;
+	t_atom at[1];
+	SETFLOAT(at, (t_float) d);
+	canvas_doget(dest, attr, 1, at);
+    }
+    if (what == (attr=gensym("dollarzero")) || all)
+    {
+	t_canvas *c = canvas_getrootfor(x);
+	t_canvasenvironment *ce = c->gl_env;
+	int dollarzero = ce->ce_dollarzero;
+        t_atom at[1];
+        SETFLOAT(at, dollarzero);
+	canvas_doget(dest, attr, 1, at);
+    }
+
+    if (what == (attr=gensym("editmode")) || all)
+    {
+        t_int e = x->gl_edit;
+	t_atom at[1];
+	SETFLOAT(at, (t_float) e);
+	canvas_doget(dest, attr, 1, at);
+    }
+    if (what == (attr=gensym("filename")) || all)
+    {
+	t_canvas *c = canvas_getrootfor(x);
+	t_symbol *filename = c->gl_name;
+        t_atom at[1];
+        SETSYMBOL(at, filename);
+	canvas_doget(dest, attr, 1, at);
+    }
+    if (what == (attr=gensym("localpath")) || all)
+    {
+	t_canvas *c = canvas_getrootfor(x);
+	t_canvasenvironment *ce = c->gl_env;
+	t_namelist *nl;
+	int i;
+	for ( nl = ce->ce_path, i = 0; nl; nl=nl->nl_next, i++) {}
+	t_atom at[i];
+	for ( nl = ce->ce_path, i = 0; nl; nl=nl->nl_next, i++)
+	{
+	    char *str = nl->nl_string;
+	    SETSYMBOL(at+i, gensym(str)); 
+	}
+	canvas_doget(dest, attr, i, at);
+    }
+    if (what == (attr=gensym("parent")) || all)
+    {
+	t_canvas *c = (x->gl_owner) ? x->gl_owner : x;
+        t_atom at[1];
+	if (x->gl_owner)
+	{
+	    t_gpointer gp;
+	    gpointer_init(&gp);
+	    gpointer_setglist(&gp, c, 0);
+	    SETPOINTER(at, &gp);
+	    canvas_doget(dest, attr, 1, at);
+	    gpointer_unset(&gp);
+	}
+	else
+	{
+	    SETFLOAT(at, 0);
+	    canvas_doget(dest, attr, 1, at);
+        }
+    }
+    if (what == (attr=gensym("posonparent")) || all)
+    {
+	t_atom at[2];
+	t_canvas *c = x;
+	int xpos = c->gl_obj.te_xpix;
+	int ypos = c->gl_obj.te_ypix;
+	SETFLOAT(at, (t_float) xpos);
+	SETFLOAT(at+1, (t_float) ypos);
+	canvas_doget(dest, attr, 2, at);
+    }
+    if (what == (attr=gensym("screenpos")) || all)
+    {
+        t_int x1 = x->gl_screenx1;
+        t_int y1 = x->gl_screeny1;
+        t_int x2 = x->gl_screenx2;
+        t_int y2 = x->gl_screeny2;
+        t_atom at[4];
+        SETFLOAT(at, (t_float) x1);
+	SETFLOAT(at+1, (t_float) y1);
+        SETFLOAT(at+2, (t_float) x2);
+	SETFLOAT(at+3, (t_float) y2);
+	canvas_doget(dest, attr, 4, at);
+    }
+    if (what == (attr=gensym("vis")) || all)
+    {
+        t_int v = glist_isvisible(x);
+        t_atom at[1];
+        SETFLOAT(at, (t_float) v);
+	canvas_doget(dest, attr, 1, at);
+    }
+}
+
 /* ------------------------------- setup routine ------------------------ */
 
     /* why are some of these "glist" and others "canvas"? */
@@ -1528,6 +1692,10 @@
     class_addmethod(canvas_class, (t_method)canvas_rename_method,
         gensym("rename"), A_GIMME, 0);
 
+/* ---------------------- user queries ---------------------- */
+    class_addmethod(canvas_class, (t_method)canvas_get, gensym("get"),
+        A_GIMME, 0); 
+
 /*---------------------------- tables -- GG ------------------- */
 
     class_addcreator((t_newmethod)table_new, gensym("table"),
