From 9fae1676221a4a0f6c26a3902fe31bdf62d340a6 Mon Sep 17 00:00:00 2001
From: Miller Puckette <msp@ucsd.edu>
Date: Mon, 17 Sep 2007 11:36:46 -0700
Subject: [PATCH] font patch from HC

---
 src/g_all_guis.c      |    9 +-
 src/g_all_guis.h      |    2 +-
 src/g_bang.c          |   13 +-
 src/g_graph.c         |   19 +-
 src/g_hdial.c         |   12 +-
 src/g_hslider.c       |   13 +-
 src/g_mycanvas.c      |   14 +-
 src/g_numbox.c        |   22 +-
 src/g_rtext.c         |   10 +-
 src/g_template.c      |    4 +-
 src/g_template.c.orig | 2333 ++++++++++++++++++++++
 src/g_toggle.c        |   13 +-
 src/g_vdial.c         |   12 +-
 src/g_vslider.c       |   13 +-
 src/g_vumeter.c       |   51 +-
 src/m_pd.h            |    2 +
 src/makefile.in       |    4 +-
 src/s_inter.c         |    8 +-
 src/s_inter.c.orig    | 1300 +++++++++++++
 src/s_main.c          |   36 +-
 src/s_main.c.orig     | 1001 ++++++++++
 src/u_main.tk         |  579 +++---
 src/u_main.tk.orig    | 4252 +++++++++++++++++++++++++++++++++++++++++
 src/x_qlist.c         |   11 +-
 24 files changed, 9379 insertions(+), 354 deletions(-)
 create mode 100644 src/g_template.c.orig
 create mode 100644 src/s_inter.c.orig
 create mode 100644 src/s_main.c.orig
 create mode 100644 src/u_main.tk.orig

diff --git a/src/g_all_guis.c b/src/g_all_guis.c
index 2d18f4801..0547b0de7 100644
--- a/src/g_all_guis.c
+++ b/src/g_all_guis.c
@@ -438,7 +438,7 @@ void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *a
     else
     {
         f = 0;
-        strcpy(iemgui->x_font, "courier");
+        strcpy(iemgui->x_font, sys_font);
     }
     iemgui->x_fsf.x_font_style = f;
     f = (int)atom_getintarg(1, ac, av);
@@ -446,8 +446,9 @@ void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *a
         f = 4;
     iemgui->x_fontsize = f;
     if(glist_isvisible(iemgui->x_glist))
-        sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold}\n",
-                 glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, iemgui->x_fontsize);
+        sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s}\n",
+                 glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, 
+				 iemgui->x_fontsize, sys_fontweight);
 }
 
 void iemgui_size(void *x, t_iemgui *iemgui)
@@ -622,7 +623,7 @@ int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv)
     else
     {
         f = 0;
-        strcpy(iemgui->x_font, "courier");
+        strcpy(iemgui->x_font, sys_font);
     }
     iemgui->x_fsf.x_font_style = f;
     if(fs < 4)
diff --git a/src/g_all_guis.h b/src/g_all_guis.h
index 2d7d7dd67..189d2c768 100644
--- a/src/g_all_guis.h
+++ b/src/g_all_guis.h
@@ -144,7 +144,7 @@ typedef struct _iemgui
     int                x_w;
     int                x_ldx;
     int                x_ldy;
-    char               x_font[16];
+    char               x_font[MAXPDSTRING]; /* font names can be long! */
     t_iem_fstyle_flags x_fsf;
     int                x_fontsize;
     t_iem_init_symargs x_isa;
diff --git a/src/g_bang.c b/src/g_bang.c
index 3a5ef4d31..cd4b71291 100644
--- a/src/g_bang.c
+++ b/src/g_bang.c
@@ -55,11 +55,12 @@ void bng_draw_new(t_bng *x, t_glist *glist)
              xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1,
              x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xpos+x->x_gui.x_ldx,
              ypos+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
              canvas, xpos,
@@ -115,8 +116,8 @@ void bng_draw_config(t_bng* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
@@ -237,7 +238,7 @@ static void bng_properties(t_gobj *z, t_glist *owner)
     t_symbol *srl[3];
 
     iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s BANG \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |bang| \
             ----------dimensions(pix):----------- %d %d size: 0 0 empty \
             --------flash-time(ms)(ms):--------- %d intrrpt: %d hold: %d \
             %d empty empty %d %d empty %d \
@@ -481,7 +482,7 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
 
     if (x->x_gui.x_fsf.x_rcv_able)
         pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
diff --git a/src/g_graph.c b/src/g_graph.c
index 1f449a63c..7db14b5e6 100644
--- a/src/g_graph.c
+++ b/src/g_graph.c
@@ -741,9 +741,9 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
         {
             i -= sys_fontheight(glist_getfont(x));
             sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor nw\
-             -font -*-courier-bold--normal--%d-* -tags %s\n",
-                (long)glist_getcanvas(x),  x1, i, arrayname->s_name,
-                sys_hostfontsize(glist_getfont(x)), tag);
+             -font {{%s} %d %s} -tags %s\n",
+             (long)glist_getcanvas(x),  x1, i, arrayname->s_name, sys_font,
+                sys_hostfontsize(glist_getfont(x)), sys_fontweight, tag);
         }
         
             /* draw ticks on horizontal borders.  If lperb field is
@@ -823,21 +823,22 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
             /* draw x labels */
         for (i = 0; i < x->gl_nxlabels; i++)
             sys_vgui(".x%lx.c create text\
-        %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
+        %d %d -text {%s} -font {{%s} %d %s} -tags %s\n",
                 glist_getcanvas(x),
                 (int)glist_xtopixels(x, atof(x->gl_xlabel[i]->s_name)),
-                (int)glist_ytopixels(x, x->gl_xlabely), x->gl_xlabel[i]->s_name,
-                glist_getfont(x), tag);
+                (int)glist_ytopixels(x, x->gl_xlabely),
+                x->gl_xlabel[i]->s_name, sys_font, 
+					 glist_getfont(x), sys_fontweight, tag);
 
             /* draw y labels */
         for (i = 0; i < x->gl_nylabels; i++)
             sys_vgui(".x%lx.c create text\
-        %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
+        %d %d -text {%s} -font {{%s} %d %s} -tags %s\n",
                 glist_getcanvas(x),
                 (int)glist_xtopixels(x, x->gl_ylabelx),
                 (int)glist_ytopixels(x, atof(x->gl_ylabel[i]->s_name)),
-                x->gl_ylabel[i]->s_name,
-                glist_getfont(x), tag);
+                x->gl_ylabel[i]->s_name, sys_font,
+                glist_getfont(x), sys_fontweight, tag);
 
             /* draw contents of graph as glist */
         for (g = x->gl_list; g; g = g->g_next)
diff --git a/src/g_hdial.c b/src/g_hdial.c
index df5951269..64b0711e2 100644
--- a/src/g_hdial.c
+++ b/src/g_hdial.c
@@ -73,10 +73,10 @@ void hradio_draw_new(t_hradio *x, t_glist *glist)
         x->x_drawn = x->x_on;
     }
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize,
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
@@ -141,8 +141,8 @@ void hradio_draw_config(t_hradio* x, t_glist* glist)
     t_canvas *canvas=glist_getcanvas(glist);
     int n=x->x_number, i;
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     for(i=0; i<n; i++)
@@ -264,7 +264,7 @@ static void hradio_properties(t_gobj *z, t_glist *owner)
     iemgui_properties(&x->x_gui, srl);
     if (pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class)
         hchange = x->x_change;
-    sprintf(buf, "pdtk_iemgui_dialog %%s hradio \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |hradio| \
             ----------dimensions(pix):----------- %d %d size: 0 0 empty \
             empty 0.0 empty 0.0 empty %d \
             %d new-only new&old %d %d number: %d \
@@ -589,7 +589,7 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if(num < 1)
         num = 1;
     if(num > IEM_RADIO_MAX)
diff --git a/src/g_hslider.c b/src/g_hslider.c
index 4958639ab..cc776be41 100644
--- a/src/g_hslider.c
+++ b/src/g_hslider.c
@@ -76,11 +76,12 @@ static void hslider_draw_new(t_hslider *x, t_glist *glist)
              canvas, r, ypos+1, r,
              ypos + x->x_gui.x_h, x->x_gui.x_fcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xpos+x->x_gui.x_ldx,
              ypos+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
              canvas, xpos-3, ypos + x->x_gui.x_h-1,
@@ -136,8 +137,8 @@ static void hslider_draw_config(t_hslider* x,t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     sys_vgui(".x%lx.c itemconfigure %lxKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
@@ -285,7 +286,7 @@ static void hslider_properties(t_gobj *z, t_glist *owner)
     t_symbol *srl[3];
 
     iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s HSLIDER \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |hsl| \
             --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
             -----------output-range:----------- %g left: %g right: %g \
             %d lin log %d %d empty %d \
@@ -586,7 +587,7 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if(x->x_gui.x_fsf.x_rcv_able)
         pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
     x->x_gui.x_ldx = ldx;
diff --git a/src/g_mycanvas.c b/src/g_mycanvas.c
index 93f96ff59..50abdcabf 100644
--- a/src/g_mycanvas.c
+++ b/src/g_mycanvas.c
@@ -44,10 +44,11 @@ void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
              xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
              x->x_gui.x_bcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
 }
 
 void my_canvas_draw_move(t_my_canvas *x, t_glist *glist)
@@ -84,8 +85,9 @@ void my_canvas_draw_config(t_my_canvas* x, t_glist* glist)
              x->x_gui.x_bcol, x->x_gui.x_bcol);
     sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%6.6x\n", canvas, x,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_bcol);
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
 }
 
@@ -152,7 +154,7 @@ static void my_canvas_properties(t_gobj *z, t_glist *owner)
     t_symbol *srl[3];
 
     iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s MY_CANVAS \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |cnv| \
             ------selectable_dimensions(pix):------ %d %d size: 0.0 0.0 empty \
             ------visible_rectangle(pix)(pix):------ %d width: %d height: %d \
             %d empty empty %d %d empty %d \
@@ -331,7 +333,7 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if (x->x_gui.x_fsf.x_rcv_able)
         pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
     x->x_gui.x_ldx = ldx;
diff --git a/src/g_numbox.c b/src/g_numbox.c
index 04c9c1bb5..099acc301 100644
--- a/src/g_numbox.c
+++ b/src/g_numbox.c
@@ -195,15 +195,17 @@ static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
         xpos, ypos + x->x_gui.x_h,
         x->x_gui.x_fcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-        -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+        -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
         canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
         strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-        x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+        x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
     my_numbox_ftoa(x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-        -font {%s %d bold} -fill #%6.6x -tags %lxNUMBER\n",
+        -font {{%s} %d %s} -fill #%6.6x -tags %lxNUMBER\n",
         canvas, xpos+half+2, ypos+half+d,
-        x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_fcol, x);
+        x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+        x->x_gui.x_fcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
              canvas,
@@ -269,12 +271,12 @@ static void my_numbox_draw_config(t_my_numbox* x,t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
-    sys_vgui(".x%lx.c itemconfigure %lxNUMBER -font {%s %d bold} -fill #%6.6x \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxNUMBER -font {{%s} %d %s} -fill #%6.6x \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
     sys_vgui(".x%lx.c itemconfigure %lxBASE1 -fill #%6.6x\n", canvas,
              x, x->x_gui.x_bcol);
@@ -451,7 +453,7 @@ static void my_numbox_properties(t_gobj *z, t_glist *owner)
         sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update);
 
     }
-    sprintf(buf, "pdtk_iemgui_dialog %%s NUMBERBOX \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |nbx| \
             -------dimensions(digits)(pix):------- %d %d width: %d %d height: \
             -----------output-range:----------- %g min: %g max: %d \
             %d lin log %d %d log-height: %d \
@@ -806,7 +808,7 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if (x->x_gui.x_fsf.x_rcv_able)
         pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
     x->x_gui.x_ldx = ldx;
diff --git a/src/g_rtext.c b/src/g_rtext.c
index cbb0ba887..8af48b1a5 100644
--- a/src/g_rtext.c
+++ b/src/g_rtext.c
@@ -15,10 +15,16 @@
 #include "g_canvas.h"
 #include "t_tk.h"
 
-#define LMARGIN 1
-#define RMARGIN 1
+#define LMARGIN 2
+#define RMARGIN 2
+/* for some reason, it draws text 1 pixel lower on Mac OS X (& linux too?) */
+#ifndef MSW
 #define TMARGIN 2
 #define BMARGIN 2
+#else
+#define TMARGIN 3
+#define BMARGIN 1
+#endif
 
 #define SEND_FIRST 1
 #define SEND_UPDATE 2
diff --git a/src/g_template.c b/src/g_template.c
index f5519e654..fecb805f1 100644
--- a/src/g_template.c
+++ b/src/g_template.c
@@ -2136,8 +2136,8 @@ static void drawnumber_vis(t_gobj *z, t_glist *glist,
         drawnumber_sprintf(x, buf, &at);
         sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
                 glist_getcanvas(glist), xloc, yloc, colorstring, buf);
-        sys_vgui(" -font -*-courier-bold--normal--%d-*",
-            sys_hostfontsize(glist_getfont(glist)));
+        sys_vgui(" -font {{%s} %d %s}", sys_font,
+				 sys_hostfontsize(glist_getfont(glist)), sys_fontweight);
         sys_vgui(" -tags drawnumber%lx\n", data);
     }
     else sys_vgui(".x%lx.c delete drawnumber%lx\n", glist_getcanvas(glist), data);
diff --git a/src/g_template.c.orig b/src/g_template.c.orig
new file mode 100644
index 000000000..f5519e654
--- /dev/null
+++ b/src/g_template.c.orig
@@ -0,0 +1,2333 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "m_pd.h"
+#include "s_stuff.h"    /* for sys_hostfontsize */
+#include "g_canvas.h"
+
+void array_redraw(t_array *a, t_glist *glist);
+
+/*
+This file contains text objects you would put in a canvas to define a
+template.  Templates describe objects of type "array" (g_array.c) and
+"scalar" (g_scalar.c).
+*/
+
+    /* the structure of a "struct" object (also the obsolete "gtemplate"
+    you get when using the name "template" in a box.) */
+
+struct _gtemplate
+{
+    t_object x_obj;
+    t_template *x_template;
+    t_canvas *x_owner;
+    t_symbol *x_sym;
+    struct _gtemplate *x_next;
+    int x_argc;
+    t_atom *x_argv;
+};
+
+/* ---------------- forward definitions ---------------- */
+
+static void template_conformarray(t_template *tfrom, t_template *tto,
+    int *conformaction, t_array *a);
+static void template_conformglist(t_template *tfrom, t_template *tto,
+    t_glist *glist,  int *conformaction);
+
+/* ---------------------- storage ------------------------- */
+
+static t_class *gtemplate_class;
+static t_class *template_class;
+
+/* there's a pre-defined "float" template.  LATER should we bind this
+to a symbol such as "pd-float"??? */
+
+    /* return true if two dataslot definitions match */
+static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
+    int nametoo)
+{
+    return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
+        ds1->ds_type == ds2->ds_type &&
+            (ds1->ds_type != DT_ARRAY ||
+                ds1->ds_arraytemplate == ds2->ds_arraytemplate));
+}
+
+/* -- templates, the active ingredient in gtemplates defined below. ------- */
+
+t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
+{
+    t_template *x = (t_template *)pd_new(template_class);
+    x->t_n = 0;
+    x->t_vec = (t_dataslot *)t_getbytes(0);
+    while (argc > 0)
+    {
+        int newtype, oldn, newn;
+        t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
+        if (argc < 2 || argv[0].a_type != A_SYMBOL ||
+            argv[1].a_type != A_SYMBOL)
+                goto bad;
+        newtypesym = argv[0].a_w.w_symbol;
+        newname = argv[1].a_w.w_symbol;
+        if (newtypesym == &s_float)
+            newtype = DT_FLOAT;
+        else if (newtypesym == &s_symbol)
+            newtype = DT_SYMBOL;
+        else if (newtypesym == &s_list)
+            newtype = DT_LIST;
+        else if (newtypesym == gensym("array"))
+        {
+            if (argc < 3 || argv[2].a_type != A_SYMBOL)
+            {
+                pd_error(x, "array lacks element template or name");
+                goto bad;
+            }
+            newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
+            newtype = DT_ARRAY;
+            argc--;
+            argv++;
+        }
+        else
+        {
+            pd_error(x, "%s: no such type", newtypesym->s_name);
+            goto bad;
+        }
+        newn = (oldn = x->t_n) + 1;
+        x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
+            oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
+        x->t_n = newn;
+        x->t_vec[oldn].ds_type = newtype;
+        x->t_vec[oldn].ds_name = newname;
+        x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
+    bad: 
+        argc -= 2; argv += 2;
+    }
+    if (templatesym->s_name)
+    {
+        x->t_sym = templatesym;
+        pd_bind(&x->t_pdobj, x->t_sym);
+    }
+    else x->t_sym = templatesym;
+    return (x);
+}
+
+int template_size(t_template *x)
+{
+    return (x->t_n * sizeof(t_word));
+}
+
+int template_find_field(t_template *x, t_symbol *name, int *p_onset,
+    int *p_type, t_symbol **p_arraytype)
+{
+    t_template *t;
+    int i, n;
+    if (!x)
+    {
+        bug("template_find_field");
+        return (0);
+    }
+    n = x->t_n;
+    for (i = 0; i < n; i++)
+        if (x->t_vec[i].ds_name == name)
+    {
+        *p_onset = i * sizeof(t_word);
+        *p_type = x->t_vec[i].ds_type;
+        *p_arraytype = x->t_vec[i].ds_arraytemplate;
+        return (1);
+    }
+    return (0);
+}
+
+t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
+    int loud)
+{
+    int onset, type;
+    t_symbol *arraytype;
+    float val = 0;
+    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+    {
+        if (type == DT_FLOAT)
+            val = *(t_float *)(((char *)wp) + onset);
+        else if (loud) error("%s.%s: not a number",
+            x->t_sym->s_name, fieldname->s_name);
+    }
+    else if (loud) error("%s.%s: no such field",
+        x->t_sym->s_name, fieldname->s_name);
+    return (val);
+}
+
+void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, 
+    t_float f, int loud)
+{
+    int onset, type;
+    t_symbol *arraytype;
+    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+     {
+        if (type == DT_FLOAT)
+            *(t_float *)(((char *)wp) + onset) = f;
+        else if (loud) error("%s.%s: not a number",
+            x->t_sym->s_name, fieldname->s_name);
+    }
+    else if (loud) error("%s.%s: no such field",
+        x->t_sym->s_name, fieldname->s_name);
+}
+
+t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
+    int loud)
+{
+    int onset, type;
+    t_symbol *arraytype;
+    t_symbol *val = &s_;
+    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+    {
+        if (type == DT_SYMBOL)
+            val = *(t_symbol **)(((char *)wp) + onset);
+        else if (loud) error("%s.%s: not a symbol",
+            x->t_sym->s_name, fieldname->s_name);
+    }
+    else if (loud) error("%s.%s: no such field",
+        x->t_sym->s_name, fieldname->s_name);
+    return (val);
+}
+
+void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, 
+    t_symbol *s, int loud)
+{
+    int onset, type;
+    t_symbol *arraytype;
+    if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+     {
+        if (type == DT_SYMBOL)
+            *(t_symbol **)(((char *)wp) + onset) = s;
+        else if (loud) error("%s.%s: not a symbol",
+            x->t_sym->s_name, fieldname->s_name);
+    }
+    else if (loud) error("%s.%s: no such field",
+        x->t_sym->s_name, fieldname->s_name);
+}
+
+    /* stringent check to see if a "saved" template, x2, matches the current
+        one (x1).  It's OK if x1 has additional scalar elements but not (yet)
+        arrays or lists.  This is used for reading in "data files". */
+int template_match(t_template *x1, t_template *x2)
+{
+    int i;
+    if (x1->t_n < x2->t_n)
+        return (0);
+    for (i = x2->t_n; i < x1->t_n; i++)
+    {
+        if (x1->t_vec[i].ds_type == DT_ARRAY || 
+            x1->t_vec[i].ds_type == DT_LIST)
+                return (0);
+    }
+    if (x2->t_n > x1->t_n)
+        post("add elements...");
+    for (i = 0; i < x2->t_n; i++)
+        if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
+            return (0);
+    return (1);
+}
+
+/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
+
+/* the following routines handle updating scalars to agree with changes
+in their template.  The old template is assumed to be the "installed" one
+so we can delete old items; but making new ones we have to avoid scalar_new
+which would make an old one whereas we will want a new one (but whose array
+elements might still be old ones.)
+    LATER deal with graphics updates too... */
+
+    /* conform the word vector of a scalar to the new template */    
+static void template_conformwords(t_template *tfrom, t_template *tto,
+    int *conformaction, t_word *wfrom, t_word *wto)
+{
+    int nfrom = tfrom->t_n, nto = tto->t_n, i;
+    for (i = 0; i < nto; i++)
+    {
+        if (conformaction[i] >= 0)
+        {
+                /* we swap the two, in case it's an array or list, so that
+                when "wfrom" is deleted the old one gets cleaned up. */
+            t_word wwas = wto[i];
+            wto[i] = wfrom[conformaction[i]];
+            wfrom[conformaction[i]] = wwas;
+        }
+    }
+}
+
+    /* conform a scalar, recursively conforming sublists and arrays  */
+static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
+    int *conformaction, t_glist *glist, t_scalar *scfrom)
+{
+    t_scalar *x;
+    t_gpointer gp;
+    int nto = tto->t_n, nfrom = tfrom->t_n, i;
+    t_template *scalartemplate;
+    /* post("conform scalar"); */
+        /* possibly replace the scalar */
+    if (scfrom->sc_template == tfrom->t_sym)
+    {
+            /* see scalar_new() for comment about the gpointer. */
+        gpointer_init(&gp);
+        x = (t_scalar *)getbytes(sizeof(t_scalar) +
+            (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);
+            /* 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);
+
+        template_conformwords(tfrom, tto, conformaction,
+            scfrom->sc_vec, x->sc_vec);
+            
+            /* replace the old one with the new one in the list */
+        if (glist->gl_list == &scfrom->sc_gobj)
+        {
+            glist->gl_list = &x->sc_gobj;
+            x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
+        }
+        else
+        {
+            t_gobj *y, *y2;
+            for (y = glist->gl_list; y2 = y->g_next; y = y2)
+                if (y2 == &scfrom->sc_gobj)
+            {
+                x->sc_gobj.g_next = y2->g_next;
+                y->g_next = &x->sc_gobj;
+                goto nobug;
+            }
+            bug("template_conformscalar");
+        nobug: ;
+        }
+            /* burn the old one */
+        pd_free(&scfrom->sc_gobj.g_pd);
+        scalartemplate = tto;
+    }
+    else
+    {
+        x = scfrom;
+        scalartemplate = template_findbyname(x->sc_template);
+    }
+        /* convert all array elements and sublists */
+    for (i = 0; i < scalartemplate->t_n; i++)
+    {
+        t_dataslot *ds = scalartemplate->t_vec + i;
+        if (ds->ds_type == DT_LIST)
+        {
+            t_glist *gl2 = x->sc_vec[i].w_list;
+            template_conformglist(tfrom, tto, gl2, conformaction);
+        }
+        else if (ds->ds_type == DT_ARRAY)
+        {
+            template_conformarray(tfrom, tto, conformaction, 
+                x->sc_vec[i].w_array);
+        }
+    }
+    return (x);
+}
+
+    /* conform an array, recursively conforming sublists and arrays  */
+static void template_conformarray(t_template *tfrom, t_template *tto,
+    int *conformaction, t_array *a)
+{
+    int i, j;
+    t_template *scalartemplate = 0;
+    if (a->a_templatesym == tfrom->t_sym)
+    {
+        /* the array elements must all be conformed */
+        int oldelemsize = sizeof(t_word) * tfrom->t_n,
+            newelemsize = sizeof(t_word) * tto->t_n;
+        char *newarray = getbytes(newelemsize * a->a_n);
+        char *oldarray = a->a_vec;
+        if (a->a_elemsize != oldelemsize)
+            bug("template_conformarray");
+        for (i = 0; i < a->a_n; i++)
+        {
+            t_word *wp = (t_word *)(newarray + newelemsize * i);
+            word_init(wp, tto, &a->a_gp);
+            template_conformwords(tfrom, tto, conformaction,
+                (t_word *)(oldarray + oldelemsize * i), wp);
+            word_free((t_word *)(oldarray + oldelemsize * i), tfrom);
+        }
+        scalartemplate = tto;
+        a->a_vec = newarray;
+        freebytes(oldarray, oldelemsize * a->a_n);
+    }
+    else scalartemplate = template_findbyname(a->a_templatesym);
+        /* convert all arrays and sublist fields in each element of the array */
+    for (i = 0; i < a->a_n; i++)
+    {
+        t_word *wp = (t_word *)(a->a_vec + sizeof(t_word) * a->a_n * i);
+        for (j = 0; j < scalartemplate->t_n; j++)
+        {
+            t_dataslot *ds = scalartemplate->t_vec + j;
+            if (ds->ds_type == DT_LIST)
+            {
+                t_glist *gl2 = wp[j].w_list;
+                template_conformglist(tfrom, tto, gl2, conformaction);
+            }
+            else if (ds->ds_type == DT_ARRAY)
+            {
+                template_conformarray(tfrom, tto, conformaction, 
+                    wp[j].w_array);
+            }
+        }
+    }
+}
+
+    /* this routine searches for every scalar in the glist that belongs
+    to the "from" template and makes it belong to the "to" template.  Descend
+    glists recursively.
+    We don't handle redrawing here; this is to be filled in LATER... */
+
+t_array *garray_getarray(t_garray *x);
+
+static void template_conformglist(t_template *tfrom, t_template *tto,
+    t_glist *glist,  int *conformaction)
+{
+    t_gobj *g;
+    /* post("conform glist %s", glist->gl_name->s_name); */
+    for (g = glist->gl_list; g; g = g->g_next)
+    {
+        if (pd_class(&g->g_pd) == scalar_class)
+            g = &template_conformscalar(tfrom, tto, conformaction,
+                glist, (t_scalar *)g)->sc_gobj;
+        else if (pd_class(&g->g_pd) == canvas_class)
+            template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
+        else if (pd_class(&g->g_pd) == garray_class)
+            template_conformarray(tfrom, tto, conformaction,
+                garray_getarray((t_garray *)g));
+    }
+}
+
+    /* globally conform all scalars from one template to another */ 
+void template_conform(t_template *tfrom, t_template *tto)
+{
+    int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
+        *conformaction = (int *)getbytes(sizeof(int) * nto),
+        *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
+    for (i = 0; i < nto; i++)
+        conformaction[i] = -1;
+    for (i = 0; i < nfrom; i++)
+        conformedfrom[i] = 0;
+    for (i = 0; i < nto; i++)
+    {
+        t_dataslot *dataslot = &tto->t_vec[i];
+        for (j = 0; j < nfrom; j++)
+        {
+            t_dataslot *dataslot2 = &tfrom->t_vec[j];
+            if (dataslot_matches(dataslot, dataslot2, 1))
+            {
+                conformaction[i] = j;
+                conformedfrom[j] = 1;
+            }
+        }
+    }
+    for (i = 0; i < nto; i++)
+        if (conformaction[i] < 0)
+    {
+        t_dataslot *dataslot = &tto->t_vec[i];
+        for (j = 0; j < nfrom; j++)
+            if (!conformedfrom[j] &&
+                dataslot_matches(dataslot, &tfrom->t_vec[j], 0))
+        {
+            conformaction[i] = j;
+            conformedfrom[j] = 1;
+        }
+    }
+    if (nto != nfrom)
+        doit = 1;
+    else for (i = 0; i < nto; i++)
+        if (conformaction[i] != i)
+            doit = 1;
+
+    if (doit)
+    {
+        t_glist *gl;
+        post("conforming template '%s' to new structure",
+            tfrom->t_sym->s_name);
+        for (i = 0; i < nto; i++)
+            post("... %d", conformaction[i]);
+        for (gl = canvas_list; gl; gl = gl->gl_next)
+            template_conformglist(tfrom, tto, gl, conformaction);
+    }
+    freebytes(conformaction, sizeof(int) * nto);
+    freebytes(conformedfrom, sizeof(int) * nfrom);
+}
+
+t_template *template_findbyname(t_symbol *s)
+{
+    return ((t_template *)pd_findbyclass(s, template_class));
+}
+
+t_canvas *template_findcanvas(t_template *template)
+{
+    t_gtemplate *gt;
+    if (!template) 
+        bug("template_findcanvas");
+    if (!(gt = template->t_list))
+        return (0);
+    return (gt->x_owner);
+    /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
+}
+
+void template_notify(t_template *template, t_symbol *s, int argc, t_atom *argv)
+{
+    if (template->t_list)
+        outlet_anything(template->t_list->x_obj.ob_outlet, s, argc, argv);
+}
+
+    /* bash the first of (argv) with a pointer to a scalar, and send on
+    to template as a notification message */
+static void template_notifyforscalar(t_template *template, t_glist *owner,
+    t_scalar *sc, t_symbol *s, int argc, t_atom *argv)
+{
+    t_gpointer gp;
+    gpointer_init(&gp);
+    gpointer_setglist(&gp, owner, sc);
+    SETPOINTER(argv, &gp);
+    template_notify(template, s, argc, argv);
+    gpointer_unset(&gp);
+}
+
+    /* call this when reading a patch from a file to declare what templates
+    we'll need.  If there's already a template, check if it matches.
+    If it doesn't it's still OK as long as there are no "struct" (gtemplate)
+    objects hanging from it; we just conform everyone to the new template.
+    If there are still struct objects belonging to the other template, we're
+    in trouble.  LATER we'll figure out how to conform the new patch's objects
+    to the pre-existing struct. */
+static void *template_usetemplate(void *dummy, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    t_template *x;
+    t_symbol *templatesym =
+        canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+    if (!argc)
+        return (0);
+    argc--; argv++;
+            /* check if there's already a template by this name. */
+    if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
+    {
+        t_template *y = template_new(&s_, argc, argv), *y2;
+            /* If the new template is the same as the old one,
+            there's nothing to do.  */
+        if (!template_match(x, y))
+        {
+                /* Are there "struct" objects upholding this template? */
+            if (x->t_list)
+            {
+                    /* don't know what to do here! */
+                error("%s: template mismatch",
+                    templatesym->s_name);
+            }
+            else
+            {
+                    /* conform everyone to the new template */
+                template_conform(x, y);
+                pd_free(&x->t_pdobj);
+                y2 = template_new(templatesym, argc, argv);
+                y2->t_list = 0;
+            }
+        }
+        pd_free(&y->t_pdobj);
+    }
+        /* otherwise, just make one. */
+    else template_new(templatesym, argc, argv);
+    return (0);
+}
+
+    /* here we assume someone has already cleaned up all instances of this. */
+void template_free(t_template *x)
+{
+    if (*x->t_sym->s_name)
+        pd_unbind(&x->t_pdobj, x->t_sym);
+    t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
+}
+
+static void template_setup(void)
+{
+    template_class = class_new(gensym("template"), 0, (t_method)template_free,
+        sizeof(t_template), CLASS_PD, 0);
+    class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
+        gensym("struct"), A_GIMME, 0);
+        
+}
+
+/* ---------------- gtemplates.  One per canvas. ----------- */
+
+/* "Struct": an object that searches for, and if necessary creates, 
+a template (above).  Other objects in the canvas then can give drawing
+instructions for the template.  The template doesn't go away when the
+"struct" is deleted, so that you can replace it with
+another one to add new fields, for example. */
+
+static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
+{
+    t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+    t_template *t = template_findbyname(sym);
+    int i;
+    t_symbol *sx = gensym("x");
+    x->x_owner = canvas_getcurrent();
+    x->x_next = 0;
+    x->x_sym = sym;
+    x->x_argc = argc;
+    x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
+    for (i = 0; i < argc; i++)
+        x->x_argv[i] = argv[i];
+
+        /* already have a template by this name? */
+    if (t)
+    {
+        x->x_template = t;
+            /* if it's already got a "struct" object we
+            just tack this one to the end of the list and leave it
+            there. */
+        if (t->t_list)
+        {
+            t_gtemplate *x2, *x3;
+            for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
+                ;
+            x2->x_next = x;
+            post("template %s: warning: already exists.", sym->s_name);
+        }
+        else
+        {
+                /* if there's none, we just replace the template with
+                our own and conform it. */
+            t_template *y = template_new(&s_, argc, argv);
+            canvas_redrawallfortemplate(t, 2);
+                /* Unless the new template is different from the old one,
+                there's nothing to do.  */
+            if (!template_match(t, y))
+            {
+                    /* conform everyone to the new template */
+                template_conform(t, y);
+                pd_free(&t->t_pdobj);
+                t = template_new(sym, argc, argv);
+            }
+            pd_free(&y->t_pdobj);
+            t->t_list = x;
+            canvas_redrawallfortemplate(t, 1);
+        }
+    }
+    else
+    {
+            /* otherwise make a new one and we're the only struct on it. */
+        x->x_template = t = template_new(sym, argc, argv);
+        t->t_list = x;
+    }
+    outlet_new(&x->x_obj, 0);
+    return (x);
+}
+
+static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *sym = atom_getsymbolarg(0, argc, argv);
+    if (argc >= 1)
+        argc--; argv++;
+    return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
+}
+
+    /* old version (0.34) -- delete 2003 or so */
+static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
+    static int warned;
+    if (!warned)
+    {
+        post("warning -- 'template' (%s) is obsolete; replace with 'struct'",
+            sym->s_name);
+        warned = 1;
+    }
+    return (gtemplate_donew(sym, argc, argv));
+}
+
+t_template *gtemplate_get(t_gtemplate *x)
+{
+    return (x->x_template);
+}
+
+static void gtemplate_free(t_gtemplate *x)
+{
+        /* get off the template's list */
+    t_template *t = x->x_template;
+    t_gtemplate *y;
+    if (x == t->t_list)
+    {
+        canvas_redrawallfortemplate(t, 2);
+        if (x->x_next)
+        {
+                /* if we were first on the list, and there are others on
+                the list, make a new template corresponding to the new
+                first-on-list and replace the existing template with it. */
+            t_template *z = template_new(&s_,
+                x->x_next->x_argc, x->x_next->x_argv);
+            template_conform(t, z);
+            pd_free(&t->t_pdobj);
+            pd_free(&z->t_pdobj);
+            z = template_new(x->x_sym, x->x_next->x_argc, x->x_next->x_argv);
+            z->t_list = x->x_next;
+            for (y = z->t_list; y ; y = y->x_next)
+                y->x_template = z;
+        }
+        else t->t_list = 0;
+        canvas_redrawallfortemplate(t, 1);
+    }
+    else
+    {
+        t_gtemplate *x2, *x3;
+        for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
+        {
+            if (x == x3)
+            {
+                x2->x_next = x3->x_next;
+                break;
+            }
+        }
+    }
+    freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
+}
+
+static void gtemplate_setup(void)
+{
+    gtemplate_class = class_new(gensym("struct"),
+        (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
+        sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
+    class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
+        A_GIMME, 0);
+}
+
+/* ---------------  FIELD DESCRIPTORS ---------------------- */
+
+/* a field descriptor can hold a constant or a variable; if a variable,
+it's the name of a field in the template we belong to.  LATER, we might
+want to cache the offset of the field so we don't have to search for it
+every single time we draw the object.
+*/
+
+struct _fielddesc
+{
+    char fd_type;       /* LATER consider removing this? */
+    char fd_var;
+    union
+    {
+        t_float fd_float;       /* the field is a constant float */
+        t_symbol *fd_symbol;    /* the field is a constant symbol */
+        t_symbol *fd_varsym;    /* the field is variable and this is the name */
+    } fd_un;
+    float fd_v1;        /* min and max values */
+    float fd_v2;
+    float fd_screen1;   /* min and max screen values */
+    float fd_screen2;
+    float fd_quantum;   /* quantization in value */ 
+};
+
+static void fielddesc_setfloat_const(t_fielddesc *fd, float f)
+{
+    fd->fd_type = A_FLOAT;
+    fd->fd_var = 0;
+    fd->fd_un.fd_float = f;
+    fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
+        fd->fd_quantum = 0;
+}
+
+static void fielddesc_setsymbol_const(t_fielddesc *fd, t_symbol *s)
+{
+    fd->fd_type = A_SYMBOL;
+    fd->fd_var = 0;
+    fd->fd_un.fd_symbol = s;
+    fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
+        fd->fd_quantum = 0;
+}
+
+static void fielddesc_setfloat_var(t_fielddesc *fd, t_symbol *s)
+{
+    char *s1, *s2, *s3, strbuf[MAXPDSTRING];
+    int i;
+    fd->fd_type = A_FLOAT;
+    fd->fd_var = 1;
+    if (!(s1 = strchr(s->s_name, '(')) || !(s2 = strchr(s->s_name, ')'))
+        || (s1 > s2))
+    {
+        fd->fd_un.fd_varsym = s;
+        fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
+            fd->fd_quantum = 0;
+    }
+    else
+    {
+        int cpy = s1 - s->s_name, got;
+        if (cpy > MAXPDSTRING-5)
+            cpy = MAXPDSTRING-5;
+        strncpy(strbuf, s->s_name, cpy);
+        strbuf[cpy] = 0;
+        fd->fd_un.fd_varsym = gensym(strbuf);
+        got = sscanf(s1, "(%f:%f)(%f:%f)(%f)",
+            &fd->fd_v1, &fd->fd_v2, &fd->fd_screen1, &fd->fd_screen2,
+                &fd->fd_quantum);
+        if (got < 2)
+            goto fail;
+        if (got == 3 || (got < 4 && strchr(s2, '(')))
+            goto fail;
+        if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '('))
+            goto fail;
+        if (got == 4)
+            fd->fd_quantum = 0;
+        else if (got == 2)
+        {
+            fd->fd_quantum = 0;
+            fd->fd_screen1 = fd->fd_v1;
+            fd->fd_screen2 = fd->fd_v2;
+        }
+        return;
+    fail:
+        post("parse error: %s", s->s_name);
+        fd->fd_v1 = fd->fd_screen1 = fd->fd_v2 = fd->fd_screen2 =
+            fd->fd_quantum = 0;
+    }
+}
+
+#define CLOSED 1
+#define BEZ 2
+#define NOMOUSE 4
+#define A_ARRAY 55      /* LATER decide whether to enshrine this in m_pd.h */
+
+static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
+{
+        if (argc <= 0) fielddesc_setfloat_const(fd, 0);
+        else if (argv->a_type == A_SYMBOL)
+            fielddesc_setfloat_var(fd, argv->a_w.w_symbol);
+        else fielddesc_setfloat_const(fd, argv->a_w.w_float);
+}
+
+static void fielddesc_setsymbolarg(t_fielddesc *fd, int argc, t_atom *argv)
+{
+        if (argc <= 0) fielddesc_setsymbol_const(fd, &s_);
+        else if (argv->a_type == A_SYMBOL)
+        {
+            fd->fd_type = A_SYMBOL;
+            fd->fd_var = 1;
+            fd->fd_un.fd_varsym = argv->a_w.w_symbol;
+            fd->fd_v1 = fd->fd_v2 = fd->fd_screen1 = fd->fd_screen2 =
+                fd->fd_quantum = 0;
+        }
+        else fielddesc_setsymbol_const(fd, &s_);
+}
+
+static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
+{
+        if (argc <= 0) fielddesc_setfloat_const(fd, 0);
+        else if (argv->a_type == A_SYMBOL)
+        {
+            fd->fd_type = A_ARRAY;
+            fd->fd_var = 1;
+            fd->fd_un.fd_varsym = argv->a_w.w_symbol;
+        }
+        else fielddesc_setfloat_const(fd, argv->a_w.w_float);
+}
+
+    /* getting and setting values via fielddescs -- note confusing names;
+    the above are setting up the fielddesc itself. */
+static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
+    t_word *wp, int loud)
+{
+    if (f->fd_type == A_FLOAT)
+    {
+        if (f->fd_var)
+            return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
+        else return (f->fd_un.fd_float);
+    }
+    else
+    {
+        if (loud)
+            error("symbolic data field used as number");
+        return (0);
+    }
+}
+
+    /* convert a variable's value to a screen coordinate via its fielddesc */
+t_float fielddesc_cvttocoord(t_fielddesc *f, float val)
+{
+    float coord, pix, extreme, div;
+    if (f->fd_v2 == f->fd_v1)
+        return (val);
+    div = (f->fd_screen2 - f->fd_screen1)/(f->fd_v2 - f->fd_v1);
+    coord = f->fd_screen1 + (val - f->fd_v1) * div;
+    extreme = (f->fd_screen1 < f->fd_screen2 ?
+        f->fd_screen1 : f->fd_screen2);
+    if (coord < extreme)
+        coord = extreme;
+    extreme = (f->fd_screen1 > f->fd_screen2 ? 
+        f->fd_screen1 : f->fd_screen2);
+    if (coord > extreme)
+        coord = extreme;
+    return (coord);
+}
+
+    /* read a variable via fielddesc and convert to screen coordinate */
+t_float fielddesc_getcoord(t_fielddesc *f, t_template *template,
+    t_word *wp, int loud)
+{
+    if (f->fd_type == A_FLOAT)
+    {
+        if (f->fd_var)
+        {
+            float val = template_getfloat(template,
+                f->fd_un.fd_varsym, wp, loud);
+            return (fielddesc_cvttocoord(f, val));
+        }
+        else return (f->fd_un.fd_float);
+    }
+    else
+    {
+        if (loud)
+            error("symbolic data field used as number");
+        return (0);
+    }
+}
+
+static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
+    t_word *wp, int loud)
+{
+    if (f->fd_type == A_SYMBOL)
+    {
+        if (f->fd_var)
+            return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
+        else return (f->fd_un.fd_symbol);
+    }
+    else
+    {
+        if (loud)
+            error("numeric data field used as symbol");
+        return (&s_);
+    }
+}
+
+    /* convert from a screen coordinate to a variable value */
+float fielddesc_cvtfromcoord(t_fielddesc *f, float coord)
+{
+    float val;
+    if (f->fd_screen2 == f->fd_screen1)
+        val = coord;
+    else
+    {
+        float div = (f->fd_v2 - f->fd_v1)/(f->fd_screen2 - f->fd_screen1);
+        float extreme;
+        val = f->fd_v1 + (coord - f->fd_screen1) * div;
+        if (f->fd_quantum != 0)
+            val = ((int)((val/f->fd_quantum) + 0.5)) *  f->fd_quantum;
+        extreme = (f->fd_v1 < f->fd_v2 ?
+            f->fd_v1 : f->fd_v2);
+        if (val < extreme) val = extreme;
+        extreme = (f->fd_v1 > f->fd_v2 ?
+            f->fd_v1 : f->fd_v2);
+        if (val > extreme) val = extreme;
+    }
+    return (val);
+ }
+
+void fielddesc_setcoord(t_fielddesc *f, t_template *template,
+    t_word *wp, float coord, int loud)
+{
+    if (f->fd_type == A_FLOAT && f->fd_var)
+    {
+        float val = fielddesc_cvtfromcoord(f, coord);
+        template_setfloat(template,
+                f->fd_un.fd_varsym, wp, val, loud);
+    }
+    else
+    {
+        if (loud)
+            error("attempt to set constant or symbolic data field to a number");
+    }
+}
+
+/* ---------------- curves and polygons (joined segments) ---------------- */
+
+/*
+curves belong to templates and describe how the data in the template are to
+be drawn.  The coordinates of the curve (and other display features) can
+be attached to fields in the template.
+*/
+
+t_class *curve_class;
+
+typedef struct _curve
+{
+    t_object x_obj;
+    int x_flags;            /* CLOSED and/or BEZ and/or NOMOUSE */
+    t_fielddesc x_fillcolor;
+    t_fielddesc x_outlinecolor;
+    t_fielddesc x_width;
+    t_fielddesc x_vis;
+    int x_npoints;
+    t_fielddesc *x_vec;
+    t_canvas *x_canvas;
+} t_curve;
+
+static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+    t_curve *x = (t_curve *)pd_new(curve_class);
+    char *classname = classsym->s_name;
+    int flags = 0;
+    int nxy, i;
+    t_fielddesc *fd;
+    x->x_canvas = canvas_getcurrent();
+    if (classname[0] == 'f')
+    {
+        classname += 6;
+        flags |= CLOSED;
+    }
+    else classname += 4;
+    if (classname[0] == 'c') flags |= BEZ;
+    fielddesc_setfloat_const(&x->x_vis, 1);
+    while (1)
+    {
+        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(firstarg->s_name, "-x"))
+        {
+            flags |= NOMOUSE;
+            argc -= 1; argv += 1;
+        }
+        else break;
+    }
+    x->x_flags = flags;
+    if ((flags & CLOSED) && argc)
+        fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_fillcolor, 0); 
+    if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_outlinecolor, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_width, 1);
+    if (argc < 0) argc = 0;
+    nxy =  (argc + (argc & 1));
+    x->x_npoints = (nxy>>1);
+    x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
+    for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
+        fielddesc_setfloatarg(fd, 1, argv);
+    if (argc & 1) fielddesc_setfloat_const(fd, 0);
+
+    return (x);
+}
+
+void curve_float(t_curve *x, t_floatarg f)
+{
+    int viswas;
+    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
+    {
+        pd_error(x, "global vis/invis for a template with variable visibility");
+        return;
+    }
+    viswas = (x->x_vis.fd_un.fd_float != 0);
+    
+    if ((f != 0 && viswas) || (f == 0 && !viswas))
+        return;
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
+    fielddesc_setfloat_const(&x->x_vis, (f != 0));
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
+}
+
+/* -------------------- widget behavior for curve ------------ */
+
+static void curve_getrect(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_curve *x = (t_curve *)z;
+    int i, n = x->x_npoints;
+    t_fielddesc *f = x->x_vec;
+    int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
+    if (!fielddesc_getfloat(&x->x_vis, template, data, 0) ||
+        (x->x_flags & NOMOUSE))
+    {
+        *xp1 = *yp1 = 0x7fffffff;
+        *xp2 = *yp2 = -0x7fffffff;
+        return;
+    }
+    for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+    {
+        int xloc = glist_xtopixels(glist,
+            basex + fielddesc_getcoord(f, template, data, 0));
+        int yloc = glist_ytopixels(glist,
+            basey + fielddesc_getcoord(f+1, template, data, 0));
+        if (xloc < x1) x1 = xloc;
+        if (xloc > x2) x2 = xloc;
+        if (yloc < y1) y1 = yloc;
+        if (yloc > y2) y2 = yloc;
+    }
+    *xp1 = x1;
+    *yp1 = y1;
+    *xp2 = x2;
+    *yp2 = y2; 
+}
+
+static void curve_displace(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int dx, int dy)
+{
+    /* refuse */
+}
+
+static void curve_select(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+    /* fill in later */
+}
+
+static void curve_activate(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+    /* fill in later */
+}
+
+#if 0
+static int rangecolor(int n)    /* 0 to 9 in 5 steps */
+{
+    int n2 = n/2;               /* 0 to 4 */
+    int ret = (n2 << 6);        /* 0 to 256 in 5 steps */
+    if (ret > 255) ret = 255;
+    return (ret);
+}
+#endif
+
+static int rangecolor(int n)    /* 0 to 9 in 5 steps */
+{
+    int n2 = (n == 9 ? 8 : n);               /* 0 to 8 */
+    int ret = (n2 << 5);        /* 0 to 256 in 9 steps */
+    if (ret > 255) ret = 255;
+    return (ret);
+}
+
+static void numbertocolor(int n, char *s)
+{
+    int red, blue, green;
+    if (n < 0) n = 0;
+    red = n / 100;
+    blue = ((n / 10) % 10);
+    green = n % 10;
+    sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
+        rangecolor(green));
+}
+
+static void curve_vis(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, float basex, float basey,
+    int vis)
+{
+    t_curve *x = (t_curve *)z;
+    int i, n = x->x_npoints;
+    t_fielddesc *f = x->x_vec;
+    
+        /* see comment in plot_vis() */
+    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
+        return;
+    if (vis)
+    {
+        if (n > 1)
+        {
+            int flags = x->x_flags, closed = (flags & CLOSED);
+            float width = fielddesc_getfloat(&x->x_width, template, data, 1);
+            char outline[20], fill[20];
+            int pix[200];
+            if (n > 100)
+                n = 100;
+                /* calculate the pixel values before we start printing
+                out the TK message so that "error" printout won't be
+                interspersed with it.  Only show up to 100 points so we don't
+                have to allocate memory here. */
+            for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+            {
+                pix[2*i] = glist_xtopixels(glist,
+                    basex + fielddesc_getcoord(f, template, data, 1));
+                pix[2*i+1] = glist_ytopixels(glist,
+                    basey + fielddesc_getcoord(f+1, template, data, 1));
+            }
+            if (width < 1) width = 1;
+            numbertocolor(
+                fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
+                outline);
+            if (flags & CLOSED)
+            {
+                numbertocolor(
+                    fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
+                    fill);
+                sys_vgui(".x%lx.c create polygon\\\n",
+                    glist_getcanvas(glist));
+            }
+            else sys_vgui(".x%lx.c create line\\\n", glist_getcanvas(glist));
+            for (i = 0; i < n; i++)
+                sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]);
+            sys_vgui("-width %f\\\n", width);
+            if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
+                fill, outline);
+            else sys_vgui("-fill %s\\\n", outline);
+            if (flags & BEZ) sys_vgui("-smooth 1\\\n");
+            sys_vgui("-tags curve%lx\n", data);
+        }
+        else post("warning: curves need at least two points to be graphed");
+    }
+    else
+    {
+        if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n",
+            glist_getcanvas(glist), data);      
+    }
+}
+
+static int curve_motion_field;
+static float curve_motion_xcumulative;
+static float curve_motion_xbase;
+static float curve_motion_xper;
+static float curve_motion_ycumulative;
+static float curve_motion_ybase;
+static float curve_motion_yper;
+static t_glist *curve_motion_glist;
+static t_scalar *curve_motion_scalar;
+static t_array *curve_motion_array;
+static t_word *curve_motion_wp;
+static t_template *curve_motion_template;
+static t_gpointer curve_motion_gpointer;
+
+    /* LATER protect against the template changing or the scalar disappearing
+    probably by attaching a gpointer here ... */
+
+static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+    t_curve *x = (t_curve *)z;
+    t_fielddesc *f = x->x_vec + curve_motion_field;
+    t_atom at;
+    if (!gpointer_check(&curve_motion_gpointer, 0))
+    {
+        post("curve_motion: scalar disappeared");
+        return;
+    }
+    curve_motion_xcumulative += dx;
+    curve_motion_ycumulative += dy;
+    if (f->fd_var && (dx != 0))
+    {
+        fielddesc_setcoord(f, curve_motion_template, curve_motion_wp,
+            curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
+                1); 
+    }
+    if ((f+1)->fd_var && (dy != 0))
+    {
+        fielddesc_setcoord(f+1, curve_motion_template, curve_motion_wp,
+            curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
+                1); 
+    }
+        /* LATER figure out what to do to notify for an array? */
+    if (curve_motion_scalar)
+        template_notifyforscalar(curve_motion_template, curve_motion_glist, 
+            curve_motion_scalar, gensym("change"), 1, &at);
+    if (curve_motion_scalar)
+        scalar_redraw(curve_motion_scalar, curve_motion_glist);
+    if (curve_motion_array)
+        array_redraw(curve_motion_array, curve_motion_glist);
+}
+
+static int curve_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    float basex, float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_curve *x = (t_curve *)z;
+    int i, n = x->x_npoints;
+    int bestn = -1;
+    int besterror = 0x7fffffff;
+    t_fielddesc *f;
+    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
+        return (0);
+    for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+    {
+        int xval = fielddesc_getcoord(f, template, data, 0),
+            xloc = glist_xtopixels(glist, basex + xval);
+        int yval = fielddesc_getcoord(f+1, template, data, 0),
+            yloc = glist_ytopixels(glist, basey + yval);
+        int xerr = xloc - xpix, yerr = yloc - ypix;
+        if (!f->fd_var && !(f+1)->fd_var)
+            continue;
+        if (xerr < 0)
+            xerr = -xerr;
+        if (yerr < 0)
+            yerr = -yerr;
+        if (yerr > xerr)
+            xerr = yerr;
+        if (xerr < besterror)
+        {
+            curve_motion_xbase = xval;
+            curve_motion_ybase = yval;
+            besterror = xerr;
+            bestn = i;
+        }
+    }
+    if (besterror > 6)
+        return (0);
+    if (doit)
+    {
+        curve_motion_xper = glist_pixelstox(glist, 1)
+            - glist_pixelstox(glist, 0);
+        curve_motion_yper = glist_pixelstoy(glist, 1)
+            - glist_pixelstoy(glist, 0);
+        curve_motion_xcumulative = 0;
+        curve_motion_ycumulative = 0;
+        curve_motion_glist = glist;
+        curve_motion_scalar = sc;
+        curve_motion_array = ap;
+        curve_motion_wp = data;
+        curve_motion_field = 2*bestn;
+        curve_motion_template = template;
+        if (curve_motion_scalar)
+            gpointer_setglist(&curve_motion_gpointer, curve_motion_glist,
+                curve_motion_scalar);
+        else gpointer_setarray(&curve_motion_gpointer,
+                curve_motion_array, curve_motion_wp);
+        glist_grab(glist, z, curve_motion, 0, xpix, ypix);
+    }
+    return (1);
+}
+
+t_parentwidgetbehavior curve_widgetbehavior =
+{
+    curve_getrect,
+    curve_displace,
+    curve_select,
+    curve_activate,
+    curve_vis,
+    curve_click,
+};
+
+static void curve_free(t_curve *x)
+{
+    t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
+}
+
+static void curve_setup(void)
+{
+    curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
+        (t_method)curve_free, sizeof(t_curve), 0, A_GIMME, 0);
+    class_setdrawcommand(curve_class);
+    class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
+        A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
+        A_GIMME, 0);
+    class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
+        A_GIMME, 0);
+    class_setparentwidget(curve_class, &curve_widgetbehavior);
+    class_addfloat(curve_class, curve_float);
+}
+
+/* --------- plots for showing arrays --------------- */
+
+t_class *plot_class;
+
+typedef struct _plot
+{
+    t_object x_obj;
+    t_canvas *x_canvas;
+    t_fielddesc x_outlinecolor;
+    t_fielddesc x_width;
+    t_fielddesc x_xloc;
+    t_fielddesc x_yloc;
+    t_fielddesc x_xinc;
+    t_fielddesc x_style;
+    t_fielddesc x_data;
+    t_fielddesc x_xpoints;
+    t_fielddesc x_ypoints;
+    t_fielddesc x_wpoints;
+    t_fielddesc x_vis;          /* visible */
+    t_fielddesc x_scalarvis;    /* true if drawing the scalar at each point */
+} t_plot;
+
+static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+    t_plot *x = (t_plot *)pd_new(plot_class);
+    int defstyle = PLOTSTYLE_POLY;
+    x->x_canvas = canvas_getcurrent();
+
+    fielddesc_setfloat_var(&x->x_xpoints, gensym("x"));
+    fielddesc_setfloat_var(&x->x_ypoints, gensym("y"));
+    fielddesc_setfloat_var(&x->x_wpoints, gensym("w"));
+    
+    fielddesc_setfloat_const(&x->x_vis, 1);
+    fielddesc_setfloat_const(&x->x_scalarvis, 1);
+    while (1)
+    {
+        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+        if (!strcmp(firstarg->s_name, "curve") ||
+            !strcmp(firstarg->s_name, "-c"))
+        {
+            defstyle = PLOTSTYLE_BEZ;
+            argc--, argv++;
+        }
+        else if (!strcmp(firstarg->s_name, "-v") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(firstarg->s_name, "-vs") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_scalarvis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(firstarg->s_name, "-x") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_xpoints, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(firstarg->s_name, "-y") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_ypoints, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(firstarg->s_name, "-w") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_wpoints, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else break;
+    }
+    if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_data, 1);
+    if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_outlinecolor, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_width, 1);
+    if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_xloc, 1);
+    if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_yloc, 1);
+    if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_xinc, 1);
+    if (argc) fielddesc_setfloatarg(&x->x_style, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_style, defstyle);
+    return (x);
+}
+
+void plot_float(t_plot *x, t_floatarg f)
+{
+    int viswas;
+    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
+    {
+        pd_error(x, "global vis/invis for a template with variable visibility");
+        return;
+    }
+    viswas = (x->x_vis.fd_un.fd_float != 0);
+    
+    if ((f != 0 && viswas) || (f == 0 && !viswas))
+        return;
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
+    fielddesc_setfloat_const(&x->x_vis, (f != 0));
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
+}
+
+/* -------------------- widget behavior for plot ------------ */
+
+
+    /* get everything we'll need from the owner template of the array being
+    plotted. Not used for garrays, but see below */
+static int plot_readownertemplate(t_plot *x,
+    t_word *data, t_template *ownertemplate, 
+    t_symbol **elemtemplatesymp, t_array **arrayp,
+    float *linewidthp, float *xlocp, float *xincp, float *ylocp, float *stylep,
+    float *visp, float *scalarvisp,
+    t_fielddesc **xfield, t_fielddesc **yfield, t_fielddesc **wfield)
+{
+    int arrayonset, type;
+    t_symbol *elemtemplatesym;
+    t_array *array;
+
+        /* find the data and verify it's an array */
+    if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
+    {
+        error("plot: needs an array field");
+        return (-1);
+    }
+    if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
+        &arrayonset, &type, &elemtemplatesym))
+    {
+        error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
+        return (-1);
+    }
+    if (type != DT_ARRAY)
+    {
+        error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
+        return (-1);
+    }
+    array = *(t_array **)(((char *)data) + arrayonset);
+    *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
+    *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
+    *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
+    *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
+    *stylep = fielddesc_getfloat(&x->x_style, ownertemplate, data, 1);
+    *visp = fielddesc_getfloat(&x->x_vis, ownertemplate, data, 1);
+    *scalarvisp = fielddesc_getfloat(&x->x_scalarvis, ownertemplate, data, 1);
+    *elemtemplatesymp = elemtemplatesym;
+    *arrayp = array;
+    *xfield = &x->x_xpoints;
+    *yfield = &x->x_ypoints;
+    *wfield = &x->x_wpoints;
+    return (0);
+}
+
+    /* get everything else you could possibly need about a plot,
+    either for plot's own purposes or for plotting a "garray" */
+int array_getfields(t_symbol *elemtemplatesym,
+    t_canvas **elemtemplatecanvasp,
+    t_template **elemtemplatep, int *elemsizep,
+    t_fielddesc *xfielddesc, t_fielddesc *yfielddesc, t_fielddesc *wfielddesc, 
+    int *xonsetp, int *yonsetp, int *wonsetp)
+{
+    int arrayonset, elemsize, yonset, wonset, xonset, type;
+    t_template *elemtemplate;
+    t_symbol *dummy, *varname;
+    t_canvas *elemtemplatecanvas = 0;
+
+        /* the "float" template is special in not having to have a canvas;
+        template_findbyname is hardwired to return a predefined 
+        template. */
+
+    if (!(elemtemplate =  template_findbyname(elemtemplatesym)))
+    {
+        error("plot: %s: no such template", elemtemplatesym->s_name);
+        return (-1);
+    }
+    if (!((elemtemplatesym == &s_float) ||
+        (elemtemplatecanvas = template_findcanvas(elemtemplate))))
+    {
+        error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
+        return (-1);
+    }
+    elemsize = elemtemplate->t_n * sizeof(t_word);
+    if (yfielddesc && yfielddesc->fd_var)
+        varname = yfielddesc->fd_un.fd_varsym;
+    else varname = gensym("y");
+    if (!template_find_field(elemtemplate, varname, &yonset, &type, &dummy)
+        || type != DT_FLOAT)    
+            yonset = -1;
+    if (xfielddesc && xfielddesc->fd_var)
+        varname = xfielddesc->fd_un.fd_varsym;
+    else varname = gensym("x");
+    if (!template_find_field(elemtemplate, varname, &xonset, &type, &dummy)
+        || type != DT_FLOAT) 
+            xonset = -1;
+    if (wfielddesc && wfielddesc->fd_var)
+        varname = wfielddesc->fd_un.fd_varsym;
+    else varname = gensym("w");
+    if (!template_find_field(elemtemplate, varname, &wonset, &type, &dummy)
+        || type != DT_FLOAT) 
+            wonset = -1;
+
+        /* fill in slots for return values */
+    *elemtemplatecanvasp = elemtemplatecanvas;
+    *elemtemplatep = elemtemplate;
+    *elemsizep = elemsize;
+    *xonsetp = xonset;
+    *yonsetp = yonset;
+    *wonsetp = wonset;
+    return (0);
+}
+
+static void plot_getrect(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_plot *x = (t_plot *)z;
+    int elemsize, yonset, wonset, xonset;
+    t_canvas *elemtemplatecanvas;
+    t_template *elemtemplate;
+    t_symbol *elemtemplatesym;
+    float linewidth, xloc, xinc, yloc, style, xsum, yval, vis, scalarvis;
+    t_array *array;
+    int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
+    int i;
+    float xpix, ypix, wpix;
+    t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
+    if (!plot_readownertemplate(x, data, template, 
+        &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
+            &vis, &scalarvis, &xfielddesc, &yfielddesc, &wfielddesc) &&
+                (vis != 0) &&
+            !array_getfields(elemtemplatesym, &elemtemplatecanvas,
+                &elemtemplate, &elemsize, 
+                xfielddesc, yfielddesc, wfielddesc,
+                &xonset, &yonset, &wonset))
+    {
+            /* if it has more than 2000 points, just check 1000 of them. */
+        int incr = (array->a_n <= 2000 ? 1 : array->a_n / 1000);
+        for (i = 0, xsum = 0; i < array->a_n; i += incr)
+        {
+            float usexloc, useyloc;
+            t_gobj *y;
+                /* get the coords of the point proper */
+            array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
+                xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
+                xfielddesc, yfielddesc, wfielddesc, &xpix, &ypix, &wpix);
+            if (xpix < x1)
+                x1 = xpix;
+            if (xpix > x2)
+                x2 = xpix;
+            if (ypix - wpix < y1)
+                y1 = ypix - wpix;
+            if (ypix + wpix > y2)
+                y2 = ypix + wpix;
+            
+            if (scalarvis != 0)
+            {
+                    /* check also the drawing instructions for the scalar */ 
+                if (xonset >= 0)
+                    usexloc = basex + xloc + fielddesc_cvttocoord(xfielddesc, 
+                        *(float *)(((char *)(array->a_vec) + elemsize * i)
+                            + xonset));
+                else usexloc = basex + xsum, xsum += xinc;
+                if (yonset >= 0)
+                    yval = *(float *)(((char *)(array->a_vec) + elemsize * i)
+                        + yonset);
+                else yval = 0;
+                useyloc = basey + yloc + fielddesc_cvttocoord(yfielddesc, yval);
+                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
+                {
+                    int xx1, xx2, yy1, yy2;
+                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+                    if (!wb) continue;
+                    (*wb->w_parentgetrectfn)(y, glist,
+                        (t_word *)((char *)(array->a_vec) + elemsize * i),
+                            elemtemplate, usexloc, useyloc, 
+                                &xx1, &yy1, &xx2, &yy2);
+                    if (xx1 < x1)
+                        x1 = xx1;
+                    if (yy1 < y1)
+                        y1 = yy1;
+                     if (xx2 > x2)
+                        x2 = xx2;
+                    if (yy2 > y2)
+                        y2 = yy2;   
+                }
+            }
+        }
+    }
+
+    *xp1 = x1;
+    *yp1 = y1;
+    *xp2 = x2;
+    *yp2 = y2;
+}
+
+static void plot_displace(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int dx, int dy)
+{
+        /* not yet */
+}
+
+static void plot_select(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+    /* not yet */
+}
+
+static void plot_activate(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+        /* not yet */
+}
+
+static void plot_vis(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, float basex, float basey,
+    int tovis)
+{
+    t_plot *x = (t_plot *)z;
+    int elemsize, yonset, wonset, xonset, i;
+    t_canvas *elemtemplatecanvas;
+    t_template *elemtemplate;
+    t_symbol *elemtemplatesym;
+    float linewidth, xloc, xinc, yloc, style, usexloc, xsum, yval, vis,
+        scalarvis;
+    t_array *array;
+    int nelem;
+    char *elem;
+    t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
+        /* even if the array is "invisible", if its visibility is
+        set by an instance variable you have to explicitly erase it,
+        because the flag could earlier have been on when we were getting
+        drawn.  Rather than look to try to find out whether we're
+        visible we just do the erasure.  At the TK level this should
+        cause no action because the tag matches nobody.  LATER we
+        might want to optimize this somehow.  Ditto the "vis()" routines
+        for other drawing instructions. */
+        
+    if (plot_readownertemplate(x, data, template, 
+        &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
+        &vis, &scalarvis, &xfielddesc, &yfielddesc, &wfielddesc) ||
+            ((vis == 0) && tovis) /* see above for 'tovis' */
+            || array_getfields(elemtemplatesym, &elemtemplatecanvas,
+                &elemtemplate, &elemsize, xfielddesc, yfielddesc, wfielddesc,
+                &xonset, &yonset, &wonset))
+                    return;
+    nelem = array->a_n;
+    elem = (char *)array->a_vec;
+
+    if (tovis)
+    {
+        if (style == PLOTSTYLE_POINTS)
+        {
+            float minyval = 1e20, maxyval = -1e20;
+            int ndrawn = 0;
+            for (xsum = basex + xloc, i = 0; i < nelem; i++)
+            {
+                float yval, xpix, ypix, nextxloc;
+                int ixpix, inextx;
+
+                if (xonset >= 0)
+                {
+                    usexloc = basex + xloc +
+                        *(float *)((elem + elemsize * i) + xonset);
+                    ixpix = glist_xtopixels(glist, 
+                        fielddesc_cvttocoord(xfielddesc, usexloc));
+                    inextx = ixpix + 2;
+                }
+                else
+                {
+                    usexloc = xsum;
+                    xsum += xinc;
+                    ixpix = glist_xtopixels(glist,
+                        fielddesc_cvttocoord(xfielddesc, usexloc));
+                    inextx = glist_xtopixels(glist,
+                        fielddesc_cvttocoord(xfielddesc, xsum));
+                }
+
+                if (yonset >= 0)
+                    yval = yloc + *(float *)((elem + elemsize * i) + yonset);
+                else yval = 0;
+                if (yval > maxyval)
+                    maxyval = yval;
+                if (yval < minyval)
+                    minyval = yval;
+                if (i == nelem-1 || inextx != ixpix)
+                {
+                    sys_vgui(
+".x%lx.c create rectangle %d %d %d %d -fill black -width 0  -tags plot%lx\n",
+                        glist_getcanvas(glist),
+                        ixpix, (int)glist_ytopixels(glist, 
+                            basey + fielddesc_cvttocoord(yfielddesc, minyval)),
+                        inextx, (int)(glist_ytopixels(glist, 
+                            basey + fielddesc_cvttocoord(yfielddesc, maxyval))
+                                + linewidth), data);
+                    ndrawn++;
+                    minyval = 1e20;
+                    maxyval = -1e20;
+                }
+                if (ndrawn > 2000 || ixpix >= 3000) break;
+            }
+        }
+        else
+        {
+            char outline[20];
+            int lastpixel = -1, ndrawn = 0;
+            float yval = 0, wval = 0, xpix;
+            int ixpix = 0;
+                /* draw the trace */
+            numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template,
+                data, 1), outline);
+            if (wonset >= 0)
+            {
+                    /* found "w" field which controls linewidth.  The trace is
+                    a filled polygon with 2n points. */
+                sys_vgui(".x%lx.c create polygon \\\n",
+                    glist_getcanvas(glist));
+
+                for (i = 0, xsum = xloc; i < nelem; i++)
+                {
+                    if (xonset >= 0)
+                        usexloc = xloc + *(float *)((elem + elemsize * i)
+                            + xonset);
+                    else usexloc = xsum, xsum += xinc;
+                    if (yonset >= 0)
+                        yval = *(float *)((elem + elemsize * i) + yonset);
+                    else yval = 0;
+                    wval = *(float *)((elem + elemsize * i) + wonset);
+                    xpix = glist_xtopixels(glist,
+                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
+                    ixpix = xpix + 0.5;
+                    if (xonset >= 0 || ixpix != lastpixel)
+                    {
+                        sys_vgui("%d %f \\\n", ixpix,
+                            glist_ytopixels(glist,
+                                basey + fielddesc_cvttocoord(yfielddesc, 
+                                    yloc + yval) -
+                                        fielddesc_cvttocoord(wfielddesc,wval)));
+                        ndrawn++;
+                    }
+                    lastpixel = ixpix;
+                    if (ndrawn >= 1000) goto ouch;
+                }
+                lastpixel = -1;
+                for (i = nelem-1; i >= 0; i--)
+                {
+                    float usexloc;
+                    if (xonset >= 0)
+                        usexloc = xloc + *(float *)((elem + elemsize * i)
+                            + xonset);
+                    else xsum -= xinc, usexloc = xsum;
+                    if (yonset >= 0)
+                        yval = *(float *)((elem + elemsize * i) + yonset);
+                    else yval = 0;
+                    wval = *(float *)((elem + elemsize * i) + wonset);
+                    xpix = glist_xtopixels(glist,
+                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
+                    ixpix = xpix + 0.5;
+                    if (xonset >= 0 || ixpix != lastpixel)
+                    {
+                        sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
+                            basey + yloc + fielddesc_cvttocoord(yfielddesc,
+                                yval) +
+                                    fielddesc_cvttocoord(wfielddesc, wval)));
+                        ndrawn++;
+                    }
+                    lastpixel = ixpix;
+                    if (ndrawn >= 1000) goto ouch;
+                }
+                    /* TK will complain if there aren't at least 3 points.
+                    There should be at least two already. */
+                if (ndrawn < 4)
+                {
+                    sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
+                        basey + yloc + fielddesc_cvttocoord(yfielddesc,
+                            yval) +
+                                fielddesc_cvttocoord(wfielddesc, wval)));
+                    sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
+                        basey + yloc + fielddesc_cvttocoord(yfielddesc,
+                            yval) -
+                                fielddesc_cvttocoord(wfielddesc, wval)));
+                }
+            ouch:
+                sys_vgui(" -width 1 -fill %s -outline %s\\\n",
+                    outline, outline);
+                if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
+
+                sys_vgui("-tags plot%lx\n", data);
+            }
+            else if (linewidth > 0)
+            {
+                    /* no "w" field.  If the linewidth is positive, draw a
+                    segmented line with the requested width; otherwise don't
+                    draw the trace at all. */
+                sys_vgui(".x%lx.c create line \\\n", glist_getcanvas(glist));
+
+                for (xsum = xloc, i = 0; i < nelem; i++)
+                {
+                    float usexloc;
+                    if (xonset >= 0)
+                        usexloc = xloc + *(float *)((elem + elemsize * i) +
+                            xonset);
+                    else usexloc = xsum, xsum += xinc;
+                    if (yonset >= 0)
+                        yval = *(float *)((elem + elemsize * i) + yonset);
+                    else yval = 0;
+                    xpix = glist_xtopixels(glist,
+                        basex + fielddesc_cvttocoord(xfielddesc, usexloc));
+                    ixpix = xpix + 0.5;
+                    if (xonset >= 0 || ixpix != lastpixel)
+                    {
+                        sys_vgui("%d %f \\\n", ixpix,
+                            glist_ytopixels(glist,
+                                basey + yloc + fielddesc_cvttocoord(yfielddesc,
+                                    yval)));
+                        ndrawn++;
+                    }
+                    lastpixel = ixpix;
+                    if (ndrawn >= 1000) break;
+                }
+                    /* TK will complain if there aren't at least 2 points... */
+                if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
+                else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
+                    glist_ytopixels(glist, basey + yloc + 
+                        fielddesc_cvttocoord(yfielddesc, yval)));
+
+                sys_vgui("-width %f\\\n", linewidth);
+                sys_vgui("-fill %s\\\n", outline);
+                if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
+
+                sys_vgui("-tags plot%lx\n", data);
+            }
+        }
+            /* We're done with the outline; now draw all the points.
+            This code is inefficient since the template has to be
+            searched for drawing instructions for every last point. */
+        if (scalarvis != 0)
+        {
+            for (xsum = xloc, i = 0; i < nelem; i++)
+            {
+                float usexloc, useyloc;
+                t_gobj *y;
+                if (xonset >= 0)
+                    usexloc = basex + xloc +
+                        *(float *)((elem + elemsize * i) + xonset);
+                else usexloc = basex + xsum, xsum += xinc;
+                if (yonset >= 0)
+                    yval = *(float *)((elem + elemsize * i) + yonset);
+                else yval = 0;
+                useyloc = basey + yloc +
+                    fielddesc_cvttocoord(yfielddesc, yval);
+                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
+                {
+                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+                    if (!wb) continue;
+                    (*wb->w_parentvisfn)(y, glist,
+                        (t_word *)(elem + elemsize * i),
+                            elemtemplate, usexloc, useyloc, tovis);
+                }
+            }
+        }
+    }
+    else
+    {
+            /* un-draw the individual points */
+        if (scalarvis != 0)
+        {
+            int i;
+            for (i = 0; i < nelem; i++)
+            {
+                t_gobj *y;
+                for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
+                {
+                    t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+                    if (!wb) continue;
+                    (*wb->w_parentvisfn)(y, glist,
+                        (t_word *)(elem + elemsize * i), elemtemplate,
+                            0, 0, 0);
+                }
+            }
+        }
+            /* and then the trace */
+        sys_vgui(".x%lx.c delete plot%lx\n",
+            glist_getcanvas(glist), data);      
+    }
+}
+
+static int plot_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    float basex, float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_plot *x = (t_plot *)z;
+    t_symbol *elemtemplatesym;
+    float linewidth, xloc, xinc, yloc, style, vis, scalarvis;
+    t_array *array;
+    t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
+
+    if (!plot_readownertemplate(x, data, template, 
+        &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
+        &vis, &scalarvis,
+        &xfielddesc, &yfielddesc, &wfielddesc) && (vis != 0))
+    {
+        return (array_doclick(array, glist, sc, ap,
+            elemtemplatesym,
+            linewidth, basex + xloc, xinc, basey + yloc, scalarvis,
+            xfielddesc, yfielddesc, wfielddesc,
+            xpix, ypix, shift, alt, dbl, doit));
+    }
+    else return (0);
+}
+
+t_parentwidgetbehavior plot_widgetbehavior =
+{
+    plot_getrect,
+    plot_displace,
+    plot_select,
+    plot_activate,
+    plot_vis,
+    plot_click,
+};
+
+static void plot_setup(void)
+{
+    plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
+        sizeof(t_plot), 0, A_GIMME, 0);
+    class_setdrawcommand(plot_class);
+    class_addfloat(plot_class, plot_float);
+    class_setparentwidget(plot_class, &plot_widgetbehavior);
+}
+
+/* ---------------- drawnumber: draw a number (or symbol) ---------------- */
+
+/*
+    drawnumbers draw numeric fields at controllable locations, with
+    controllable color and label.  invocation:
+    (drawnumber|drawsymbol) [-v <visible>] variable x y color label
+*/
+
+t_class *drawnumber_class;
+
+#define DRAW_SYMBOL 1
+
+typedef struct _drawnumber
+{
+    t_object x_obj;
+    t_fielddesc x_value;
+    t_fielddesc x_xloc;
+    t_fielddesc x_yloc;
+    t_fielddesc x_color;
+    t_fielddesc x_vis;
+    t_symbol *x_label;
+    int x_flags;
+    t_canvas *x_canvas;
+} t_drawnumber;
+
+static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+    t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
+    char *classname = classsym->s_name;
+    int flags = 0;
+    
+    if (classname[4] == 's')
+        flags |= DRAW_SYMBOL;
+    x->x_flags = flags;
+    fielddesc_setfloat_const(&x->x_vis, 1);
+    x->x_canvas = canvas_getcurrent();
+    while (1)
+    {
+        t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+        if (!strcmp(firstarg->s_name, "-v") && argc > 1)
+        {
+            fielddesc_setfloatarg(&x->x_vis, 1, argv+1);
+            argc -= 2; argv += 2;
+        }
+        else break;
+    }
+    if (flags & DRAW_SYMBOL)
+    {
+        if (argc) fielddesc_setsymbolarg(&x->x_value, argc--, argv++);
+        else fielddesc_setsymbol_const(&x->x_value, &s_);
+    }
+    else
+    {
+        if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
+        else fielddesc_setfloat_const(&x->x_value, 0);
+    }
+    if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_xloc, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_yloc, 0);
+    if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
+    else fielddesc_setfloat_const(&x->x_color, 1);
+    if (argc)
+        x->x_label = atom_getsymbolarg(0, argc, argv);
+    else x->x_label = &s_;
+
+    return (x);
+}
+
+void drawnumber_float(t_drawnumber *x, t_floatarg f)
+{
+    int viswas;
+    if (x->x_vis.fd_type != A_FLOAT || x->x_vis.fd_var)
+    {
+        pd_error(x, "global vis/invis for a template with variable visibility");
+        return;
+    }
+    viswas = (x->x_vis.fd_un.fd_float != 0);
+    
+    if ((f != 0 && viswas) || (f == 0 && !viswas))
+        return;
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 2);
+    fielddesc_setfloat_const(&x->x_vis, (f != 0));
+    canvas_redrawallfortemplatecanvas(x->x_canvas, 1);
+}
+
+/* -------------------- widget behavior for drawnumber ------------ */
+
+#define DRAWNUMBER_BUFSIZE 80
+static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
+{
+    int nchars;
+    strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
+    buf[DRAWNUMBER_BUFSIZE - 1] = 0;
+    nchars = strlen(buf);
+    atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
+}
+
+static void drawnumber_getrect(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int *xp1, int *yp1, int *xp2, int *yp2)
+{
+    t_drawnumber *x = (t_drawnumber *)z;
+    t_atom at;
+        int xloc, yloc, font, fontwidth, fontheight;
+    char buf[DRAWNUMBER_BUFSIZE];
+
+    if (!fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        *xp1 = *yp1 = 0x7fffffff;
+        *xp2 = *yp2 = -0x7fffffff;
+        return;
+    }
+    xloc = glist_xtopixels(glist,
+        basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+    yloc = glist_ytopixels(glist,
+        basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+    font = glist_getfont(glist);
+    fontwidth = sys_fontwidth(font);
+        fontheight = sys_fontheight(font);
+    if (x->x_flags & DRAW_SYMBOL)
+        SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+    else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+    drawnumber_sprintf(x, buf, &at);
+    *xp1 = xloc;
+    *yp1 = yloc;
+    *xp2 = xloc + fontwidth * strlen(buf);
+    *yp2 = yloc + fontheight;
+}
+
+static void drawnumber_displace(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int dx, int dy)
+{
+    /* refuse */
+}
+
+static void drawnumber_select(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+    post("drawnumber_select %d", state);
+    /* fill in later */
+}
+
+static void drawnumber_activate(t_gobj *z, t_glist *glist,
+    t_word *data, t_template *template, float basex, float basey,
+    int state)
+{
+    post("drawnumber_activate %d", state);
+}
+
+static void drawnumber_vis(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, float basex, float basey,
+    int vis)
+{
+    t_drawnumber *x = (t_drawnumber *)z;
+    
+        /* see comment in plot_vis() */
+    if (vis && !fielddesc_getfloat(&x->x_vis, template, data, 0))
+        return;
+    if (vis)
+    {
+        t_atom at;
+        int xloc = glist_xtopixels(glist,
+            basex + fielddesc_getcoord(&x->x_xloc, template, data, 0));
+        int yloc = glist_ytopixels(glist,
+            basey + fielddesc_getcoord(&x->x_yloc, template, data, 0));
+        char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
+        numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
+            colorstring);
+        if (x->x_flags & DRAW_SYMBOL)
+            SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+        else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+        drawnumber_sprintf(x, buf, &at);
+        sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
+                glist_getcanvas(glist), xloc, yloc, colorstring, buf);
+        sys_vgui(" -font -*-courier-bold--normal--%d-*",
+            sys_hostfontsize(glist_getfont(glist)));
+        sys_vgui(" -tags drawnumber%lx\n", data);
+    }
+    else sys_vgui(".x%lx.c delete drawnumber%lx\n", glist_getcanvas(glist), data);
+}
+
+static float drawnumber_motion_ycumulative;
+static t_glist *drawnumber_motion_glist;
+static t_scalar *drawnumber_motion_scalar;
+static t_array *drawnumber_motion_array;
+static t_word *drawnumber_motion_wp;
+static t_template *drawnumber_motion_template;
+static t_gpointer drawnumber_motion_gpointer;
+static int drawnumber_motion_symbol;
+static int drawnumber_motion_firstkey;
+
+    /* LATER protect against the template changing or the scalar disappearing
+    probably by attaching a gpointer here ... */
+
+static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+    t_drawnumber *x = (t_drawnumber *)z;
+    t_fielddesc *f = &x->x_value;
+    t_atom at;
+    if (!gpointer_check(&drawnumber_motion_gpointer, 0))
+    {
+        post("drawnumber_motion: scalar disappeared");
+        return;
+    }
+    if (drawnumber_motion_symbol)
+    {
+        post("drawnumber_motion: symbol");
+        return;
+    }
+    drawnumber_motion_ycumulative -= dy;
+    template_setfloat(drawnumber_motion_template,
+        f->fd_un.fd_varsym,
+            drawnumber_motion_wp, 
+            drawnumber_motion_ycumulative,
+                1);
+    if (drawnumber_motion_scalar)
+        template_notifyforscalar(drawnumber_motion_template,
+            drawnumber_motion_glist, drawnumber_motion_scalar,
+                gensym("change"), 1, &at);
+
+    if (drawnumber_motion_scalar)
+        scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist);
+    if (drawnumber_motion_array)
+        array_redraw(drawnumber_motion_array, drawnumber_motion_glist);
+}
+
+static void drawnumber_key(void *z, t_floatarg fkey)
+{
+    t_drawnumber *x = (t_drawnumber *)z;
+    t_fielddesc *f = &x->x_value;
+    int key = fkey;
+    char sbuf[MAXPDSTRING];
+    t_atom at;
+    if (!gpointer_check(&drawnumber_motion_gpointer, 0))
+    {
+        post("drawnumber_motion: scalar disappeared");
+        return;
+    }
+    if (key == 0)
+        return;
+    if (drawnumber_motion_symbol)
+    {
+            /* key entry for a symbol field */
+        if (drawnumber_motion_firstkey)
+            sbuf[0] = 0;
+        else strncpy(sbuf, template_getsymbol(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, 1)->s_name,
+                MAXPDSTRING);
+        sbuf[MAXPDSTRING-1] = 0;
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+    }
+    else
+    {
+            /* key entry for a numeric field.  This is just a stopgap. */
+        float newf;
+        if (drawnumber_motion_firstkey)
+            sbuf[0] = 0;
+        else sprintf(sbuf, "%g", template_getfloat(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, 1));
+        drawnumber_motion_firstkey = (key == '\n');
+        if (key == '\b')
+        {
+            if (*sbuf)
+                sbuf[strlen(sbuf)-1] = 0;
+        }
+        else
+        {
+            sbuf[strlen(sbuf)+1] = 0;
+            sbuf[strlen(sbuf)] = key;
+        }
+        if (sscanf(sbuf, "%g", &newf) < 1)
+            newf = 0;
+        template_setfloat(drawnumber_motion_template,
+            f->fd_un.fd_varsym, drawnumber_motion_wp, newf, 1);
+        if (drawnumber_motion_scalar)
+            template_notifyforscalar(drawnumber_motion_template,
+                drawnumber_motion_glist, drawnumber_motion_scalar,
+                    gensym("change"), 1, &at);
+        if (drawnumber_motion_scalar)
+            scalar_redraw(drawnumber_motion_scalar, drawnumber_motion_glist);
+        if (drawnumber_motion_array)
+            array_redraw(drawnumber_motion_array, drawnumber_motion_glist);
+    }
+}
+
+static int drawnumber_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    float basex, float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    t_drawnumber *x = (t_drawnumber *)z;
+    int x1, y1, x2, y2;
+    drawnumber_getrect(z, glist,
+        data, template, basex, basey,
+        &x1, &y1, &x2, &y2);
+    if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+        && x->x_value.fd_var &&
+            fielddesc_getfloat(&x->x_vis, template, data, 0))
+    {
+        if (doit)
+        {
+            drawnumber_motion_glist = glist;
+            drawnumber_motion_wp = data;
+            drawnumber_motion_template = template;
+            drawnumber_motion_scalar = sc;
+            drawnumber_motion_array = ap;
+            drawnumber_motion_firstkey = 1;
+            drawnumber_motion_ycumulative =
+                fielddesc_getfloat(&x->x_value, template, data, 0);
+            drawnumber_motion_symbol = ((x->x_flags & DRAW_SYMBOL) != 0);
+            if (drawnumber_motion_scalar)
+                gpointer_setglist(&drawnumber_motion_gpointer, 
+                    drawnumber_motion_glist, drawnumber_motion_scalar);
+            else gpointer_setarray(&drawnumber_motion_gpointer,
+                    drawnumber_motion_array, drawnumber_motion_wp);
+           glist_grab(glist, z, drawnumber_motion, drawnumber_key,
+                xpix, ypix);
+        }
+        return (1);
+    }
+    else return (0);
+}
+
+t_parentwidgetbehavior drawnumber_widgetbehavior =
+{
+    drawnumber_getrect,
+    drawnumber_displace,
+    drawnumber_select,
+    drawnumber_activate,
+    drawnumber_vis,
+    drawnumber_click,
+};
+
+static void drawnumber_free(t_drawnumber *x)
+{
+}
+
+static void drawnumber_setup(void)
+{
+    drawnumber_class = class_new(gensym("drawnumber"),
+        (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
+        sizeof(t_drawnumber), 0, A_GIMME, 0);
+    class_setdrawcommand(drawnumber_class);
+    class_addfloat(drawnumber_class, drawnumber_float);
+    class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
+        A_GIMME, 0);
+    class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
+}
+
+/* ---------------------- setup function ---------------------------- */
+
+void g_template_setup(void)
+{
+    template_setup();
+    gtemplate_setup();
+    curve_setup();
+    plot_setup();
+    drawnumber_setup();
+}
+
diff --git a/src/g_toggle.c b/src/g_toggle.c
index e36be5fac..c0c36f1ac 100644
--- a/src/g_toggle.c
+++ b/src/g_toggle.c
@@ -61,11 +61,12 @@ void toggle_draw_new(t_toggle *x, t_glist *glist)
              canvas, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w, w,
              (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xx+x->x_gui.x_ldx,
              yy+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
              canvas, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h, x, 0);
@@ -120,8 +121,8 @@ void toggle_draw_config(t_toggle* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%6.6x\n", canvas, x,
@@ -225,7 +226,7 @@ static void toggle_properties(t_gobj *z, t_glist *owner)
     t_symbol *srl[3];
 
     iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s TOGGLE \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |tgl| \
             ----------dimensions(pix):----------- %d %d size: 0 0 empty \
             -----------non-zero-value:----------- %g value: 0.0 empty %g \
             -1 lin log %d %d empty %d \
@@ -407,7 +408,7 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     x->x_nonzero = (nonzero!=0.0)?nonzero:1.0;
     if(x->x_gui.x_isa.x_loadinit)
         x->x_on = (on!=0.0)?nonzero:0.0;
diff --git a/src/g_vdial.c b/src/g_vdial.c
index 3d352b355..80c857f51 100644
--- a/src/g_vdial.c
+++ b/src/g_vdial.c
@@ -75,10 +75,10 @@ void vradio_draw_new(t_vradio *x, t_glist *glist)
         x->x_drawn = x->x_on;
     }
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize,
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
@@ -141,8 +141,8 @@ void vradio_draw_config(t_vradio* x, t_glist* glist)
     t_canvas *canvas=glist_getcanvas(glist);
     int n=x->x_number, i;
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, 
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     for(i=0; i<n; i++)
@@ -265,7 +265,7 @@ static void vradio_properties(t_gobj *z, t_glist *owner)
     iemgui_properties(&x->x_gui, srl);
     if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class)
         hchange = x->x_change;
-    sprintf(buf, "pdtk_iemgui_dialog %%s vradio \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |vradio| \
             ----------dimensions(pix):----------- %d %d size: 0 0 empty \
             empty 0.0 empty 0.0 empty %d \
             %d new-only new&old %d %d number: %d \
@@ -590,7 +590,7 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if(num < 1)
         num = 1;
     if(num > IEM_RADIO_MAX)
diff --git a/src/g_vslider.c b/src/g_vslider.c
index 1b575dac0..a5b9cc860 100644
--- a/src/g_vslider.c
+++ b/src/g_vslider.c
@@ -59,10 +59,11 @@ static void vslider_draw_new(t_vslider *x, t_glist *glist)
              canvas, xpos+1, r,
              xpos + x->x_gui.x_w, r, x->x_gui.x_fcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, 
+			 x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
              canvas,
@@ -122,8 +123,8 @@ static void vslider_draw_config(t_vslider* x,t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, 
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
     sys_vgui(".x%lx.c itemconfigure %lxKNOB -fill #%6.6x\n", canvas,
@@ -277,7 +278,7 @@ static void vslider_properties(t_gobj *z, t_glist *owner)
 
     iemgui_properties(&x->x_gui, srl);
 
-    sprintf(buf, "pdtk_iemgui_dialog %%s VSLIDER \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |vsl| \
             --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
             -----------output-range:----------- %g bottom: %g top: %d \
             %d lin log %d %d empty %d \
@@ -562,7 +563,7 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv)
     if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
     else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
     x->x_gui.x_ldx = ldx;
     x->x_gui.x_ldy = ldy;
diff --git a/src/g_vumeter.c b/src/g_vumeter.c
index ac6ee0ae7..813e63c97 100644
--- a/src/g_vumeter.c
+++ b/src/g_vumeter.c
@@ -116,17 +116,19 @@ static void vu_draw_new(t_vu *x, t_glist *glist)
                  canvas, quad1, yyy, quad3, yyy, x->x_led_size, iemgui_color_hex[led_col], x, i);
         if(((i+2)&3) && (x->x_scale))
             sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-                     -font {%s %d bold} -fill #%6.6x -tags %lxSCALE%d\n",
-                     canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
-                     x->x_gui.x_lcol, x, i);
+                     -font {{%s} %d %s} -fill #%6.6x -tags %lxSCALE%d\n",
+                     canvas, end, yyy+k3, iemgui_vu_scale_str[i], 
+					 x->x_gui.x_font, x->x_gui.x_fontsize,
+                     sys_fontweight, x->x_gui.x_lcol, x, i);
     }
     if(x->x_scale)
     {
         i=IEM_VU_STEPS+1;
         yyy = k4 + k1*(k2-i);
         sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-                 -font {%s %d bold} -fill #%6.6x -tags %lxSCALE%d\n",
-                 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+                 -font {{%s} %d %s} -fill #%6.6x -tags %lxSCALE%d\n",
+                 canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, 
+				 x->x_gui.x_fontsize, sys_fontweight,
                  x->x_gui.x_lcol, x, i);
     }
     sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %lxRCOVER\n",
@@ -136,10 +138,11 @@ static void vu_draw_new(t_vu *x, t_glist *glist)
              canvas, mid, ypos+10,
              mid, ypos+10, x->x_led_size, x->x_gui.x_bcol, x);
     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-             -font {%s %d bold} -fill #%6.6x -tags %lxLABEL\n",
+             -font {{%s} %d %s} -fill #%6.6x -tags %lxLABEL\n",
              canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
-             x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+             x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+			 x->x_gui.x_lcol, x);
     if(!x->x_gui.x_fsf.x_snd_able)
     {
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxOUT%d\n",
@@ -274,19 +277,21 @@ static void vu_draw_config(t_vu* x, t_glist* glist)
         sys_vgui(".x%lx.c itemconfigure %lxRLED%d -width %d\n", canvas, x, i,
                  x->x_led_size);
         if(((i+2)&3) && (x->x_scale))
-            sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
-                     canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+            sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {{%s} %d %s} -fill #%6.6x\n",
+                     canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, 
+					 x->x_gui.x_fontsize, sys_fontweight, 
                      x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
     }
     if(x->x_scale)
     {
         i=IEM_VU_STEPS+1;
-        sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
-                 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+        sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {{%s} %d %s} -fill #%6.6x\n",
+                 canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, 
+				 x->x_gui.x_fontsize, sys_fontweight,
                  x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
     }
-    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
-             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+    sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} %d %s} -fill #%6.6x -text {%s} \n",
+             canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
              x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
              strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
 
@@ -476,16 +481,18 @@ static void vu_scale(t_vu *x, t_floatarg fscale)
                 yyy = k4 + k1*(k2-i);
                 if((i+2)&3)
                     sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-                             -font {%s %d bold} -fill #%6.6x -tags %lxSCALE%d\n",
-                             canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
-                             x->x_gui.x_lcol, x, i);
+                             -font {{%s} %d %s} -fill #%6.6x -tags %lxSCALE%d\n",
+                             canvas, end, yyy+k3, iemgui_vu_scale_str[i], 
+							 x->x_gui.x_font, x->x_gui.x_fontsize,
+                             sys_fontweight, x->x_gui.x_lcol, x, i);
             }
             i=IEM_VU_STEPS+1;
             yyy = k4 + k1*(k2-i);
             sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-                     -font {%s %d bold} -fill #%6.6x -tags %lxSCALE%d\n",
-                     canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
-                     x->x_gui.x_lcol, x, i);
+                     -font {{%s} %d %s} -fill #%6.6x -tags %lxSCALE%d\n",
+                     canvas, end, yyy+k3, iemgui_vu_scale_str[i], 
+					 x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
+                     sys_fontweight, x->x_gui.x_lcol, x, i);
         }
     }
 }
@@ -497,7 +504,7 @@ static void vu_properties(t_gobj *z, t_glist *owner)
     t_symbol *srl[3];
 
     iemgui_properties(&x->x_gui, srl);
-    sprintf(buf, "pdtk_iemgui_dialog %%s VU-METER \
+    sprintf(buf, "pdtk_iemgui_dialog %%s |vu| \
             --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
             empty 0.0 empty 0.0 empty %d \
             %d no_scale scale %d %d empty %d \
@@ -627,7 +634,7 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv)
     t_vu *x = (t_vu *)pd_new(vu_class);
     int bflcol[]={-66577, -1, -1};
     int w=IEM_GUI_DEFAULTSIZE, h=IEM_VU_STEPS*IEM_VU_DEFAULTSIZE;
-    int ldx=-1, ldy=-8, f=0, fs=8, scale=1;
+    int ldx=-1, ldy=-8, f=0, fs=10, scale=1;
     int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
     char str[144];
 
@@ -667,7 +674,7 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv)
     else if(x->x_gui.x_fsf.x_font_style == 2)
         strcpy(x->x_gui.x_font, "times");
     else { x->x_gui.x_fsf.x_font_style = 0;
-        strcpy(x->x_gui.x_font, "courier"); }
+        strcpy(x->x_gui.x_font, sys_font); }
     if(x->x_gui.x_fsf.x_rcv_able)
         pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
     x->x_gui.x_ldx = ldx;
diff --git a/src/m_pd.h b/src/m_pd.h
index 5460c517c..9ecc559a3 100644
--- a/src/m_pd.h
+++ b/src/m_pd.h
@@ -368,6 +368,8 @@ EXTERN t_glist *canvas_getcurrent(void);
 EXTERN void canvas_makefilename(t_glist *c, char *file,
     char *result,int resultsize);
 EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN char sys_font[]; /* default typeface set in s_main.c */
+EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */
 EXTERN int sys_fontwidth(int fontsize);
 EXTERN int sys_fontheight(int fontsize);
 EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
diff --git a/src/makefile.in b/src/makefile.in
index d77d4ac4d..c019c078f 100644
--- a/src/makefile.in
+++ b/src/makefile.in
@@ -170,12 +170,12 @@ install:  all
 	for dir in $(shell ls -1 ../doc | grep -v CVS); do \
 		echo "installing $$dir"; \
 		install -d $(pddocdir)/$$dir ; \
-		install -p ../doc/$$dir/*.* $(pddocdir)/$$dir ; \
+		install -m644 -p ../doc/$$dir/*.* $(pddocdir)/$$dir ; \
 	done
 	for dir in $(shell ls -1 ../doc/7.stuff | grep -v CVS); do \
 		echo "installing 7.stuff/$$dir"; \
 		install -d $(pddocdir)/7.stuff/$$dir ; \
-		install -p ../doc/7.stuff/$$dir/*.* $(pddocdir)/7.stuff/$$dir ; \
+		install -m644 -p ../doc/7.stuff/$$dir/*.* $(pddocdir)/7.stuff/$$dir ; \
 	done
 	mv $(ABOUT_FILE) $(ABOUT_FILE).tmp
 	cat $(ABOUT_FILE).tmp | sed 's|PD_VERSION|Pd version $(PD_VERSION)|' \
diff --git a/src/s_inter.c b/src/s_inter.c
index 9945466f1..bbfaf23f3 100644
--- a/src/s_inter.c
+++ b/src/s_inter.c
@@ -90,7 +90,6 @@ struct _socketreceiver
 
 extern char *pd_version;
 extern int sys_guisetportnumber;
-extern char sys_font[]; /* tb: typeface */
 
 static int sys_nfdpoll;
 static t_fdpoll *sys_fdpoll;
@@ -849,7 +848,8 @@ void glob_watchdog(t_pd *dummy)
 
 #define FIRSTPORTNUM 5400
 
-static int defaultfontshit[] = {
+#define MAXFONTS 21
+static int defaultfontshit[MAXFONTS] = {
     8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
         24, 15, 28};
 #define NDEFAULTFONT (sizeof(defaultfontshit)/sizeof(*defaultfontshit))
@@ -1257,8 +1257,8 @@ int sys_startgui(const char *guidir)
 #endif
          sys_get_audio_apis(buf);
          sys_get_midi_apis(buf2);
-         sys_vgui("pdtk_pd_startup {%s} %s %s {%s}\n", pd_version, buf, buf2,
-                                  sys_font); 
+         sys_vgui("pdtk_pd_startup {%s} %s %s {%s} %s\n", pd_version, buf, buf2, 
+				  sys_font, sys_fontweight); 
     }
     return (0);
 
diff --git a/src/s_inter.c.orig b/src/s_inter.c.orig
new file mode 100644
index 000000000..9945466f1
--- /dev/null
+++ b/src/s_inter.c.orig
@@ -0,0 +1,1300 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+/* Pd side of the Pd/Pd-gui interface.  Also, some system interface routines
+that didn't really belong anywhere. */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_imp.h"
+#include "g_canvas.h"   /* for GUI queueing stuff */
+#ifndef MSW
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <winsock.h>
+#include <windows.h>
+# ifdef _MSC_VER
+typedef int pid_t;
+# endif
+typedef int socklen_t;
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#else
+#include <stdlib.h>
+#endif
+
+#define DEBUG_MESSUP 1      /* messages up from pd to pd-gui */
+#define DEBUG_MESSDOWN 2    /* messages down from pd-gui to pd */
+
+#ifndef PDBINDIR
+#define PDBINDIR "bin/"
+#endif
+
+#ifndef WISHAPP
+#define WISHAPP "wish84.exe"
+#endif
+
+#ifdef __linux__
+#define LOCALHOST "127.0.0.1"
+#else
+#define LOCALHOST "localhost"
+#endif
+
+typedef struct _fdpoll
+{
+    int fdp_fd;
+    t_fdpollfn fdp_fn;
+    void *fdp_ptr;
+} t_fdpoll;
+
+#define INBUFSIZE 4096
+
+struct _socketreceiver
+{
+    char *sr_inbuf;
+    int sr_inhead;
+    int sr_intail;
+    void *sr_owner;
+    int sr_udp;
+    t_socketnotifier sr_notifier;
+    t_socketreceivefn sr_socketreceivefn;
+};
+
+extern char *pd_version;
+extern int sys_guisetportnumber;
+extern char sys_font[]; /* tb: typeface */
+
+static int sys_nfdpoll;
+static t_fdpoll *sys_fdpoll;
+static int sys_maxfd;
+static int sys_guisock;
+
+static t_binbuf *inbinbuf;
+static t_socketreceiver *sys_socketreceiver;
+extern int sys_addhist(int phase);
+
+/* ----------- functions for timing, signals, priorities, etc  --------- */
+
+#ifdef MSW
+static LARGE_INTEGER nt_inittime;
+static double nt_freq = 0;
+
+static void sys_initntclock(void)
+{
+    LARGE_INTEGER f1;
+    LARGE_INTEGER now;
+    QueryPerformanceCounter(&now);
+    if (!QueryPerformanceFrequency(&f1))
+    {
+          fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
+          f1.QuadPart = 1;
+    }
+    nt_freq = f1.QuadPart;
+    nt_inittime = now;
+}
+
+#if 0
+    /* this is a version you can call if you did the QueryPerformanceCounter
+    call yourself.  Necessary for time tagging incoming MIDI at interrupt
+    level, for instance; but we're not doing that just now. */
+
+double nt_tixtotime(LARGE_INTEGER *dumbass)
+{
+    if (nt_freq == 0) sys_initntclock();
+    return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
+}
+#endif
+#endif /* MSW */
+
+    /* get "real time" in seconds; take the
+    first time we get called as a reference time of zero. */
+double sys_getrealtime(void)    
+{
+#ifndef MSW
+    static struct timeval then;
+    struct timeval now;
+    gettimeofday(&now, 0);
+    if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
+    return ((now.tv_sec - then.tv_sec) +
+        (1./1000000.) * (now.tv_usec - then.tv_usec));
+#else
+    LARGE_INTEGER now;
+    QueryPerformanceCounter(&now);
+    if (nt_freq == 0) sys_initntclock();
+    return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
+#endif
+}
+
+extern int sys_nosleep;
+
+static int sys_domicrosleep(int microsec, int pollem)
+{
+    struct timeval timout;
+    int i, didsomething = 0;
+    t_fdpoll *fp;
+    timout.tv_sec = 0;
+    timout.tv_usec = (sys_nosleep ? 0 : microsec);
+    if (pollem)
+    {
+        fd_set readset, writeset, exceptset;
+        FD_ZERO(&writeset);
+        FD_ZERO(&readset);
+        FD_ZERO(&exceptset);
+        for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++)
+            FD_SET(fp->fdp_fd, &readset);
+#ifdef MSW
+        if (sys_maxfd == 0)
+                Sleep(microsec/1000);
+        else
+#endif
+        select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
+        for (i = 0; i < sys_nfdpoll; i++)
+            if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
+        {
+#ifdef THREAD_LOCKING
+            sys_lock();
+#endif
+            (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
+#ifdef THREAD_LOCKING
+            sys_unlock();
+#endif
+            didsomething = 1;
+        }
+        return (didsomething);
+    }
+    else
+    {
+#ifdef MSW
+        if (sys_maxfd == 0)
+              Sleep(microsec/1000);
+        else
+#endif
+        select(0, 0, 0, 0, &timout);
+        return (0);
+    }
+}
+
+void sys_microsleep(int microsec)
+{
+    sys_domicrosleep(microsec, 1);
+}
+
+#ifdef UNISTD
+typedef void (*sighandler_t)(int);
+
+static void sys_signal(int signo, sighandler_t sigfun)
+{
+    struct sigaction action;
+    action.sa_flags = 0;
+    action.sa_handler = sigfun;
+    memset(&action.sa_mask, 0, sizeof(action.sa_mask));
+#if 0  /* GG says: don't use that */
+    action.sa_restorer = 0;
+#endif
+    if (sigaction(signo, &action, 0) < 0)
+        perror("sigaction");
+}
+
+static void sys_exithandler(int n)
+{
+    static int trouble = 0;
+    if (!trouble)
+    {
+        trouble = 1;
+        fprintf(stderr, "Pd: signal %d\n", n);
+        sys_bail(1);
+    }
+    else _exit(1);
+}
+
+static void sys_alarmhandler(int n)
+{
+    fprintf(stderr, "Pd: system call timed out\n");
+}
+
+static void sys_huphandler(int n)
+{
+    struct timeval timout;
+    timout.tv_sec = 0;
+    timout.tv_usec = 30000;
+    select(1, 0, 0, 0, &timout);
+}
+
+void sys_setalarm(int microsec)
+{
+    struct itimerval gonzo;
+#if 0
+    fprintf(stderr, "timer %d\n", microsec);
+#endif
+    gonzo.it_interval.tv_sec = 0;
+    gonzo.it_interval.tv_usec = 0;
+    gonzo.it_value.tv_sec = 0;
+    gonzo.it_value.tv_usec = microsec;
+    if (microsec)
+        sys_signal(SIGALRM, sys_alarmhandler);
+    else sys_signal(SIGALRM, SIG_IGN);
+    setitimer(ITIMER_REAL, &gonzo, 0);
+}
+
+#endif
+
+#ifdef __linux
+
+#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
+#include <sched.h>
+#endif
+
+void sys_set_priority(int higher) 
+{
+#ifdef _POSIX_PRIORITY_SCHEDULING
+    struct sched_param par;
+    int p1 ,p2, p3;
+    p1 = sched_get_priority_min(SCHED_FIFO);
+    p2 = sched_get_priority_max(SCHED_FIFO);
+#ifdef USEAPI_JACK    
+    p3 = (higher ? p1 + 7 : p1 + 5);
+#else
+    p3 = (higher ? p2 - 1 : p2 - 3);
+#endif
+    par.sched_priority = p3;
+    if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+       fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+
+#ifdef REALLY_POSIX_MEMLOCK /* this doesn't work on Fedora 4, for example. */
+#ifdef _POSIX_MEMLOCK
+    /* tb: force memlock to physical memory { */
+    {
+        struct rlimit mlock_limit;
+        mlock_limit.rlim_cur=0;
+        mlock_limit.rlim_max=0;
+        setrlimit(RLIMIT_MEMLOCK,&mlock_limit);
+    }
+    /* } tb */
+    if (mlockall(MCL_FUTURE) != -1) 
+        fprintf(stderr, "memory locking enabled.\n");
+#endif
+#endif
+}
+
+#endif /* __linux__ */
+
+#ifdef IRIX             /* hack by <olaf.matthes@gmx.de> at 2003/09/21 */
+
+#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
+#include <sched.h>
+#endif
+
+void sys_set_priority(int higher)
+{
+#ifdef _POSIX_PRIORITY_SCHEDULING
+    struct sched_param par;
+        /* Bearing the table found in 'man realtime' in mind, I found it a */
+        /* good idea to use 192 as the priority setting for Pd. Any thoughts? */
+    if (higher)
+                par.sched_priority = 250;       /* priority for watchdog */
+    else
+                par.sched_priority = 192;       /* priority for pd (DSP) */
+
+    if (sched_setscheduler(0, SCHED_FIFO, &par) != -1)
+        fprintf(stderr, "priority %d scheduling enabled.\n", par.sched_priority);
+#endif
+
+#ifdef _POSIX_MEMLOCK
+    if (mlockall(MCL_FUTURE) != -1) 
+        fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+/* end of hack */
+#endif /* IRIX */
+
+/* ------------------ receiving incoming messages over sockets ------------- */
+
+void sys_sockerror(char *s)
+{
+#ifdef MSW
+    int err = WSAGetLastError();
+    if (err == 10054) return;
+    else if (err == 10044)
+    {
+        fprintf(stderr,
+            "Warning: you might not have TCP/IP \"networking\" turned on\n");
+        fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
+    }
+#else
+    int err = errno;
+#endif
+    fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
+{
+    int nfd = sys_nfdpoll;
+    int size = nfd * sizeof(t_fdpoll);
+    t_fdpoll *fp;
+    sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
+        size + sizeof(t_fdpoll));
+    fp = sys_fdpoll + nfd;
+    fp->fdp_fd = fd;
+    fp->fdp_fn = fn;
+    fp->fdp_ptr = ptr;
+    sys_nfdpoll = nfd + 1;
+    if (fd >= sys_maxfd) sys_maxfd = fd + 1;
+}
+
+void sys_rmpollfn(int fd)
+{
+    int nfd = sys_nfdpoll;
+    int i, size = nfd * sizeof(t_fdpoll);
+    t_fdpoll *fp;
+    for (i = nfd, fp = sys_fdpoll; i--; fp++)
+    {
+        if (fp->fdp_fd == fd)
+        {
+            while (i--)
+            {
+                fp[0] = fp[1];
+                fp++;
+            }
+            sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
+                size - sizeof(t_fdpoll));
+            sys_nfdpoll = nfd - 1;
+            return;
+        }
+    }
+    post("warning: %d removed from poll list but not found", fd);
+}
+
+t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier,
+    t_socketreceivefn socketreceivefn, int udp)
+{
+    t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
+    x->sr_inhead = x->sr_intail = 0;
+    x->sr_owner = owner;
+    x->sr_notifier = notifier;
+    x->sr_socketreceivefn = socketreceivefn;
+    x->sr_udp = udp;
+    if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_socketreceiver");;
+    return (x);
+}
+
+void socketreceiver_free(t_socketreceiver *x)
+{
+    free(x->sr_inbuf);
+    freebytes(x, sizeof(*x));
+}
+
+    /* this is in a separately called subroutine so that the buffer isn't
+    sitting on the stack while the messages are getting passed. */
+static int socketreceiver_doread(t_socketreceiver *x)
+{
+    char messbuf[INBUFSIZE], *bp = messbuf;
+    int indx;
+    int inhead = x->sr_inhead;
+    int intail = x->sr_intail;
+    char *inbuf = x->sr_inbuf;
+    if (intail == inhead) return (0);
+    for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1))
+    {
+            /* if we hit a semi that isn't preceeded by a \, it's a message
+            boundary.  LATER we should deal with the possibility that the
+            preceeding \ might itself be escaped! */
+        char c = *bp++ = inbuf[indx];
+        if (c == ';' && (!indx || inbuf[indx-1] != '\\'))
+        {
+            intail = (indx+1)&(INBUFSIZE-1);
+            binbuf_text(inbinbuf, messbuf, bp - messbuf);
+            if (sys_debuglevel & DEBUG_MESSDOWN)
+            {
+                write(2,  messbuf, bp - messbuf);
+                write(2, "\n", 1);
+            }
+            x->sr_inhead = inhead;
+            x->sr_intail = intail;
+            return (1);
+        }
+    }
+    return (0);
+}
+
+static void socketreceiver_getudp(t_socketreceiver *x, int fd)
+{
+    char buf[INBUFSIZE+1];
+    int ret = recv(fd, buf, INBUFSIZE, 0);
+    if (ret < 0)
+    {
+        sys_sockerror("recv");
+        sys_rmpollfn(fd);
+        sys_closesocket(fd);
+    }
+    else if (ret > 0)
+    {
+        buf[ret] = 0;
+#if 0
+        post("%s", buf);
+#endif
+        if (buf[ret-1] != '\n')
+        {
+#if 0
+            buf[ret] = 0;
+            error("dropped bad buffer %s\n", buf);
+#endif
+        }
+        else
+        {
+            char *semi = strchr(buf, ';');
+            if (semi) 
+                *semi = 0;
+            binbuf_text(inbinbuf, buf, strlen(buf));
+            outlet_setstacklim();
+            if (x->sr_socketreceivefn)
+                (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
+            else bug("socketreceiver_getudp");
+        }
+    }
+}
+
+void sys_exit(void);
+
+void socketreceiver_read(t_socketreceiver *x, int fd)
+{
+    if (x->sr_udp)   /* UDP ("datagram") socket protocol */
+        socketreceiver_getudp(x, fd);
+    else  /* TCP ("streaming") socket protocol */
+    {
+        char *semi;
+        int readto =
+            (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
+        int ret;
+
+            /* the input buffer might be full.  If so, drop the whole thing */
+        if (readto == x->sr_inhead)
+        {
+            fprintf(stderr, "pd: dropped message from gui\n");
+            x->sr_inhead = x->sr_intail = 0;
+            readto = INBUFSIZE;
+        }
+        else
+        {
+            ret = recv(fd, x->sr_inbuf + x->sr_inhead,
+                readto - x->sr_inhead, 0);
+            if (ret < 0)
+            {
+                sys_sockerror("recv");
+                if (x == sys_socketreceiver) sys_bail(1);
+                else
+                {
+                    if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
+                    sys_rmpollfn(fd);
+                    sys_closesocket(fd);
+                }
+            }
+            else if (ret == 0)
+            {
+                if (x == sys_socketreceiver)
+                {
+                    fprintf(stderr, "pd: exiting\n");
+                    sys_exit();
+                    return;
+                }
+                else
+                {
+                    post("EOF on socket %d\n", fd);
+                    if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
+                    sys_rmpollfn(fd);
+                    sys_closesocket(fd);
+                }
+            }
+            else
+            {
+                x->sr_inhead += ret;
+                if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0;
+                while (socketreceiver_doread(x))
+                {
+                    outlet_setstacklim();
+                    if (x->sr_socketreceivefn)
+                        (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
+                    else binbuf_eval(inbinbuf, 0, 0, 0);
+                }
+            }
+        }
+    }
+}
+
+void sys_closesocket(int fd)
+{
+#ifdef UNISTD
+    close(fd);
+#endif
+#ifdef MSW
+    closesocket(fd);
+#endif
+}
+
+/* ---------------------- sending messages to the GUI ------------------ */
+#define GUI_ALLOCCHUNK 8192
+#define GUI_UPDATESLICE 512 /* how much we try to do in one idle period */
+#define GUI_BYTESPERPING 1024 /* how much we send up per ping */
+
+typedef struct _guiqueue
+{
+    void *gq_client;
+    t_glist *gq_glist;
+    t_guicallbackfn gq_fn;
+    struct _guiqueue *gq_next;
+} t_guiqueue;
+
+static t_guiqueue *sys_guiqueuehead;
+static char *sys_guibuf;
+static int sys_guibufhead;
+static int sys_guibuftail;
+static int sys_guibufsize;
+static int sys_waitingforping;
+static int sys_bytessincelastping;
+
+static void sys_trytogetmoreguibuf(int newsize)
+{
+    char *newbuf = realloc(sys_guibuf, newsize);
+#if 0
+    static int sizewas;
+    if (newsize > 70000 && sizewas < 70000)
+    {
+        int i;
+        for (i = sys_guibuftail; i < sys_guibufhead; i++)
+            fputc(sys_guibuf[i], stderr);
+    }
+    sizewas = newsize;
+#endif
+#if 0
+    fprintf(stderr, "new size %d (head %d, tail %d)\n",
+        newsize, sys_guibufhead, sys_guibuftail);
+#endif
+
+        /* if realloc fails, make a last-ditch attempt to stay alive by
+        synchronously writing out the existing contents.  LATER test
+        this by intentionally setting newbuf to zero */
+    if (!newbuf)
+    {
+        int bytestowrite = sys_guibuftail - sys_guibufhead;
+        int written = 0;
+        while (1)
+        {
+            int res = send(sys_guisock,
+                sys_guibuf + sys_guibuftail + written, bytestowrite, 0);
+            if (res < 0)
+            {
+                perror("pd output pipe");
+                sys_bail(1);
+            }
+            else
+            {
+                written += res;
+                if (written >= bytestowrite)
+                    break;
+            }
+        }
+        sys_guibufhead = sys_guibuftail = 0;
+    }
+    else
+    {
+        sys_guibufsize = newsize;
+        sys_guibuf = newbuf;
+    }
+}
+
+void sys_vgui(char *fmt, ...)
+{
+    int msglen, bytesleft, headwas, nwrote;
+    va_list ap;
+
+    if (sys_nogui)
+        return;
+    if (!sys_guibuf)
+    {
+        if (!(sys_guibuf = malloc(GUI_ALLOCCHUNK)))
+        {
+            fprintf(stderr, "Pd: couldn't allocate GUI buffer\n");
+            sys_bail(1);
+        }
+        sys_guibufsize = GUI_ALLOCCHUNK;
+        sys_guibufhead = sys_guibuftail = 0;
+    }
+    if (sys_guibufhead > sys_guibufsize - (GUI_ALLOCCHUNK/2))
+        sys_trytogetmoreguibuf(sys_guibufsize + GUI_ALLOCCHUNK);
+    va_start(ap, fmt);
+    msglen = vsnprintf(sys_guibuf + sys_guibufhead,
+        sys_guibufsize - sys_guibufhead, fmt, ap);
+    va_end(ap);
+    if(msglen < 0) 
+    {
+        fprintf(stderr, "Pd: buffer space wasn't sufficient for long GUI string\n");
+        return;
+    }
+    if (msglen >= sys_guibufsize - sys_guibufhead)
+    {
+        int msglen2, newsize = sys_guibufsize + 1 +
+            (msglen > GUI_ALLOCCHUNK ? msglen : GUI_ALLOCCHUNK);
+        sys_trytogetmoreguibuf(newsize);
+
+        va_start(ap, fmt);
+        msglen2 = vsnprintf(sys_guibuf + sys_guibufhead,
+            sys_guibufsize - sys_guibufhead, fmt, ap);
+        va_end(ap);
+        if (msglen2 != msglen)
+            bug("sys_vgui");
+        if (msglen >= sys_guibufsize - sys_guibufhead)
+            msglen = sys_guibufsize - sys_guibufhead;
+    }
+    if (sys_debuglevel & DEBUG_MESSUP)
+        fprintf(stderr, "%s",  sys_guibuf + sys_guibufhead);
+    sys_guibufhead += msglen;
+    sys_bytessincelastping += msglen;
+}
+
+void sys_gui(char *s)
+{
+    sys_vgui("%s", s);
+}
+
+static int sys_flushtogui( void)
+{
+    int writesize = sys_guibufhead - sys_guibuftail, nwrote = 0;
+    if (writesize > 0)
+        nwrote = send(sys_guisock, sys_guibuf + sys_guibuftail, writesize, 0);
+
+#if 0   
+    if (writesize)
+        fprintf(stderr, "wrote %d of %d\n", nwrote, writesize);
+#endif
+
+    if (nwrote < 0)
+    {
+        perror("pd-to-gui socket");
+        sys_bail(1);
+    }
+    else if (!nwrote)
+        return (0);
+    else if (nwrote >= sys_guibufhead - sys_guibuftail)
+         sys_guibufhead = sys_guibuftail = 0;
+    else if (nwrote)
+    {
+        sys_guibuftail += nwrote;
+        if (sys_guibuftail > (sys_guibufsize >> 2))
+        {
+            memmove(sys_guibuf, sys_guibuf + sys_guibuftail,
+                sys_guibufhead - sys_guibuftail);
+            sys_guibufhead = sys_guibufhead - sys_guibuftail;
+            sys_guibuftail = 0;
+        }
+    }
+    return (1);
+}
+
+void glob_ping(t_pd *dummy)
+{
+    sys_waitingforping = 0;
+}
+
+static int sys_flushqueue(void )
+{
+    int wherestop = sys_bytessincelastping + GUI_UPDATESLICE;
+    if (wherestop + (GUI_UPDATESLICE >> 1) > GUI_BYTESPERPING)
+        wherestop = 0x7fffffff;
+    if (sys_waitingforping)
+        return (0);
+    if (!sys_guiqueuehead)
+        return (0);
+    while (1)
+    {
+        if (sys_bytessincelastping >= GUI_BYTESPERPING)
+        {
+            sys_gui("pdtk_ping\n");
+            sys_bytessincelastping = 0;
+            sys_waitingforping = 1;
+            return (1);
+        }
+        if (sys_guiqueuehead)
+        {
+            t_guiqueue *headwas = sys_guiqueuehead;
+            sys_guiqueuehead = headwas->gq_next;
+            (*headwas->gq_fn)(headwas->gq_client, headwas->gq_glist);
+            t_freebytes(headwas, sizeof(*headwas));
+            if (sys_bytessincelastping >= wherestop)
+                break;
+        }
+        else break;
+    }
+    sys_flushtogui();
+    return (1);
+}
+
+    /* flush output buffer and update queue to gui in small time slices */
+static int sys_poll_togui(void) /* returns 1 if did anything */
+{
+    if (sys_nogui)
+        return (0);
+        /* see if there is stuff still in the buffer, if so we
+            must have fallen behind, so just try to clear that. */
+    if (sys_flushtogui())
+        return (1);
+        /* if the flush wasn't complete, wait. */
+    if (sys_guibufhead > sys_guibuftail)
+        return (0);
+    
+        /* check for queued updates */
+    if (sys_flushqueue())
+        return (1);
+    
+    return (0);
+}
+
+    /* if some GUI object is having to do heavy computations, it can tell
+    us to back off from doing more updates by faking a big one itself. */
+void sys_pretendguibytes(int n)
+{
+    sys_bytessincelastping += n;
+}
+
+void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f)
+{
+    t_guiqueue **gqnextptr, *gq;
+    if (!sys_guiqueuehead)
+        gqnextptr = &sys_guiqueuehead;
+    else
+    {
+        for (gq = sys_guiqueuehead; gq->gq_next; gq = gq->gq_next)
+            if (gq->gq_client == client)
+                return;
+        if (gq->gq_client == client)
+            return;
+        gqnextptr = &gq->gq_next;
+    }
+    gq = t_getbytes(sizeof(*gq));
+    gq->gq_next = 0;
+    gq->gq_client = client;
+    gq->gq_glist = glist;
+    gq->gq_fn = f;
+    gq->gq_next = 0;
+    *gqnextptr = gq;
+}
+
+void sys_unqueuegui(void *client)
+{
+    t_guiqueue *gq, *gq2;
+    if (!sys_guiqueuehead)
+        return;
+    if (sys_guiqueuehead->gq_client == client)
+    {
+        t_freebytes(sys_guiqueuehead, sizeof(*sys_guiqueuehead));
+        sys_guiqueuehead = 0;
+    }
+    else for (gq = sys_guiqueuehead; gq2 = gq->gq_next; gq = gq2)
+        if (gq2->gq_client == client)
+    {
+        gq->gq_next = gq2->gq_next;
+        t_freebytes(gq2, sizeof(*gq2));
+        break;
+    }
+}
+
+int sys_pollgui(void)
+{
+    return (sys_domicrosleep(0, 1) || sys_poll_togui());
+}
+
+
+
+/* --------------------- starting up the GUI connection ------------- */
+
+static int sys_watchfd;
+
+#ifdef __linux__
+void glob_watchdog(t_pd *dummy)
+{
+    if (write(sys_watchfd, "\n", 1) < 1)
+    {
+        fprintf(stderr, "pd: watchdog process died\n");
+        sys_bail(1);
+    }
+}
+#endif
+
+#define FIRSTPORTNUM 5400
+
+static int defaultfontshit[] = {
+    8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
+        24, 15, 28};
+#define NDEFAULTFONT (sizeof(defaultfontshit)/sizeof(*defaultfontshit))
+
+int sys_startgui(const char *guidir)
+{
+    pid_t childpid;
+    char cmdbuf[4*MAXPDSTRING];
+    struct sockaddr_in server;
+    int msgsock;
+    char buf[15];
+    int len = sizeof(server);
+    int ntry = 0, portno = FIRSTPORTNUM;
+    int xsock = -1;
+#ifdef MSW
+    short version = MAKEWORD(2, 0);
+    WSADATA nobby;
+#endif
+#ifdef UNISTD
+    int stdinpipe[2];
+#endif
+    /* create an empty FD poll list */
+    sys_fdpoll = (t_fdpoll *)t_getbytes(0);
+    sys_nfdpoll = 0;
+    inbinbuf = binbuf_new();
+
+#ifdef UNISTD
+    signal(SIGHUP, sys_huphandler);
+    signal(SIGINT, sys_exithandler);
+    signal(SIGQUIT, sys_exithandler);
+    signal(SIGILL, sys_exithandler);
+    signal(SIGIOT, sys_exithandler);
+    signal(SIGFPE, SIG_IGN);
+    /* signal(SIGILL, sys_exithandler);
+    signal(SIGBUS, sys_exithandler);
+    signal(SIGSEGV, sys_exithandler); */
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGALRM, SIG_IGN);
+#if 0  /* GG says: don't use that */
+    signal(SIGSTKFLT, sys_exithandler);
+#endif
+#endif
+#ifdef MSW
+    if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
+#endif
+
+    if (sys_nogui)
+    {
+            /* fake the GUI's message giving cwd and font sizes; then
+            skip starting the GUI up. */
+        t_atom zz[NDEFAULTFONT+2];
+        int i;
+#ifdef MSW
+        if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
+            strcpy(cmdbuf, ".");
+#endif
+#ifdef UNISTD
+        if (!getcwd(cmdbuf, MAXPDSTRING))
+            strcpy(cmdbuf, ".");
+        
+#endif
+        SETSYMBOL(zz, gensym(cmdbuf));
+        for (i = 0; i < (int)NDEFAULTFONT; i++)
+            SETFLOAT(zz+i+1, defaultfontshit[i]);
+        SETFLOAT(zz+NDEFAULTFONT+1,0);
+        glob_initfromgui(0, 0, 23, zz);
+    }
+    else if (sys_guisetportnumber)  /* GUI exists and sent us a port number */
+    {
+        struct sockaddr_in server;
+        struct hostent *hp;
+        /* create a socket */
+        sys_guisock = socket(AF_INET, SOCK_STREAM, 0);
+        if (sys_guisock < 0)
+            sys_sockerror("socket");
+
+        /* connect socket using hostname provided in command line */
+        server.sin_family = AF_INET;
+
+        hp = gethostbyname(LOCALHOST);
+
+        if (hp == 0)
+        {
+            fprintf(stderr,
+                "localhost not found (inet protocol not installed?)\n");
+            exit(1);
+        }
+        memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+        /* assign client port number */
+        server.sin_port = htons((unsigned short)sys_guisetportnumber);
+
+            /* try to connect */
+        if (connect(sys_guisock, (struct sockaddr *) &server, sizeof (server))
+            < 0)
+        {
+            sys_sockerror("connecting stream socket");
+            exit(1);
+        }
+    }
+    else    /* default behavior: start up the GUI ourselves. */
+    {
+#ifdef MSW
+        char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
+        int spawnret;
+
+#endif
+#ifdef MSW
+        char intarg;
+#else
+        int intarg;
+#endif
+
+        /* create a socket */
+        xsock = socket(AF_INET, SOCK_STREAM, 0);
+        if (xsock < 0) sys_sockerror("socket");
+#if 0
+        intarg = 0;
+        if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF,
+            &intarg, sizeof(intarg)) < 0)
+                post("setsockopt (SO_RCVBUF) failed\n");
+        intarg = 0;
+        if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF,
+            &intarg, sizeof(intarg)) < 0)
+                post("setsockopt (SO_RCVBUF) failed\n");
+#endif
+        intarg = 1;
+        if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY,
+            &intarg, sizeof(intarg)) < 0)
+#ifndef MSW
+                post("setsockopt (TCP_NODELAY) failed\n")
+#endif
+                    ;
+        
+        
+        server.sin_family = AF_INET;
+        server.sin_addr.s_addr = INADDR_ANY;
+
+        /* assign server port number */
+        server.sin_port =  htons((unsigned short)portno);
+
+        /* name the socket */
+        while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
+        {
+#ifdef MSW
+            int err = WSAGetLastError();
+#else
+            int err = errno;
+#endif
+            if ((ntry++ > 20) || (err != EADDRINUSE))
+            {
+                perror("bind");
+                fprintf(stderr,
+                    "Pd needs your machine to be configured with\n");
+                fprintf(stderr,
+                  "'networking' turned on (see Pd's html doc for details.)\n");
+                exit(1);
+            }
+            portno++;
+            server.sin_port = htons((unsigned short)(portno));
+        }
+
+        if (sys_verbose) fprintf(stderr, "port %d\n", portno);
+
+
+#ifdef UNISTD
+        childpid = fork();
+        if (childpid < 0)
+        {
+            if (errno) perror("sys_startgui");
+            else fprintf(stderr, "sys_startgui failed\n");
+            return (1);
+        }
+        else if (!childpid)                     /* we're the child */
+        {
+            seteuid(getuid());          /* lose setuid priveliges */
+#ifndef __APPLE__
+                /* the wish process in Unix will make a wish shell and
+                    read/write standard in and out unless we close the
+                    file descriptors.  Somehow this doesn't make the MAC OSX
+                        version of Wish happy...*/
+            if (pipe(stdinpipe) < 0)
+                sys_sockerror("pipe");
+            else
+            {
+                if (stdinpipe[0] != 0)
+                {
+                    close (0);
+                    dup2(stdinpipe[0], 0);
+                    close(stdinpipe[0]);
+                }
+            }
+#endif
+            if (!sys_guicmd)
+            {
+#ifdef __APPLE__
+                char *homedir = getenv("HOME"), filename[250];
+                struct stat statbuf;
+                    /* first look for Wish bundled with and renamed "Pd" */
+                sprintf(filename, "%s/../../MacOS/Pd", guidir);
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                if (!homedir || strlen(homedir) > 150)
+                    goto nohomedir;
+                    /* Look for Wish in user's Applications.  Might or might
+                    not be names "Wish Shell", and might or might not be
+                    in "Utilities" subdir. */
+                sprintf(filename,
+                    "%s/Applications/Utilities/Wish shell.app/Contents/MacOS/Wish Shell",
+                        homedir);
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                sprintf(filename,
+                    "%s/Applications/Utilities/Wish.app/Contents/MacOS/Wish",
+                        homedir);
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                sprintf(filename,
+                    "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
+                        homedir);
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                sprintf(filename,
+                    "%s/Applications/Wish.app/Contents/MacOS/Wish",
+                        homedir);
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+            nohomedir:
+                    /* Perform the same search among system applications. */
+                strcpy(filename, 
+                    "/usr/bin/wish");
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                strcpy(filename, 
+                    "/Applications/Utilities/Wish Shell.app/Contents/MacOS/Wish Shell");
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                strcpy(filename, 
+                    "/Applications/Utilities/Wish.app/Contents/MacOS/Wish");
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                strcpy(filename, 
+                    "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
+                if (stat(filename, &statbuf) >= 0)
+                    goto foundit;
+                strcpy(filename, 
+                    "/Applications/Wish.app/Contents/MacOS/Wish");
+            foundit:
+                sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
+#else
+                sprintf(cmdbuf,
+"TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
+ \"%s/pd-gui\" %d\n",
+                    sys_libdir->s_name, sys_libdir->s_name, guidir, portno);
+#endif
+                sys_guicmd = cmdbuf;
+            }
+            if (sys_verbose) fprintf(stderr, "%s", sys_guicmd);
+            execl("/bin/sh", "sh", "-c", sys_guicmd, (char*)0);
+            perror("pd: exec");
+            _exit(1);
+        }
+#endif /* UNISTD */
+
+#ifdef MSW
+            /* in MSW land "guipath" is unused; we just do everything from
+            the libdir. */
+        /* fprintf(stderr, "%s\n", sys_libdir->s_name); */
+        
+        strcpy(scriptbuf, "\"");
+        strcat(scriptbuf, sys_libdir->s_name);
+        strcat(scriptbuf, "/" PDBINDIR "pd.tk\"");
+        sys_bashfilename(scriptbuf, scriptbuf);
+        
+                sprintf(portbuf, "%d", portno);
+
+        strcpy(wishbuf, sys_libdir->s_name);
+        strcat(wishbuf, "/" PDBINDIR WISHAPP);
+        sys_bashfilename(wishbuf, wishbuf);
+        
+        spawnret = _spawnl(P_NOWAIT, wishbuf, WISHAPP, scriptbuf, portbuf, 0);
+        if (spawnret < 0)
+        {
+            perror("spawnl");
+            fprintf(stderr, "%s: couldn't load TCL\n", wishbuf);
+            exit(1);
+        }
+
+#endif /* MSW */
+    }
+
+#if defined(__linux__) || defined(IRIX)
+        /* now that we've spun off the child process we can promote
+        our process's priority, if we can and want to.  If not specfied
+        (-1), we check root status.  This misses the case where we might
+        have permission from a "security module" (linux 2.6) -- I don't
+        know how to test for that.  The "-rt" flag must b eset in that
+        case. */
+    if (sys_hipriority == -1)
+        sys_hipriority = (!getuid() || !geteuid());
+    
+    if (sys_hipriority)
+    {
+            /* To prevent lockup, we fork off a watchdog process with
+            higher real-time priority than ours.  The GUI has to send
+            a stream of ping messages to the watchdog THROUGH the Pd
+            process which has to pick them up from the GUI and forward
+            them.  If any of these things aren't happening the watchdog
+            starts sending "stop" and "cont" signals to the Pd process
+            to make it timeshare with the rest of the system.  (Version
+            0.33P2 : if there's no GUI, the watchdog pinging is done
+            from the scheduler idle routine in this process instead.) */
+        int pipe9[2], watchpid;
+
+        if (pipe(pipe9) < 0)
+        {
+            seteuid(getuid());      /* lose setuid priveliges */
+            sys_sockerror("pipe");
+            return (1);
+        }
+        watchpid = fork();
+        if (watchpid < 0)
+        {
+            seteuid(getuid());      /* lose setuid priveliges */
+            if (errno)
+                perror("sys_startgui");
+            else fprintf(stderr, "sys_startgui failed\n");
+            return (1);
+        }
+        else if (!watchpid)             /* we're the child */
+        {
+            sys_set_priority(1);
+            seteuid(getuid());      /* lose setuid priveliges */
+            if (pipe9[1] != 0)
+            {
+                dup2(pipe9[0], 0);
+                close(pipe9[0]);
+            }
+            close(pipe9[1]);
+
+            sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
+            if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
+            execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0);
+            perror("pd: exec");
+            _exit(1);
+        }
+        else                            /* we're the parent */
+        {
+            sys_set_priority(0);
+            seteuid(getuid());      /* lose setuid priveliges */
+            close(pipe9[0]);
+            sys_watchfd = pipe9[1];
+                /* We also have to start the ping loop in the GUI;
+                this is done later when the socket is open. */
+        }
+    }
+
+    seteuid(getuid());          /* lose setuid priveliges */
+#endif /* __linux__ */
+
+#ifdef MSW
+    if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+        fprintf(stderr, "pd: couldn't set high priority class\n");
+#endif
+#ifdef __APPLE__
+    if (sys_hipriority)
+    {
+        struct sched_param param;
+        int policy = SCHED_RR;
+        int err;
+        param.sched_priority = 80; /* adjust 0 : 100 */
+
+        err = pthread_setschedparam(pthread_self(), policy, &param);
+        if (err)
+            post("warning: high priority scheduling failed\n");
+    }
+#endif /* __APPLE__ */
+
+    if (!sys_nogui && !sys_guisetportnumber)
+    {
+        if (sys_verbose)
+            fprintf(stderr, "Waiting for connection request... \n");
+        if (listen(xsock, 5) < 0) sys_sockerror("listen");
+
+        sys_guisock = accept(xsock, (struct sockaddr *) &server, 
+            (socklen_t *)&len);
+#ifdef OOPS
+        close(xsock);
+#endif
+        if (sys_guisock < 0) sys_sockerror("accept");
+        if (sys_verbose)
+            fprintf(stderr, "... connected\n");
+    }
+    if (!sys_nogui)
+    {
+      char buf[256], buf2[256];
+         sys_socketreceiver = socketreceiver_new(0, 0, 0, 0);
+         sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read,
+             sys_socketreceiver);
+
+            /* here is where we start the pinging. */
+#if defined(__linux__) || defined(IRIX)
+         if (sys_hipriority)
+             sys_gui("pdtk_watchdog\n");
+#endif
+         sys_get_audio_apis(buf);
+         sys_get_midi_apis(buf2);
+         sys_vgui("pdtk_pd_startup {%s} %s %s {%s}\n", pd_version, buf, buf2,
+                                  sys_font); 
+    }
+    return (0);
+
+}
+
+extern void sys_exit(void);
+
+/* This is called when something bad has happened, like a segfault.
+Call glob_quit() below to exit cleanly.
+LATER try to save dirty documents even in the bad case. */
+void sys_bail(int n)
+{
+    static int reentered = 0;
+    if (!reentered)
+    {
+        reentered = 1;
+#ifndef __linux__  /* sys_close_audio() hangs if you're in a signal? */
+        fprintf(stderr, "closing audio...\n");
+        sys_close_audio();
+        fprintf(stderr, "closing MIDI...\n");
+        sys_close_midi();
+        fprintf(stderr, "... done.\n");
+#endif
+        exit(n);
+    }
+    else _exit(1);
+}
+
+void glob_quit(void *dummy)
+{
+    sys_vgui("exit\n");
+    if (!sys_nogui)
+    {
+        close(sys_guisock);
+        sys_rmpollfn(sys_guisock);
+    }
+    sys_bail(0); 
+}
+
diff --git a/src/s_main.c b/src/s_main.c
index ded67c886..de282d043 100644
--- a/src/s_main.c
+++ b/src/s_main.c
@@ -58,7 +58,12 @@ int sys_nmidiin = -1;
 int sys_midiindevlist[MAXMIDIINDEV] = {1};
 int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
 
-char sys_font[100] = "courier"; /* tb: font name */
+#ifdef __APPLE__
+char sys_font[] = "Monaco"; /* tb: font name */
+#else
+char sys_font[] = "Bitstream Vera Sans Mono"; /* tb: font name */
+#endif
+char sys_fontweight[] = "normal"; /* currently only used for iemguis */
 static int sys_main_srate;
 static int sys_main_advance;
 static int sys_main_callback;
@@ -107,8 +112,12 @@ typedef struct _fontinfo
     in the six fonts.  */
 
 static t_fontinfo sys_fontlist[] = {
-    {8, 6, 10, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
-    {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
+    {8, 6, 10, 8, 6, 10}, {10, 7, 13, 10, 7, 13}, {12, 9, 16, 12, 9, 16},
+    {16, 10, 20, 16, 10, 20}, {24, 15, 25, 24, 15, 25},
+    {36, 25, 45, 36, 25, 45}};
+/*  {8, 5, 11, 8, 5, 11}, {10, 6, 13, 10, 6, 13}, {12, 7, 16, 12, 7, 16},
+    {16, 10, 19, 16, 10, 19}, {24, 14, 29, 24, 14, 29}, {36, 23, 44, 36, 23, 44}};
+*/
 #define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
 
 /* here are the actual font size structs on msp's systems:
@@ -159,11 +168,7 @@ int sys_fontheight(int fontsize)
 }
 
 int sys_defaultfont;
-#ifdef MSW
-#define DEFAULTFONT 12
-#else
 #define DEFAULTFONT 10
-#endif
 
 static void openit(const char *dirname, const char *filename)
 {
@@ -383,8 +388,9 @@ static char *(usagemessage[]) = {
 "-helppath <path> -- add to help file search path\n",
 "-open <file>     -- open file(s) on startup\n",
 "-lib <file>      -- load object library(s)\n",
-"-font <n>        -- specify default font size in points\n",
-"-typeface <name> -- specify default font (default: courier)\n",
+"-font-size <n>     -- specify default font size in points\n",
+"-font-face <name>  -- specify default font (default: Bitstream Vera Sans Mono)\n",
+"-font-weight <name>-- specify default font weight (normal or bold)\n",
 "-verbose         -- extra printout on startup and when searching for files\n",
 "-version         -- don't run Pd; just print out which version it is \n",
 "-d <n>           -- specify debug level\n",
@@ -744,21 +750,25 @@ int sys_argparse(int argc, char **argv)
             sys_externlist = namelist_append_files(sys_externlist, argv[1]);
             argc -= 2; argv += 2;
         }
-        else if (!strcmp(*argv, "-font") && argc > 1)
+        else if ((!strcmp(*argv, "-font-size") || !strcmp(*argv, "-font")) && argc > 1)
         {
             sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
             argc -= 2;
             argv += 2;
         }
-                /* tb: font name { */
-        else if (!strcmp(*argv, "-typeface") && argc > 1)
+        else if ((!strcmp(*argv, "-font-face") || !strcmp(*argv, "-typeface")) && argc > 1)
         {
             strncpy(sys_font,*(argv+1),sizeof(sys_font)-1);
             sys_font[sizeof(sys_font)-1] = 0;
             argc -= 2;
             argv += 2;
         }
-                /* } tb */
+        else if (!strcmp(*argv, "-font-weight") && argc > 1)
+        {
+                       strcpy(sys_fontweight,*(argv+1));
+                       argc -= 2;
+                       argv += 2;
+               }
         else if (!strcmp(*argv, "-verbose"))
         {
             sys_verbose++;
diff --git a/src/s_main.c.orig b/src/s_main.c.orig
new file mode 100644
index 000000000..ded67c886
--- /dev/null
+++ b/src/s_main.c.orig
@@ -0,0 +1,1001 @@
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#include "m_pd.h"
+#include "m_imp.h"
+#include "s_stuff.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+char *pd_version;
+char pd_compiletime[] = __TIME__;
+char pd_compiledate[] = __DATE__;
+
+void pd_init(void);
+int sys_argparse(int argc, char **argv);
+void sys_findprogdir(char *progname);
+int sys_startgui(const char *guipath);
+int sys_rcfile(void);
+int m_mainloop(void);
+void sys_addhelppath(char *p);
+#ifdef USEAPI_ALSA
+void alsa_adddev(char *name);
+#endif
+
+int sys_debuglevel;
+int sys_verbose;
+int sys_noloadbang;
+int sys_nogui;
+int sys_hipriority = -1;    /* -1 = don't care; 0 = no; 1 = yes */
+int sys_guisetportnumber;   /* if started from the GUI, this is the port # */
+int sys_nosleep = 0;  /* skip all "sleep" calls and spin instead */
+
+char *sys_guicmd;
+t_symbol *sys_libdir;
+static t_symbol *sys_guidir;
+static t_namelist *sys_openlist;
+static t_namelist *sys_messagelist;
+static int sys_version;
+int sys_oldtclversion;      /* hack to warn g_rtext.c about old text sel */
+
+int sys_nmidiout = -1;
+int sys_nmidiin = -1;
+int sys_midiindevlist[MAXMIDIINDEV] = {1};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
+
+char sys_font[100] = "courier"; /* tb: font name */
+static int sys_main_srate;
+static int sys_main_advance;
+static int sys_main_callback;
+static int sys_listplease;
+
+int sys_externalschedlib;
+char sys_externalschedlibname[MAXPDSTRING];
+int sys_extraflags;
+char sys_extraflagsstring[MAXPDSTRING];
+
+
+    /* here the "-1" counts signify that the corresponding vector hasn't been
+    specified in command line arguments; sys_set_audio_settings will detect it
+    and fill things in. */
+static int sys_nsoundin = -1;
+static int sys_nsoundout = -1;
+static int sys_soundindevlist[MAXAUDIOINDEV];
+static int sys_soundoutdevlist[MAXAUDIOOUTDEV];
+
+static int sys_nchin = -1;
+static int sys_nchout = -1;
+static int sys_chinlist[MAXAUDIOINDEV];
+static int sys_choutlist[MAXAUDIOOUTDEV];
+
+t_sample* get_sys_soundout() { return sys_soundout; }
+t_sample* get_sys_soundin() { return sys_soundin; }
+int* get_sys_main_advance() { return &sys_main_advance; }
+double* get_sys_time_per_dsp_tick() { return &sys_time_per_dsp_tick; }
+int* get_sys_schedblocksize() { return &sys_schedblocksize; }
+double* get_sys_time() { return &sys_time; }
+float* get_sys_dacsr() { return &sys_dacsr; }
+int* get_sys_sleepgrain() { return &sys_sleepgrain; }
+int* get_sys_schedadvance() { return &sys_schedadvance; }
+
+typedef struct _fontinfo
+{
+    int fi_fontsize;
+    int fi_maxwidth;
+    int fi_maxheight;
+    int fi_hostfontsize;
+    int fi_width;
+    int fi_height;
+} t_fontinfo;
+
+    /* these give the nominal point size and maximum height of the characters
+    in the six fonts.  */
+
+static t_fontinfo sys_fontlist[] = {
+    {8, 6, 10, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
+    {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
+#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
+
+/* here are the actual font size structs on msp's systems:
+MSW:
+font 8 5 9 8 5 11
+font 10 7 13 10 6 13
+font 12 9 16 14 8 16
+font 16 10 20 16 10 18
+font 24 15 25 16 10 18
+font 36 25 42 36 22 41
+
+linux:
+font 8 5 9 8 5 9
+font 10 7 13 12 7 13
+font 12 9 16 14 9 15
+font 16 10 20 16 10 19
+font 24 15 25 24 15 24
+font 36 25 42 36 22 41
+*/
+
+static t_fontinfo *sys_findfont(int fontsize)
+{
+    unsigned int i;
+    t_fontinfo *fi;
+    for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
+        if (fontsize < fi[1].fi_fontsize) return (fi);
+    return (sys_fontlist + (NFONT-1));
+}
+
+int sys_nearestfontsize(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_fontsize);
+}
+
+int sys_hostfontsize(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_hostfontsize);
+}
+
+int sys_fontwidth(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_width);
+}
+
+int sys_fontheight(int fontsize)
+{
+    return (sys_findfont(fontsize)->fi_height);
+}
+
+int sys_defaultfont;
+#ifdef MSW
+#define DEFAULTFONT 12
+#else
+#define DEFAULTFONT 10
+#endif
+
+static void openit(const char *dirname, const char *filename)
+{
+    char dirbuf[MAXPDSTRING], *nameptr;
+    int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
+        MAXPDSTRING, 0);
+    if (fd)
+    {
+        close (fd);
+        glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
+    }
+    else
+        error("%s: can't open", filename);
+}
+
+/* this is called from the gui process.  The first argument is the cwd, and
+succeeding args give the widths and heights of known fonts.  We wait until 
+these are known to open files and send messages specified on the command line.
+We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
+from; for instance we could be some kind of RT embedded system.  However, to
+really make this make sense we would have to implement
+open(), read(), etc, calls to be served somehow from the GUI too. */
+
+void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+    char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
+    t_namelist *nl;
+    unsigned int i;
+    int j;
+    int nhostfont = (argc-2)/3;
+    sys_oldtclversion = atom_getfloatarg(1, argc, argv);
+    if (argc != 2 + 3 * nhostfont) bug("glob_initfromgui");
+    for (i = 0; i < NFONT; i++)
+    {
+        int best = 0;
+        int wantheight = sys_fontlist[i].fi_maxheight;
+        int wantwidth = sys_fontlist[i].fi_maxwidth;
+        for (j = 1; j < nhostfont; j++)
+        {
+            if (atom_getintarg(3 * j + 4, argc, argv) <= wantheight &&
+                atom_getintarg(3 * j + 3, argc, argv) <= wantwidth)
+                    best = j;
+        }
+            /* best is now the host font index for the desired font index i. */
+        sys_fontlist[i].fi_hostfontsize =
+            atom_getintarg(3 * best + 2, argc, argv);
+        sys_fontlist[i].fi_width = atom_getintarg(3 * best + 3, argc, argv);
+        sys_fontlist[i].fi_height = atom_getintarg(3 * best + 4, argc, argv);
+    }
+#if 0
+    for (i = 0; i < 6; i++)
+        fprintf(stderr, "font (%d %d %d) -> (%d %d %d)\n",
+            sys_fontlist[i].fi_fontsize,
+            sys_fontlist[i].fi_maxwidth,
+            sys_fontlist[i].fi_maxheight,
+            sys_fontlist[i].fi_hostfontsize,
+            sys_fontlist[i].fi_width,
+            sys_fontlist[i].fi_height);
+#endif
+        /* load dynamic libraries specified with "-lib" args */
+    for  (nl = sys_externlist; nl; nl = nl->nl_next)
+        if (!sys_load_lib(0, nl->nl_string))
+            post("%s: can't load library", nl->nl_string);
+        /* open patches specifies with "-open" args */
+    for  (nl = sys_openlist; nl; nl = nl->nl_next)
+        openit(cwd, nl->nl_string);
+    namelist_free(sys_openlist);
+    sys_openlist = 0;
+        /* send messages specified with "-send" args */
+    for  (nl = sys_messagelist; nl; nl = nl->nl_next)
+    {
+        t_binbuf *b = binbuf_new();
+        binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
+        binbuf_eval(b, 0, 0, 0);
+        binbuf_free(b);
+    }
+    namelist_free(sys_messagelist);
+    sys_messagelist = 0;
+}
+
+static void sys_afterargparse(void);
+
+static void pd_makeversion(void)
+{
+    char foo[100];
+    sprintf(foo,  "Pd version %d.%d-%d%s\n",PD_MAJOR_VERSION,
+        PD_MINOR_VERSION,PD_BUGFIX_VERSION,PD_TEST_VERSION);
+    pd_version = malloc(strlen(foo)+1);
+    strcpy(pd_version, foo);
+}
+
+/* this is called from main() in s_entry.c */
+int sys_main(int argc, char **argv)
+{
+    int i, noprefs;
+    sys_externalschedlib = 0;
+    sys_extraflags = 0;
+#ifdef PD_DEBUG
+    fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
+#endif
+    pd_init();                                  /* start the message system */
+    sys_findprogdir(argv[0]);                   /* set sys_progname, guipath */
+    for (i = noprefs = 0; i < argc; i++)        /* prescan args for noprefs */
+        if (!strcmp(argv[i], "-noprefs"))
+            noprefs = 1;
+    if (!noprefs)
+        sys_loadpreferences();                  /* load default settings */
+#ifndef MSW
+    sys_rcfile();                               /* parse the startup file */
+#endif
+    if (sys_argparse(argc-1, argv+1))           /* parse cmd line */
+        return (1);
+    sys_afterargparse();                    /* post-argparse settings */
+        /* build version string from defines in m_pd.h */
+    pd_makeversion();
+    if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
+        pd_version, pd_compiletime, pd_compiledate);
+    if (sys_version)    /* if we were just asked our version, exit here. */
+        return (0);
+    if (sys_startgui(sys_guidir->s_name))       /* start the gui */
+        return(1);
+    if (sys_externalschedlib)
+    {
+#ifdef MSW
+        typedef int (*t_externalschedlibmain)(char *);
+        t_externalschedlibmain externalmainfunc;
+        HINSTANCE ntdll;
+        char filename[MAXPDSTRING];
+
+        sprintf(filename, "%s.dll", sys_externalschedlibname);
+        sys_bashfilename(filename, filename);
+        ntdll = LoadLibrary(filename);
+        if (!ntdll)
+        {
+              post("%s: couldn't load external scheduler lib ", filename);
+              return (0);
+        }
+        externalmainfunc = (t_externalschedlibmain)GetProcAddress(ntdll,
+                                                                  "main");
+        return((*externalmainfunc)(sys_extraflagsstring));
+#else
+        return (0);
+#endif
+    }
+    else
+    {
+            /* open audio and MIDI */
+        sys_reopen_midi();
+        sys_reopen_audio();
+            /* run scheduler until it quits */
+        return (m_mainloop());
+    }
+}
+
+static char *(usagemessage[]) = {
+"usage: pd [-flags] [file]...\n",
+"\naudio configuration flags:\n",
+"-r <n>           -- specify sample rate\n",
+"-audioindev ...  -- audio in devices; e.g., \"1,3\" for first and third\n",
+"-audiooutdev ... -- audio out devices (same)\n",
+"-audiodev ...    -- specify input and output together\n",
+"-inchannels ...  -- audio input channels (by device, like \"2\" or \"16,8\")\n",
+"-outchannels ... -- number of audio out channels (same)\n",
+"-channels ...    -- specify both input and output channels\n",
+"-audiobuf <n>    -- specify size of audio buffer in msec\n",
+"-blocksize <n>   -- specify audio I/O block size in sample frames\n",
+"-sleepgrain <n>  -- specify number of milliseconds to sleep when idle\n",
+"-nodac           -- suppress audio output\n",
+"-noadc           -- suppress audio input\n",
+"-noaudio         -- suppress audio input and output (-nosound is synonym) \n",
+"-listdev         -- list audio and MIDI devices\n",
+
+#ifdef USEAPI_OSS
+"-oss             -- use OSS audio API\n",
+"-32bit           ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
+#endif
+
+#ifdef USEAPI_ALSA
+"-alsa            -- use ALSA audio API\n",
+"-alsaadd <name>  -- add an ALSA device name to list\n",
+#endif
+
+#ifdef USEAPI_JACK
+"-jack            -- use JACK audio API\n",
+#endif
+
+#ifdef USEAPI_PORTAUDIO
+#ifdef MSW
+"-asio            -- use ASIO audio driver (via Portaudio)\n",
+"-pa              -- synonym for -asio\n",
+#else
+"-pa              -- use Portaudio API\n",
+#endif
+#endif
+
+#ifdef USEAPI_MMIO
+"-mmio            -- use MMIO audio API (default for Windows)\n",
+#endif
+"      (default audio API for this platform:  ", API_DEFSTRING, ")\n\n",
+
+"\nMIDI configuration flags:\n",
+"-midiindev ...   -- midi in device list; e.g., \"1,3\" for first and third\n",
+"-midioutdev ...  -- midi out device list, same format\n",
+"-mididev ...     -- specify -midioutdev and -midiindev together\n",
+"-nomidiin        -- suppress MIDI input\n",
+"-nomidiout       -- suppress MIDI output\n",
+"-nomidi          -- suppress MIDI input and output\n",
+#ifdef USEAPI_ALSA
+"-alsamidi        -- use ALSA midi API\n",
+#endif
+
+
+"\nother flags:\n",
+"-path <path>     -- add to file search path\n",
+"-nostdpath       -- don't search standard (\"extra\") directory\n",
+"-stdpath         -- search standard directory (true by default)\n",
+"-helppath <path> -- add to help file search path\n",
+"-open <file>     -- open file(s) on startup\n",
+"-lib <file>      -- load object library(s)\n",
+"-font <n>        -- specify default font size in points\n",
+"-typeface <name> -- specify default font (default: courier)\n",
+"-verbose         -- extra printout on startup and when searching for files\n",
+"-version         -- don't run Pd; just print out which version it is \n",
+"-d <n>           -- specify debug level\n",
+"-noloadbang      -- suppress all loadbangs\n",
+"-stderr          -- send printout to standard error instead of GUI\n",
+"-nogui           -- suppress starting the GUI\n",
+"-guiport <n>     -- connect to pre-existing GUI over port <n>\n",
+"-guicmd \"cmd...\" -- start alternatve GUI program (e.g., remote via ssh)\n",
+"-send \"msg...\"   -- send a message at startup, after patches are loaded\n",
+"-noprefs         -- suppress loading preferences on startup\n",
+#ifdef UNISTD
+"-rt or -realtime -- use real-time priority\n",
+"-nrt             -- don't use real-time priority\n",
+#endif
+"-nosleep         -- spin, don't sleep (may lower latency on multi-CPUs)\n",
+};
+
+static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
+{
+    int n = 0;
+    while (n < max)
+    {
+        if (!*str) break;
+        else
+        {
+            char *endp;
+            vecp[n] = strtol(str, &endp, 10);
+            if (endp == str)
+                break;
+            n++;
+            if (!endp)
+                break;
+            str = endp + 1;
+        }
+    }
+    *np = n;
+}
+
+static int sys_getmultidevchannels(int n, int *devlist)
+{
+    int sum = 0;
+    if (n<0)return(-1);
+    if (n==0)return 0;
+    while(n--)sum+=*devlist++;
+    return sum;
+}
+
+
+    /* this routine tries to figure out where to find the auxilliary files
+    Pd will need to run.  This is either done by looking at the command line
+    invokation for Pd, or if that fails, by consulting the variable
+    INSTALL_PREFIX.  In MSW, we don't try to use INSTALL_PREFIX. */
+void sys_findprogdir(char *progname)
+{
+    char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
+    char *lastslash; 
+#ifdef UNISTD
+    struct stat statbuf;
+#endif
+
+    /* find out by what string Pd was invoked; put answer in "sbuf". */
+#ifdef MSW
+    GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
+    sbuf2[MAXPDSTRING-1] = 0;
+    sys_unbashfilename(sbuf2, sbuf);
+#endif /* MSW */
+#ifdef UNISTD
+    strncpy(sbuf, progname, MAXPDSTRING);
+    sbuf[MAXPDSTRING-1] = 0;
+#endif
+    lastslash = strrchr(sbuf, '/');
+    if (lastslash)
+    {
+            /* bash last slash to zero so that sbuf is directory pd was in,
+                e.g., ~/pd/bin */
+        *lastslash = 0; 
+            /* go back to the parent from there, e.g., ~/pd */
+        lastslash = strrchr(sbuf, '/');
+        if (lastslash)
+        {
+            strncpy(sbuf2, sbuf, lastslash-sbuf);
+            sbuf2[lastslash-sbuf] = 0;
+        }
+        else strcpy(sbuf2, "..");
+    }
+    else
+    {
+            /* no slashes found.  Try INSTALL_PREFIX. */
+#ifdef INSTALL_PREFIX
+        strcpy(sbuf2, INSTALL_PREFIX);
+#else
+        strcpy(sbuf2, ".");
+#endif
+    }
+        /* now we believe sbuf2 holds the parent directory of the directory
+        pd was found in.  We now want to infer the "lib" directory and the
+        "gui" directory.  In "simple" unix installations, the layout is
+            .../bin/pd
+            .../bin/pd-gui
+            .../doc
+        and in "complicated" unix installations, it's:
+            .../bin/pd
+            .../lib/pd/bin/pd-gui
+            .../lib/pd/doc
+        To decide which, we stat .../lib/pd; if that exists, we assume it's
+        the complicated layout.  In MSW, it's the "simple" layout, but
+        the gui program is straight wish80:
+            .../bin/pd
+            .../bin/wish80.exe
+            .../doc
+        */
+#ifdef MSW
+    sys_libdir = gensym(sbuf2);
+    sys_guidir = &s_;   /* in MSW the guipath just depends on the libdir */
+#else
+    strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/lib/pd");
+    if (stat(sbuf, &statbuf) >= 0)
+    {
+            /* complicated layout: lib dir is the one we just stat-ed above */
+        sys_libdir = gensym(sbuf);
+            /* gui lives in .../lib/pd/bin */
+        strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+        sbuf[MAXPDSTRING-30] = 0;
+        strcat(sbuf, "/lib/pd/bin");
+        sys_guidir = gensym(sbuf);
+    }
+    else
+    {
+            /* simple layout: lib dir is the parent */
+        sys_libdir = gensym(sbuf2);
+            /* gui lives in .../bin */
+        strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+        sbuf[MAXPDSTRING-30] = 0;
+        strcat(sbuf, "/bin");
+        sys_guidir = gensym(sbuf);
+    }
+#endif
+}
+
+#ifdef MSW
+static int sys_mmio = 1;
+#else
+static int sys_mmio = 0;
+#endif
+
+int sys_argparse(int argc, char **argv)
+{
+    char sbuf[MAXPDSTRING];
+    int i;
+    while ((argc > 0) && **argv == '-')
+    {
+        if (!strcmp(*argv, "-r") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_main_srate) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-inchannels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchin,
+                sys_chinlist, MAXAUDIOINDEV, argv[1]);
+
+          if (!sys_nchin)
+              goto usage;
+
+          argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-outchannels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchout, sys_choutlist,
+                MAXAUDIOOUTDEV, argv[1]);
+
+          if (!sys_nchout)
+            goto usage;
+
+          argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-channels") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
+                argv[1]);
+            sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV,
+                argv[1]);
+
+            if (!sys_nchout)
+              goto usage;
+
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf") && (argc > 1))
+        {
+            sys_main_advance = atoi(argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-callback"))
+        {
+            sys_main_callback = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-blocksize"))
+        {
+            sys_setblocksize(atoi(argv[1]));
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-sleepgrain") && (argc > 1))
+        {
+            sys_sleepgrain = 1000 * atof(argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-nodac"))
+        {
+            sys_nsoundout=0;
+            sys_nchout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-noadc"))
+        {
+            sys_nsoundin=0;
+            sys_nchin = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
+        {
+            sys_nsoundin=sys_nsoundout = 0;
+            sys_nchin = sys_nchout = 0;
+            argc--; argv++;
+        }
+#ifdef USEAPI_OSS
+        else if (!strcmp(*argv, "-oss"))
+        {
+            sys_set_audio_api(API_OSS);
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-32bit"))
+        {
+            sys_set_audio_api(API_OSS);
+            oss_set32bit();
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_ALSA
+        else if (!strcmp(*argv, "-alsa"))
+        {
+            sys_set_audio_api(API_ALSA);
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-alsaadd") && (argc > 1))
+        {
+            if (argc > 1)
+                alsa_adddev(argv[1]);
+            else goto usage;
+            argc -= 2; argv +=2;
+        }
+        else if (!strcmp(*argv, "-alsamidi"))
+        {
+          sys_set_midi_api(API_ALSA);
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_JACK
+        else if (!strcmp(*argv, "-jack"))
+        {
+            sys_set_audio_api(API_JACK);
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_PORTAUDIO
+        else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio")
+#ifdef MSW
+            || !strcmp(*argv, "-asio")
+#endif
+            )
+        {
+            sys_set_audio_api(API_PORTAUDIO);
+            sys_mmio = 0;
+            argc--; argv++;
+        }
+#endif
+#ifdef USEAPI_MMIO
+        else if (!strcmp(*argv, "-mmio"))
+        {
+            sys_set_audio_api(API_MMIO);
+            sys_mmio = 1;
+            argc--; argv++;
+        }
+#endif
+        else if (!strcmp(*argv, "-nomidiin"))
+        {
+            sys_nmidiin = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nomidiout"))
+        {
+            sys_nmidiout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nomidi"))
+        {
+            sys_nmidiin = sys_nmidiout = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-midiindev"))
+        {
+            sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+                argv[1]);
+            if (!sys_nmidiin)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-midioutdev") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+                argv[1]);
+            if (!sys_nmidiout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-mididev") && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+                argv[1]);
+            sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+                argv[1]);
+            if (!sys_nmidiout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-path") && (argc > 1))
+        {
+            sys_searchpath = namelist_append_files(sys_searchpath, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-nostdpath"))
+        {
+            sys_usestdpath = 0;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-stdpath"))
+        {
+            sys_usestdpath = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-helppath"))
+        {
+            sys_helppath = namelist_append_files(sys_helppath, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-open") && argc > 1)
+        {
+            sys_openlist = namelist_append_files(sys_openlist, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-lib") && argc > 1)
+        {
+            sys_externlist = namelist_append_files(sys_externlist, argv[1]);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-font") && argc > 1)
+        {
+            sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
+            argc -= 2;
+            argv += 2;
+        }
+                /* tb: font name { */
+        else if (!strcmp(*argv, "-typeface") && argc > 1)
+        {
+            strncpy(sys_font,*(argv+1),sizeof(sys_font)-1);
+            sys_font[sizeof(sys_font)-1] = 0;
+            argc -= 2;
+            argv += 2;
+        }
+                /* } tb */
+        else if (!strcmp(*argv, "-verbose"))
+        {
+            sys_verbose++;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-version"))
+        {
+            sys_version = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-d") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-noloadbang"))
+        {
+            sys_noloadbang = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nogui"))
+        {
+            sys_printtostderr = sys_nogui = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-guiport") && argc > 1 &&
+            sscanf(argv[1], "%d", &sys_guisetportnumber) >= 1)
+        {
+            argc -= 2;
+            argv += 2;
+        }
+        else if (!strcmp(*argv, "-stderr"))
+        {
+            sys_printtostderr = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-guicmd") && argc > 1)
+        {
+            sys_guicmd = argv[1];
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-send") && argc > 1)
+        {
+            sys_messagelist = namelist_append(sys_messagelist, argv[1], 1);
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-listdev"))
+        {
+            sys_listplease = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-schedlib"))
+        {
+            sys_externalschedlib = 1;
+            strcpy(sys_externalschedlibname, argv[1]);
+            argv += 2;
+            argc -= 2;
+        }
+        else if (!strcmp(*argv, "-extraflags"))
+        {
+            sys_extraflags = 1;
+            strcpy(sys_extraflagsstring, argv[1]);
+            argv += 2;
+            argc -= 2;
+        }
+#ifdef UNISTD
+        else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
+        {
+            sys_hipriority = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-nrt"))
+        {
+            sys_hipriority = 0;
+            argc--; argv++;
+        }
+#endif
+        else if (!strcmp(*argv, "-nosleep"))
+        {
+            sys_nosleep = 1;
+            argc--; argv++;
+        }
+        else if (!strcmp(*argv, "-soundindev") ||
+            !strcmp(*argv, "-audioindev"))
+        {
+            sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+                MAXAUDIOINDEV, argv[1]);
+            if (!sys_nsoundin)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-soundoutdev") ||
+            !strcmp(*argv, "-audiooutdev"))
+        {
+            sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+                MAXAUDIOOUTDEV, argv[1]);
+            if (!sys_nsoundout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if ((!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
+                 && (argc > 1))
+        {
+            sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+                MAXAUDIOINDEV, argv[1]);
+            sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+                MAXAUDIOOUTDEV, argv[1]);
+            if (!sys_nsoundout)
+                goto usage;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(*argv, "-noprefs")) /* did this earlier */
+            argc--, argv++;
+        else
+        {
+            unsigned int i;
+        usage:
+            for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
+                fprintf(stderr, "%s", usagemessage[i]);
+            return (1);
+        }
+    }
+    if (!sys_defaultfont)
+        sys_defaultfont = DEFAULTFONT;
+    for (; argc > 0; argc--, argv++) 
+        sys_openlist = namelist_append_files(sys_openlist, *argv);
+
+
+    return (0);
+}
+
+int sys_getblksize(void)
+{
+    return (DEFDACBLKSIZE);
+}
+
+    /* stuff to do, once, after calling sys_argparse() -- which may itself
+    be called more than once (first from "settings, second from .pdrc, then
+    from command-line arguments */
+static void sys_afterargparse(void)
+{
+    char sbuf[MAXPDSTRING];
+    int i;
+    int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
+    int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
+    int nchindev, nchoutdev, rate, advance, callback;
+    int nmidiindev = 0, midiindev[MAXMIDIINDEV];
+    int nmidioutdev = 0, midioutdev[MAXMIDIOUTDEV];
+            /* add "extra" library to path */
+    strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/extra");
+    sys_setextrapath(sbuf);
+            /* add "doc/5.reference" library to helppath */
+    strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+    sbuf[MAXPDSTRING-30] = 0;
+    strcat(sbuf, "/doc/5.reference");
+    sys_helppath = namelist_append_files(sys_helppath, sbuf);
+        /* correct to make audio and MIDI device lists zero based.  On
+        MMIO, however, "1" really means the second device (the first one
+        is "mapper" which is was not included when the command args were
+        set up, so we leave it that way for compatibility. */
+    if (!sys_mmio)
+    {
+        for (i = 0; i < sys_nsoundin; i++)
+            sys_soundindevlist[i]--;
+        for (i = 0; i < sys_nsoundout; i++)
+            sys_soundoutdevlist[i]--;
+    }
+    for (i = 0; i < sys_nmidiin; i++)
+        sys_midiindevlist[i]--;
+    for (i = 0; i < sys_nmidiout; i++)
+        sys_midioutdevlist[i]--;
+    if (sys_listplease)
+        sys_listdevs();
+        
+            /* get the current audio parameters.  These are set
+            by the preferences mechanism (sys_loadpreferences()) or
+            else are the default.  Overwrite them with any results
+            of argument parsing, and store them again. */
+    sys_get_audio_params(&naudioindev, audioindev, chindev,
+        &naudiooutdev, audiooutdev, choutdev, &rate, &advance, &callback);
+    if (sys_nchin >= 0)
+    {
+        nchindev = sys_nchin;
+        for (i = 0; i < nchindev; i++)
+            chindev[i] = sys_chinlist[i];
+    }
+    else nchindev = naudioindev;
+    if (sys_nsoundin >= 0)
+    {
+        naudioindev = sys_nsoundin;
+        for (i = 0; i < naudioindev; i++)
+            audioindev[i] = sys_soundindevlist[i];
+    }
+    
+    if (sys_nchout >= 0)
+    {
+        nchoutdev = sys_nchout;
+        for (i = 0; i < nchoutdev; i++)
+            choutdev[i] = sys_choutlist[i];
+    }
+    else nchoutdev = naudiooutdev;
+    if (sys_nsoundout >= 0)
+    {
+        naudiooutdev = sys_nsoundout;
+        for (i = 0; i < naudiooutdev; i++)
+            audiooutdev[i] = sys_soundoutdevlist[i];
+    }
+    sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+    if (sys_nmidiin >= 0)
+    {
+        post("sys_nmidiin %d, nmidiindev %d", sys_nmidiin, nmidiindev);
+        nmidiindev = sys_nmidiin;
+        for (i = 0; i < nmidiindev; i++)
+            midiindev[i] = sys_midiindevlist[i];
+    }
+    if (sys_nmidiout >= 0)
+    {
+        nmidioutdev = sys_nmidiout;
+        for (i = 0; i < nmidioutdev; i++)
+            midioutdev[i] = sys_midioutdevlist[i];
+    }
+    if (sys_main_advance)
+        advance = sys_main_advance;
+    if (sys_main_srate)
+        rate = sys_main_srate;
+    if (sys_main_callback)
+        callback = sys_main_callback;
+    sys_set_audio_settings(naudioindev, audioindev, nchindev, chindev,
+        naudiooutdev, audiooutdev, nchoutdev, choutdev, rate, advance, 
+        callback);
+    sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0);
+}
+
+static void sys_addreferencepath(void)
+{
+    char sbuf[MAXPDSTRING];
+}
diff --git a/src/u_main.tk b/src/u_main.tk
index 2a736ca5d..8da3b4503 100644
--- a/src/u_main.tk
+++ b/src/u_main.tk
@@ -1,14 +1,4 @@
 #!/usr/bin/wish
-
-# set pd_nt (bad name) 0 for unix, 1 for microsoft, and 2 for Mac OSX.
-if { $tcl_platform(platform) == "windows" }  {
-         set pd_nt 1
-} elseif { $tcl_platform(os) == "Darwin" } {  
-         set pd_nt 2
-} else { 
-         set pd_nt 0
-}        
-
 # Copyright (c) 1997-1999 Miller Puckette.
 # For information on usage and redistribution, and for a DISCLAIMER OF ALL
 # WARRANTIES, see the file, "LICENSE.txt," in this distribution.
@@ -21,6 +11,35 @@ if { $tcl_platform(platform) == "windows" }  {
 #
 # all this changes are labeled with #######iemlib##########
 
+# set pd_nt (bad name) 0 for unix, 1 for microsoft, and 2 for Mac OSX.
+if { $tcl_platform(platform) == "windows" }  {
+    set pd_nt 1
+	 set defaultFontFamily {Bitstream Vera Sans Mono}
+    font create menuFont -family Tahoma -size 11
+} elseif { $tcl_platform(os) == "Darwin" } {  
+    set pd_nt 2
+	 set defaultFontFamily Monaco
+} else { 
+    set pd_nt 0
+	 set defaultFontFamily {Bitstream Vera Sans Mono}
+}        
+
+# start Pd-extended font hacks -----------------------------
+
+# Pd-0.39.2-extended hacks to make font/box sizes the same across platform
+# puts stderr "tk scaling is [tk scaling]"
+tk scaling 1
+
+# this font is for the Pd Window console text
+font create console_font -family $defaultFontFamily -size 12 -weight normal
+# this font is for text in Pd windows
+font create text_font -family {Times} -size 14 -weight normal
+# for text in Properties Panels and other panes
+font create highlight_font -family $defaultFontFamily -size 14 -weight bold
+
+# end Pd-extended font hacks -----------------------------
+
+
 # Tearoff is set to true by default:
 set pd_tearoff 1
 
@@ -44,12 +63,8 @@ if {$pd_nt == 1} {
 if {$pd_nt == 2} {
 # turn on James Tittle II's fast drawing
     set tk::mac::useCGDrawing 1
-    # set minimum line size for anti-aliasing.  If set to 1 or 0, then every
-    # line will be anti-aliased.  While this makes connections and circles in
-    # [bng] and such look really good, it makes boxes and messages look out of
-    # focus.  Setting this to 2 makes it so the thick audio rate connections
-    # are anti-aliased.  <hans@at.or.at> 2005-06-09
-    set tk::mac::CGAntialiasLimit 2
+# anti-alias all lines that need it
+    set tk::mac::CGAntialiasLimit 0
     global pd_guidir
     global pd_tearoff
     set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
@@ -132,6 +147,15 @@ if {$pd_nt != 2} {
     .mbar add cascade -label "Help" -menu .mbar.help
 }
 
+# fix menu font size on Windows with tk scaling = 1
+if {$pd_nt == 1} {
+    .mbar.file configure -font menuFont
+    .mbar.find configure -font menuFont
+    .mbar.windows configure -font menuFont
+    .mbar.audio configure -font menuFont
+    .mbar.help configure -font menuFont
+}
+
 set ctrls_audio_on 0
 set ctrls_meter_on 0
 set ctrls_inlevel 0
@@ -175,7 +199,7 @@ pack .controls.dio -side right -padx 20
 
 
 frame .printout
-text .printout.text -relief raised -bd 2 -font -*-courier-bold--normal--12-* \
+text .printout.text -relief raised -bd 2 -font console_font \
     -yscrollcommand ".printout.scroll set" -width 80
 # .printout.text insert end "\n\n\n\n\n\n\n\n\n\n"
 scrollbar .printout.scroll -command ".printout.text yview"
@@ -365,7 +389,7 @@ proc menu_opentext {filename} {
     global pd_myversion
     set name [format ".help%d" $doc_number]
     toplevel $name
-    text $name.text -relief raised -bd 2 -font -*-times-regular--normal--14-* \
+    text $name.text -relief raised -bd 2 -font text_font \
         -yscrollcommand "$name.scroll set" -background white
     scrollbar $name.scroll -command "$name.text yview"
     pack $name.scroll -side right -fill y
@@ -1143,6 +1167,18 @@ proc pdtk_canvas_new {name width height geometry editable} {
     $name.popup add command -label {Help} \
         -command [concat popup_action $name 2] 
 
+# fix menu font size on Windows with tk scaling = 1
+if {$pd_nt == 1} {
+    $name.m.file configure -font menuFont
+    $name.m.edit configure -font menuFont
+    $name.m.find configure -font menuFont
+    $name.m.put configure -font menuFont
+    $name.m.windows configure -font menuFont
+    $name.m.audio configure -font menuFont
+    $name.m.help configure -font menuFont
+    $name.popup configure -font menuFont
+}
+
 # WM protocol
     wm protocol $name WM_DELETE_WINDOW [concat menu_close $name]
 
@@ -1267,6 +1303,7 @@ proc pdtk_array_listview_new {id arrayName page} {
     global pd_nt
     global pd_array_listview_page
     global pd_array_listview_id
+	 global fontname fontweight
     set pd_array_listview_page($arrayName) $page
     set pd_array_listview_id($arrayName) $id
     set windowName [format ".%sArrayWindow" $arrayName]
@@ -1280,8 +1317,7 @@ proc pdtk_array_listview_new {id arrayName page} {
     set $windowName.lb [listbox $windowName.lb -height 20 -width 25\
                         -selectmode extended \
                         -relief solid -background white -borderwidth 1 \
-                        -font [format -*-courier-bold--normal--%d-* \
-                               $font] \
+                        -font [format {{%s} %d %s} $fontname $font $fontweight]\
                         -yscrollcommand "$windowName.lb.sb set"]
     set $windowName.lb.sb [scrollbar $windowName.lb.sb \
                            -command "$windowName.lb yview" -orient vertical]
@@ -1385,9 +1421,7 @@ proc pdtk_array_listview_paste {arrayName} {
 proc pdtk_array_listview_edit {arrayName page font} {
     global pd_array_listview_entry
     global pd_nt
-    if {$pd_nt == 0} {
-      set font [expr $font - 2]
-    }
+	 global fontname fontweight
     set lbName [format ".%sArrayWindow.lb" $arrayName]
     if {[winfo exists $lbName.entry]} {
       pdtk_array_listview_update_entry \
@@ -1399,7 +1433,7 @@ proc pdtk_array_listview_edit {arrayName page font} {
     set bbox [$lbName bbox $itemNum]
     set y [expr [lindex $bbox 1] - 4]
     set $lbName.entry [entry $lbName.entry \
-                       -font [format -*-courier-bold--normal--%d-* $font]]
+                       -font [format {{%s} %d %s} $fontname $font $fontweight]]
     $lbName.entry insert 0 []
     place configure $lbName.entry -relx 0 -y $y -relwidth 1
     lower $lbName.entry
@@ -1875,6 +1909,8 @@ proc pdtk_gatom_dialog {id initwidth initlo inithi \
 
     set vid [string trimleft $id .]
 
+	 global pd_nt
+
     set var_gatomwidth [concat gatomwidth_$vid]
     global $var_gatomwidth
     set var_gatomlo [concat gatomlo_$vid]
@@ -1899,87 +1935,96 @@ proc pdtk_gatom_dialog {id initwidth initlo inithi \
     set $var_gatomsymto [gatom_unescape $symto]
 
     toplevel $id
-    wm title $id {Atom}
+    wm title $id "atom box properties"
+    wm resizable $id 0 0
     wm protocol $id WM_DELETE_WINDOW [concat dogatom_cancel $id]
 
-    frame $id.buttonframe
-    pack $id.buttonframe -side bottom -fill x -pady 2m
+    frame $id.params -height 7
+    pack $id.params -side top
+    label $id.params.entryname -text "width"
+    entry $id.params.entry -textvariable $var_gatomwidth -width 4
+    pack $id.params.entryname $id.params.entry -side left
+
+    labelframe $id.limits -text "limits" -padx 15 -pady 4 -borderwidth 1 \
+		  -font highlight_font
+	 pack $id.limits -side top -fill x
+    frame $id.limits.lower
+    pack $id.limits.lower -side left
+    label $id.limits.lower.entryname -text "lower"
+    entry $id.limits.lower.entry -textvariable $var_gatomlo -width 8
+    pack $id.limits.lower.entryname $id.limits.lower.entry -side left
+    frame $id.limits.upper
+    pack $id.limits.upper -side left
+    frame $id.limits.upper.spacer -width 20
+    label $id.limits.upper.entryname -text "upper"
+    entry $id.limits.upper.entry -textvariable $var_gatomhi -width 8
+    pack  $id.limits.upper.spacer $id.limits.upper.entryname \
+		  $id.limits.upper.entry -side left
+
+    frame $id.spacer1 -height 7
+    pack $id.spacer1 -side top
+
+    labelframe $id.label -text "label" -padx 5 -pady 4 -borderwidth 1 \
+		  -font highlight_font
+	 pack $id.label -side top -fill x
+    frame $id.label.name
+    pack $id.label.name -side top
+    entry $id.label.name.entry -textvariable $var_gatomlabel -width 33
+    pack $id.label.name.entry -side left
+    frame $id.label.radio
+    pack $id.label.radio -side top
+    radiobutton $id.label.radio.left -value 0 \
+        -variable $var_gatomwherelabel \
+        -text "left   "  -justify left
+    radiobutton $id.label.radio.right -value 1 \
+        -variable $var_gatomwherelabel \
+        -text "right" -justify left
+    radiobutton $id.label.radio.top -value 2 \
+        -variable $var_gatomwherelabel \
+        -text "top" -justify left
+    radiobutton $id.label.radio.bottom -value 3 \
+        -variable $var_gatomwherelabel \
+        -text "bottom" -justify left
+    pack $id.label.radio.left -side left -anchor w
+    pack $id.label.radio.right -side right -anchor w
+    pack $id.label.radio.top -side top -anchor w
+    pack $id.label.radio.bottom -side bottom -anchor w
+
+    frame $id.spacer2 -height 7
+    pack $id.spacer2 -side top
+
+    labelframe $id.s_r -text "messages" -padx 5 -pady 4 -borderwidth 1 \
+		  -font highlight_font
+	 pack $id.s_r -side top -fill x
+    frame $id.s_r.paramsymto
+    pack $id.s_r.paramsymto -side top -anchor e
+    label $id.s_r.paramsymto.entryname -text "send symbol"
+    entry $id.s_r.paramsymto.entry -textvariable $var_gatomsymto -width 21
+    pack $id.s_r.paramsymto.entry $id.s_r.paramsymto.entryname -side right
+
+    frame $id.s_r.paramsymfrom
+    pack $id.s_r.paramsymfrom -side top -anchor e
+    label $id.s_r.paramsymfrom.entryname -text "receive symbol"
+    entry $id.s_r.paramsymfrom.entry -textvariable $var_gatomsymfrom -width 21
+    pack $id.s_r.paramsymfrom.entry $id.s_r.paramsymfrom.entryname -side right
+        
+    frame $id.buttonframe -pady 5
+    pack $id.buttonframe -side top -fill x -pady 2m
     button $id.buttonframe.cancel -text {Cancel}\
         -command "dogatom_cancel $id"
+    pack $id.buttonframe.cancel -side left -expand 1
     button $id.buttonframe.apply -text {Apply}\
         -command "dogatom_apply $id"
+    pack $id.buttonframe.apply -side left -expand 1
     button $id.buttonframe.ok -text {OK}\
         -command "dogatom_ok $id"
-    pack $id.buttonframe.cancel -side left -expand 1
-    pack $id.buttonframe.apply -side left -expand 1
     pack $id.buttonframe.ok -side left -expand 1
 
-    frame $id.paramsymto
-    pack $id.paramsymto -side bottom
-    label $id.paramsymto.entryname -text {send symbol}
-    entry $id.paramsymto.entry -textvariable $var_gatomsymto -width 20
-    pack $id.paramsymto.entryname $id.paramsymto.entry -side left
-
-    frame $id.paramsymfrom
-    pack $id.paramsymfrom -side bottom
-    label $id.paramsymfrom.entryname -text {receive symbol}
-    entry $id.paramsymfrom.entry -textvariable $var_gatomsymfrom -width 20
-    pack $id.paramsymfrom.entryname $id.paramsymfrom.entry -side left
-    
-    frame $id.radio
-    pack $id.radio -side bottom
-    label $id.radio.label -text {show label on:}
-    frame $id.radio.l
-    frame $id.radio.r
-    pack $id.radio.label -side top
-    pack $id.radio.l $id.radio.r -side left
-    radiobutton $id.radio.l.radio0 -value 0 \
-        -variable $var_gatomwherelabel \
-        -text "left"
-    radiobutton $id.radio.l.radio1 -value 1 \
-        -variable $var_gatomwherelabel \
-        -text "right"
-    radiobutton $id.radio.r.radio2 -value 2 \
-        -variable $var_gatomwherelabel \
-        -text "top"
-    radiobutton $id.radio.r.radio3 -value 3 \
-        -variable $var_gatomwherelabel \
-        -text "bottom"
-    pack $id.radio.l.radio0 $id.radio.l.radio1 -side top -anchor w
-    pack $id.radio.r.radio2 $id.radio.r.radio3 -side top -anchor w
-        
-
-    frame $id.paramlabel
-    pack $id.paramlabel -side bottom
-    label $id.paramlabel.entryname -text label
-    entry $id.paramlabel.entry -textvariable $var_gatomlabel -width 20
-    pack $id.paramlabel.entryname $id.paramlabel.entry -side left
-
-    frame $id.paramhi
-    pack $id.paramhi -side bottom
-    label $id.paramhi.entryname -text "upper limit"
-    entry $id.paramhi.entry -textvariable $var_gatomhi -width 8
-    pack $id.paramhi.entryname $id.paramhi.entry -side left
-
-    frame $id.paramlo
-    pack $id.paramlo -side bottom
-    label $id.paramlo.entryname -text "lower limit"
-    entry $id.paramlo.entry -textvariable $var_gatomlo -width 8
-    pack $id.paramlo.entryname $id.paramlo.entry -side left
-
-    frame $id.params
-    pack $id.params -side bottom
-    label $id.params.entryname -text width
-    entry $id.params.entry -textvariable $var_gatomwidth -width 4
-    pack $id.params.entryname $id.params.entry -side left
-
-
-
-    bind $id.paramhi.entry <KeyPress-Return> [concat dogatom_ok $id]
-    bind $id.paramlo.entry <KeyPress-Return> [concat dogatom_ok $id]
+    bind $id.limits.upper.entry <KeyPress-Return> [concat dogatom_ok $id]
+    bind $id.limits.lower.entry <KeyPress-Return> [concat dogatom_ok $id]
     bind $id.params.entry <KeyPress-Return> [concat dogatom_ok $id]
-    pdtk_standardkeybindings $id.paramhi.entry
-    pdtk_standardkeybindings $id.paramlo.entry
+    pdtk_standardkeybindings $id.limits.upper.entry
+    pdtk_standardkeybindings $id.limits.lower.entry
     pdtk_standardkeybindings $id.params.entry
     $id.params.entry select from 0
     $id.params.entry select adjust end
@@ -2132,7 +2177,7 @@ proc iemgui_clip_fontsize {id} {
 
     if {[eval concat $$var_iemgui_gn_fs] < $iemgui_define_min_fontsize} {
         set $var_iemgui_gn_fs $iemgui_define_min_fontsize
-        $id.gnfs.fs_ent configure -textvariable $var_iemgui_gn_fs
+        $id.label.fs_ent configure -textvariable $var_iemgui_gn_fs
     }
 }
 
@@ -2146,20 +2191,20 @@ proc iemgui_set_col_example {id} {
     set var_iemgui_lcol [concat iemgui_lcol_$vid]
     global $var_iemgui_lcol
     
-    $id.col_example_choose.lb_bk configure \
+    $id.colors.sections.lb_bk configure \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
        -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]]
     
     if { [eval concat $$var_iemgui_fcol] >= 0 } {
-       $id.col_example_choose.fr_bk configure \
+       $id.colors.sections.fr_bk configure \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
        -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]]
     } else {
-       $id.col_example_choose.fr_bk configure \
+       $id.colors.sections.fr_bk configure \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
@@ -2243,17 +2288,27 @@ proc iemgui_lilo {id} {
     }
 }
 
-proc iemgui_toggle_font {id} {
+proc iemgui_toggle_font {id gn_f} {
     set vid [string trimleft $id .]
 
     set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
     global $var_iemgui_gn_f
+	 global fontname fontweight
     
-    set $var_iemgui_gn_f [expr [eval concat $$var_iemgui_gn_f] + 1]
-    if {[eval concat $$var_iemgui_gn_f] > 2} {set $var_iemgui_gn_f 0}
-    if {[eval concat $$var_iemgui_gn_f] == 0} {$id.gnfs.fb configure -text "courier" -font {courier 10 bold}}
-    if {[eval concat $$var_iemgui_gn_f] == 1} {$id.gnfs.fb configure -text "helvetica" -font {helvetica 10 bold}}
-    if {[eval concat $$var_iemgui_gn_f] == 2} {$id.gnfs.fb configure -text "times" -font {times 10 bold}}
+    set $var_iemgui_gn_f $gn_f
+
+	 switch -- $gn_f {
+		  0 { set current_font $fontname}
+		  1 { set current_font "Helvetica" }
+		  2 { set current_font "Times" }
+	 }
+	 set current_font_spec "{$current_font} 12 $fontweight"
+
+	 $id.label.fontpopup_label configure -text $current_font \
+		  -font $current_font_spec
+	 $id.label.name_entry configure -font $current_font_spec
+	 $id.colors.sections.fr_bk configure -font $current_font_spec
+	 $id.colors.sections.lb_bk configure -font $current_font_spec
 }
 
 proc iemgui_lb {id} {
@@ -2399,6 +2454,9 @@ proc pdtk_iemgui_dialog {id mainheader \
 
     set vid [string trimleft $id .]
 
+	 global pd_nt
+	 global fontname fontweight
+
     set var_iemgui_wdt [concat iemgui_wdt_$vid]
     global $var_iemgui_wdt
     set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
@@ -2486,7 +2544,8 @@ proc pdtk_iemgui_dialog {id mainheader \
     set $var_iemgui_l2_f1_b0 0
 
     toplevel $id
-    wm title $id [format "%s-PROPERTIES" $mainheader]
+    wm title $id [format "%s Properties" $mainheader]
+    wm resizable $id 0 0
     wm protocol $id WM_DELETE_WINDOW [concat iemgui_cancel $id]
     
     frame $id.dim
@@ -2519,7 +2578,7 @@ proc pdtk_iemgui_dialog {id mainheader \
             $id.rng.max_lab $id.rng.max_ent -side left} }
     
     if { [eval concat $$var_iemgui_lin0_log1] >= 0 || [eval concat $$var_iemgui_loadbang] >= 0 || [eval concat $$var_iemgui_num] > 0 || [eval concat $$var_iemgui_steady] >= 0 } {
-        label $id.space1 -text "---------------------------------"
+        label $id.space1 -text ""
         pack $id.space1 -side top }
 
     frame $id.para
@@ -2548,157 +2607,189 @@ proc pdtk_iemgui_dialog {id mainheader \
         pack $id.para.dummy3 $id.para.num_lab $id.para.num_ent -side left -expand 1}
     if {[eval concat $$var_iemgui_steady] >= 0} {
         pack $id.para.dummy3 $id.para.stdy_jmp -side left -expand 1}
-    if { $snd != "nosndno" || $rcv != "norcvno" } {
-        label $id.space2 -text "---------------------------------"
-        pack $id.space2 -side top }
+
+	 frame $id.spacer0 -height 4
+	 pack $id.spacer0 -side top
     
-    frame $id.snd
-    pack $id.snd -side top
-    label $id.snd.dummy1 -text "" -width 2
-    label $id.snd.lab -text "send-symbol:" -width 12
-    entry $id.snd.ent -textvariable $var_iemgui_snd -width 20
+	 labelframe $id.s_r -borderwidth 1 -pady 4 -text "messages" \
+        -font highlight_font
+	 pack $id.s_r -side top -fill x -ipadx 5
+    frame $id.s_r.send
+    pack $id.s_r.send -side top
+    label $id.s_r.send.lab -text "   send-symbol:" -width 12  -justify right
+    entry $id.s_r.send.ent -textvariable $var_iemgui_snd -width 22
     if { $snd != "nosndno" } {
-        pack $id.snd.dummy1 $id.snd.lab $id.snd.ent -side left}
+        pack $id.s_r.send.lab $id.s_r.send.ent -side left}
     
-    frame $id.rcv
-    pack $id.rcv -side top
-    label $id.rcv.lab -text "receive-symbol:" -width 15
-    entry $id.rcv.ent -textvariable $var_iemgui_rcv -width 20
+    frame $id.s_r.receive
+    pack $id.s_r.receive -side top
+    label $id.s_r.receive.lab -text "receive-symbol:" -width 12 -justify right
+    entry $id.s_r.receive.ent -textvariable $var_iemgui_rcv -width 22
     if { $rcv != "norcvno" } {
-        pack $id.rcv.lab $id.rcv.ent -side left}
+        pack $id.s_r.receive.lab $id.s_r.receive.ent -side left}
     
-    frame $id.gnam
-    pack $id.gnam -side top
-    label $id.gnam.head -text "--------------label:---------------"
-    label $id.gnam.dummy1 -text "" -width 1
-    label $id.gnam.lab -text "name:" -width 6
-    entry $id.gnam.ent -textvariable $var_iemgui_gui_nam -width 29
-    label $id.gnam.dummy2 -text "" -width 1
-    pack $id.gnam.head -side top
-    pack $id.gnam.dummy1 $id.gnam.lab $id.gnam.ent $id.gnam.dummy2 -side left
+# get the current font name from the int given from C-space (gn_f)
+	 set current_font $fontname
+    if {[eval concat $$var_iemgui_gn_f] == 1} \
+		  { set current_font "Helvetica" }
+    if {[eval concat $$var_iemgui_gn_f] == 2} \
+		  { set current_font "Times" }
+
+	 frame $id.spacer1 -height 7
+	 pack $id.spacer1 -side top
     
-    frame $id.gnxy
-    pack $id.gnxy -side top
-    label $id.gnxy.x_lab -text "x_off:" -width 6
-    entry $id.gnxy.x_ent -textvariable $var_iemgui_gn_dx -width 5
-    label $id.gnxy.dummy1 -text " " -width 10
-    label $id.gnxy.y_lab -text "y_off:" -width 6
-    entry $id.gnxy.y_ent -textvariable $var_iemgui_gn_dy -width 5
-    pack $id.gnxy.x_lab $id.gnxy.x_ent $id.gnxy.dummy1 \
-         $id.gnxy.y_lab $id.gnxy.y_ent -side left
+	 labelframe $id.label -borderwidth 1 -text "label" -pady 4 \
+		  -font highlight_font
+	 pack $id.label -side top -fill x
+    entry $id.label.name_entry -textvariable $var_iemgui_gui_nam -width 30 \
+		  -font [list $current_font 12 $fontweight]
+    pack $id.label.name_entry -side top -expand yes -fill both -padx 5
     
-    frame $id.gnfs
-    pack $id.gnfs -side top
-    label $id.gnfs.f_lab -text "font:" -width 6
-    if {[eval concat $$var_iemgui_gn_f] == 0} {
-        button $id.gnfs.fb -text "courier" -font {courier 10 bold} -width 7 -command "iemgui_toggle_font $id" }
-    if {[eval concat $$var_iemgui_gn_f] == 1} {
-        button $id.gnfs.fb -text "helvetica" -font {helvetica 10 bold} -width 7 -command "iemgui_toggle_font $id" }
-    if {[eval concat $$var_iemgui_gn_f] == 2} {
-        button $id.gnfs.fb -text "times" -font {times 10 bold} -width 7 -command "iemgui_toggle_font $id" }
-    label $id.gnfs.dummy1 -text "" -width 1
-    label $id.gnfs.fs_lab -text "fontsize:" -width 8
-    entry $id.gnfs.fs_ent -textvariable $var_iemgui_gn_fs -width 5
-    pack $id.gnfs.f_lab $id.gnfs.fb $id.gnfs.dummy1 \
-         $id.gnfs.fs_lab $id.gnfs.fs_ent -side left
+    frame $id.label.xy -padx 27 -pady 1
+    pack $id.label.xy -side top
+    label $id.label.xy.x_lab -text "x offset" -width 6
+    entry $id.label.xy.x_entry -textvariable $var_iemgui_gn_dx -width 5
+    label $id.label.xy.dummy1 -text " " -width 2
+    label $id.label.xy.y_lab -text "y offset" -width 6
+    entry $id.label.xy.y_entry -textvariable $var_iemgui_gn_dy -width 5
+    pack $id.label.xy.x_lab $id.label.xy.x_entry $id.label.xy.dummy1 \
+         $id.label.xy.y_lab $id.label.xy.y_entry -side left -anchor e
     
-    label $id.col_head -text "--------------colors:--------------"
-    pack $id.col_head -side top
+	 label $id.label.fontpopup_label -text $current_font \
+		  -relief groove -font [list $current_font 12 $fontweight] -padx 5
+    pack $id.label.fontpopup_label -side left -anchor w -expand yes -fill x
+    label $id.label.fontsize_label -text "size" -width 4
+    entry $id.label.fontsize_entry -textvariable $var_iemgui_gn_fs -width 5
+	 pack $id.label.fontsize_entry $id.label.fontsize_label \
+		  -side right -anchor e -padx 5 -pady 5
+	 menu $id.popup
+	 $id.popup add command \
+		  -label $fontname \
+		  -font [format {{%s} 12 %s} $fontname $fontweight] \
+		  -command "iemgui_toggle_font $id 0" 
+	 $id.popup add command \
+		  -label "Helvetica" \
+		  -font [format {Helvetica 12 %s} $fontweight] \
+		  -command "iemgui_toggle_font $id 1" 
+	 $id.popup add command \
+		  -label "Times" \
+		  -font [format {Times 12 %s} $fontweight] \
+		  -command "iemgui_toggle_font $id 2" 
+	 bind $id.label.fontpopup_label <Button> \
+		  [list tk_popup $id.popup %X %Y]
+
+	 frame $id.spacer2 -height 7
+	 pack $id.spacer2 -side top
     
-    frame $id.col_select
-    pack $id.col_select -side top
-    radiobutton $id.col_select.radio0 -value 0 -variable $var_iemgui_l2_f1_b0 \
-       -text "backgd" -width 5
-    radiobutton $id.col_select.radio1 -value 1 -variable $var_iemgui_l2_f1_b0 \
-       -text "front" -width 5
-    radiobutton $id.col_select.radio2 -value 2 -variable $var_iemgui_l2_f1_b0 \
-       -text "label" -width 5
+    labelframe $id.colors -borderwidth 1 -text "colors" -font highlight_font
+    pack $id.colors -fill x -ipadx 5 -ipady 4
+    
+    frame $id.colors.select
+    pack $id.colors.select -side top
+    radiobutton $id.colors.select.radio0 -value 0 -variable \
+		  $var_iemgui_l2_f1_b0 -text "background" -width 10 -justify left
+    radiobutton $id.colors.select.radio1 -value 1 -variable \
+		  $var_iemgui_l2_f1_b0 -text "front" -width 5 -justify left
+    radiobutton $id.colors.select.radio2 -value 2 -variable \
+		  $var_iemgui_l2_f1_b0 -text "label" -width 5 -justify left
     if { [eval concat $$var_iemgui_fcol] >= 0 } {
-         pack $id.col_select.radio0 $id.col_select.radio1 $id.col_select.radio2 -side left
-       } else {pack $id.col_select.radio0 $id.col_select.radio2 -side left}
+		  pack $id.colors.select.radio0 $id.colors.select.radio1 \
+				$id.colors.select.radio2 -side left
+	 } else {
+		  pack $id.colors.select.radio0 $id.colors.select.radio2 -side left \
+	 }
     
-    frame $id.col_example_choose
-    pack $id.col_example_choose -side top
-    button $id.col_example_choose.but -text "compose color" -width 10 \
+    frame $id.colors.sections
+    pack $id.colors.sections -side top
+    button $id.colors.sections.but -text "compose color" -width 12 \
              -command "iemgui_choose_col_bkfrlb $id"
-    label $id.col_example_choose.dummy1 -text "" -width 1
+    pack $id.colors.sections.but -side left -anchor w -padx 10 -pady 5 \
+		  -expand yes -fill x
     if { [eval concat $$var_iemgui_fcol] >= 0 } {
-      button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+		  label $id.colors.sections.fr_bk -text "o=||=o" -width 6 \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
-       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] -pady 2
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
+       -font [list $current_font 12 $fontweight] -padx 2 -pady 2 -relief ridge
     } else {
-      button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+		  label $id.colors.sections.fr_bk -text "o=||=o" -width 6 \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
-       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] -pady 2}
-    button $id.col_example_choose.lb_bk -text "testlabel" -width 7 \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -font [list $current_font 12 $fontweight] -padx 2 -pady 2 -relief ridge
+	 }
+	 label $id.colors.sections.lb_bk -text "testlabel" -width 9 \
        -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
        -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
-       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] -pady 2
-    
-    pack $id.col_example_choose.but $id.col_example_choose.dummy1 \
-       $id.col_example_choose.fr_bk $id.col_example_choose.lb_bk -side left
+		 -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
+		  -font [list $current_font 12 $fontweight] -padx 2 -pady 2 -relief ridge
+    pack $id.colors.sections.lb_bk $id.colors.sections.fr_bk \
+		  -side right -anchor e -expand yes -fill both -pady 7
+
+# color scheme by Mary Ann Benedetto http://piR2.org
+    frame $id.colors.r1
+    pack $id.colors.r1 -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9} \
+		  hexcol { 0xFFFFFF 0xDFDFDF 0xBBBBBB 0xFFC7C6 0xFFE3C6 \
+							0xFEFFC6 0xC6FFC7 0xc6FEFF 0xC7C6FF 0xE3C6FF } \
+		  {
+				label $id.colors.r1.c$i -background [format "#%6.6x" $hexcol] \
+					 -activebackground [format "#%6.6x" $hexcol] -relief ridge \
+					 -padx 7 -pady 0
+				bind $id.colors.r1.c$i <Button> [format "iemgui_preset_col %s %d" $id $hexcol] 
+		  }
+    pack $id.colors.r1.c0 $id.colors.r1.c1 $id.colors.r1.c2 $id.colors.r1.c3 \
+		  $id.colors.r1.c4 $id.colors.r1.c5 $id.colors.r1.c6 $id.colors.r1.c7 \
+		  $id.colors.r1.c8 $id.colors.r1.c9 -side left
     
-    label $id.space3 -text "------or click color preset:-------"
-    pack $id.space3 -side top
+    frame $id.colors.r2
+    pack $id.colors.r2 -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9 } \
+		  hexcol { 0x9F9F9F 0x7C7C7C 0x606060 0xFF0400 0xFF8300 \
+							0xFAFF00 0x00FF04 0x00FAFF 0x0400FF 0x9C00FF } \
+		  {
+				label $id.colors.r2.c$i -background [format "#%6.6x" $hexcol] \
+					 -activebackground [format "#%6.6x" $hexcol] -relief ridge \
+					 -padx 7 -pady 0
+				bind  $id.colors.r2.c$i <Button> \
+					 [format "iemgui_preset_col %s %d" $id $hexcol] 
+		  }
+    pack $id.colors.r2.c0 $id.colors.r2.c1 $id.colors.r2.c2 $id.colors.r2.c3 \
+		  $id.colors.r2.c4 $id.colors.r2.c5 $id.colors.r2.c6 $id.colors.r2.c7 \
+		  $id.colors.r2.c8 $id.colors.r2.c9 -side left
     
-    frame $id.bcol
-    pack $id.bcol -side top
-    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 16579836 14737632 12369084 \
-      16572640 16572608 16579784 14220504 14220540 14476540 16308476 } {
-        button $id.bcol.c$i -background [format "#%6.6x" $hexcol] \
-            -activebackground [format "#%6.6x" $hexcol] \
-            -font {courier 2 normal} -padx 7 -pady 6 \
-            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
-    pack $id.bcol.c0 $id.bcol.c1 $id.bcol.c2 $id.bcol.c3 $id.bcol.c4 \
-        $id.bcol.c5 $id.bcol.c6 $id.bcol.c7 $id.bcol.c8 $id.bcol.c9 -side left
+    frame $id.colors.r3
+    pack $id.colors.r3 -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9 } \
+		  hexcol { 0x404040 0x202020 0x000000 0x551312 0x553512 \
+							0x535512 0x0F4710 0x0E4345 0x131255 0x2F004D } \
+		  {
+				label $id.colors.r3.c$i -background [format "#%6.6x" $hexcol] \
+					 -activebackground [format "#%6.6x" $hexcol] -relief ridge \
+					 -padx 7 -pady 0
+				bind  $id.colors.r3.c$i <Button> \
+					 [format "iemgui_preset_col %s %d" $id $hexcol] 
+		  }
+    pack $id.colors.r3.c0 $id.colors.r3.c1 $id.colors.r3.c2 $id.colors.r3.c3 \
+		  $id.colors.r3.c4 $id.colors.r3.c5 $id.colors.r3.c6 $id.colors.r3.c7 \
+		  $id.colors.r3.c8 $id.colors.r3.c9 -side left
     
-    frame $id.fcol
-    pack $id.fcol -side top
-    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 10526880 8158332 6316128 \
-      16525352 16559172 15263784 1370132 2684148 3952892 16003312 } {
-        button $id.fcol.c$i -background [format "#%6.6x" $hexcol] \
-            -activebackground [format "#%6.6x" $hexcol] \
-            -font {courier 2 normal} -padx 7 -pady 6 \
-            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
-    pack $id.fcol.c0 $id.fcol.c1 $id.fcol.c2 $id.fcol.c3 $id.fcol.c4 \
-        $id.fcol.c5 $id.fcol.c6 $id.fcol.c7 $id.fcol.c8 $id.fcol.c9 -side left
-    
-    frame $id.lcol
-    pack $id.lcol -side top
-    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 4210752 2105376 0 \
-      9177096 5779456 7874580 2641940 17488 5256 5767248 } {
-        button $id.lcol.c$i -background [format "#%6.6x" $hexcol] \
-            -activebackground [format "#%6.6x" $hexcol] \
-            -font {courier 2 normal} -padx 7 -pady 6 \
-            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
-    pack $id.lcol.c0 $id.lcol.c1 $id.lcol.c2 $id.lcol.c3 $id.lcol.c4 \
-        $id.lcol.c5 $id.lcol.c6 $id.lcol.c7 $id.lcol.c8 $id.lcol.c9 -side left
-    
-    
-    label $id.space4 -text "---------------------------------"
-    pack $id.space4 -side top
-    
-    frame $id.cao
+    frame $id.cao -pady 10
     pack $id.cao -side top
     button $id.cao.cancel -text {Cancel} -width 6 \
         -command "iemgui_cancel $id"
     label $id.cao.dummy1 -text "" -width 3
-    button $id.cao.apply -text {Apply} -width 6 \
-        -command "iemgui_apply $id"
+	 button $id.cao.apply -text {Apply} -width 6 -command "iemgui_apply $id"
     label $id.cao.dummy2 -text "" -width 3
     button $id.cao.ok -text {OK} -width 6 \
         -command "iemgui_ok $id"
-    pack $id.cao.cancel $id.cao.dummy1 \
-        $id.cao.apply $id.cao.dummy2 \
-        $id.cao.ok -side left
     
-    label $id.space5 -text ""
-    pack $id.space5 -side top
+    pack $id.cao.cancel $id.cao.dummy1 -side left
+	 pack $id.cao.apply $id.cao.dummy2 -side left
+    pack $id.cao.ok -side left
 
     if {[info tclversion] < 8.4} {
         bind $id <Key-Tab> {tkTabToWindow [tk_focusNext %W]}
@@ -2713,24 +2804,24 @@ proc pdtk_iemgui_dialog {id mainheader \
     bind $id.rng.min_ent <KeyPress-Return> [concat iemgui_ok $id]
     bind $id.rng.max_ent <KeyPress-Return> [concat iemgui_ok $id]
     bind $id.para.num_ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.snd.ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.rcv.ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.gnam.ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.gnxy.x_ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.gnxy.y_ent <KeyPress-Return> [concat iemgui_ok $id]
-    bind $id.gnfs.fs_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.s_r.send.ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.s_r.receive.ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.label.name_entry <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.label.xy.x_entry <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.label.xy.y_entry <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.label.fontsize_entry <KeyPress-Return> [concat iemgui_ok $id]
     bind $id.cao.ok <KeyPress-Return> [concat iemgui_ok $id]
     pdtk_standardkeybindings $id.dim.w_ent
     pdtk_standardkeybindings $id.dim.h_ent
     pdtk_standardkeybindings $id.rng.min_ent
     pdtk_standardkeybindings $id.rng.max_ent
     pdtk_standardkeybindings $id.para.num_ent
-    pdtk_standardkeybindings $id.snd.ent
-    pdtk_standardkeybindings $id.rcv.ent
-    pdtk_standardkeybindings $id.gnam.ent
-    pdtk_standardkeybindings $id.gnxy.x_ent
-    pdtk_standardkeybindings $id.gnxy.y_ent
-    pdtk_standardkeybindings $id.gnfs.fs_ent
+    pdtk_standardkeybindings $id.s_r.send.ent
+    pdtk_standardkeybindings $id.s_r.receive.ent
+    pdtk_standardkeybindings $id.label.name_entry
+    pdtk_standardkeybindings $id.label.xy.x_entry
+    pdtk_standardkeybindings $id.label.xy.y_entry
+    pdtk_standardkeybindings $id.label.fontsize_entry
     pdtk_standardkeybindings $id.cao.ok
     
     $id.dim.w_ent select from 0
@@ -2808,6 +2899,7 @@ proc pdtk_array_dialog {id name n flags newone} {
 
     toplevel $id
     wm title $id {array}
+    wm resizable $id 0 0
     wm protocol $id WM_DELETE_WINDOW [concat array_cancel $id]
 
     frame $id.name
@@ -3265,18 +3357,21 @@ proc pdtk_pd_ctrlkey {name key shift} {
 # seven "useful" font sizes.
 
 # tb: user defined typefaces
-proc pdtk_pd_startup {version apilist midiapilist fontname} {
+proc pdtk_pd_startup {version apilist midiapilist fontname_from_pd fontweight_from_pd} {
 #    puts stderr [concat $version $apilist $fontname]
-    global pd_myversion pd_apilist pd_midiapilist
+    global pd_myversion pd_apilist pd_midiapilist pd_nt
     set pd_myversion $version
     set pd_apilist $apilist
     set pd_midiapilist $midiapilist
+	 global fontname fontweight
+	 set fontname $fontname_from_pd
+	 set fontweight $fontweight_from_pd
     global pd_fontlist
     set pd_fontlist {}
 
     set fontlist ""
     foreach i {8 9 10 12 14 16 18 24 30 36} {
-       set font [concat $fontname -$i bold]
+       set font [format {{%s} %d %s} $fontname_from_pd $i $fontweight_from_pd]
        set pd_fontlist [linsert $pd_fontlist 100000 $font] 
        set width0 [font measure  $font x]
        set height0 [lindex [font metrics $font] 5]
@@ -3523,8 +3618,12 @@ proc audio_popup_action {buttonname varname devlist index} {
 
 # create a popup menu
 proc audio_popup {name buttonname varname devlist} {
+    global pd_nt
     if [winfo exists $name.popup] {destroy $name.popup}
     menu $name.popup -tearoff false
+    if {$pd_nt == 1} {
+	$name.popup configure -font menuFont
+    }
 #    puts stderr [concat $devlist ]
     for {set x 0} {$x<[llength $devlist]} {incr x} {
         $name.popup add command -label [lindex $devlist $x] \
@@ -3805,8 +3904,12 @@ proc midi_popup_action {buttonname varname devlist index} {
 
 # create a popup menu
 proc midi_popup {name buttonname varname devlist} {
+    global pd_nt
     if [winfo exists $name.popup] {destroy $name.popup}
     menu $name.popup -tearoff false
+    if {$pd_nt == 1} {
+	$name.popup configure -font menuFont
+    }
 #    puts stderr [concat $devlist ]
     for {set x 0} {$x<[llength $devlist]} {incr x} {
         $name.popup add command -label [lindex $devlist $x] \
diff --git a/src/u_main.tk.orig b/src/u_main.tk.orig
new file mode 100644
index 000000000..2a736ca5d
--- /dev/null
+++ b/src/u_main.tk.orig
@@ -0,0 +1,4252 @@
+#!/usr/bin/wish
+
+# set pd_nt (bad name) 0 for unix, 1 for microsoft, and 2 for Mac OSX.
+if { $tcl_platform(platform) == "windows" }  {
+         set pd_nt 1
+} elseif { $tcl_platform(os) == "Darwin" } {  
+         set pd_nt 2
+} else { 
+         set pd_nt 0
+}        
+
+# Copyright (c) 1997-1999 Miller Puckette.
+# For information on usage and redistribution, and for a DISCLAIMER OF ALL
+# WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+# changed by Thomas Musil 09.2001
+# between "pdtk_graph_dialog -- dialog window for graphs"
+# and "pdtk_array_dialog -- dialog window for arrays"
+# a new dialogbox was inserted, named:
+# "pdtk_iemgui_dialog -- dialog window for iem guis"
+#
+# all this changes are labeled with #######iemlib##########
+
+# Tearoff is set to true by default:
+set pd_tearoff 1
+
+# jsarlo
+set pd_array_listview_pagesize 1000
+set pd_array_listview_id(0) 0
+set pd_array_listview_entry(0) 0
+set pd_array_listview_page(0) 0
+# end jsarlo
+
+if {$pd_nt == 1} {
+    global pd_guidir
+    global pd_tearoff
+    set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]]
+    regsub -all \\\\ $pd_gui2 / pd_gui3
+    set pd_guidir $pd_gui3/..
+    load $pd_guidir/bin/pdtcl.dll
+    set pd_tearoff 1
+}
+
+if {$pd_nt == 2} {
+# turn on James Tittle II's fast drawing
+    set tk::mac::useCGDrawing 1
+    # set minimum line size for anti-aliasing.  If set to 1 or 0, then every
+    # line will be anti-aliased.  While this makes connections and circles in
+    # [bng] and such look really good, it makes boxes and messages look out of
+    # focus.  Setting this to 2 makes it so the thick audio rate connections
+    # are anti-aliased.  <hans@at.or.at> 2005-06-09
+    set tk::mac::CGAntialiasLimit 2
+    global pd_guidir
+    global pd_tearoff
+    set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
+    set pd_guidir $pd_gui2/..
+    load $pd_guidir/bin/libPdTcl.dylib
+    set pd_tearoff 0
+    global pd_macready
+    set pd_macready 0
+    global pd_macdropped
+    set pd_macdropped ""
+    # tk::mac::OpenDocument is called with the filenames put into the 
+    # var args whenever docs are either dropped on the Pd.app icon or 
+    # opened from the Finder.
+    # It uses menu_doc_open so it can handles numerous file types.
+    proc tk::mac::OpenDocument {args} {
+        global pd_macready pd_macdropped
+        foreach file $args {
+            if {$pd_macready != 0} {
+                pd [concat pd open [pdtk_enquote [file tail $file]] \
+                    [pdtk_enquote  [file dirname $file]] \;]
+                    menu_doc_open [file dirname $file] [file tail $file]
+            } else {
+                set pd_macdropped $args
+            }
+        }
+    }
+}
+
+# hack so you can easily test-run this script in linux... define pd_guidir
+# (which is normally defined at startup in pd under linux...)
+
+if {$pd_nt == 0} {
+    if {! [info exists pd_guidir]} {
+        global pd_guidir
+        puts stderr {setting pd_guidir to '.'}
+        set pd_guidir .
+    }
+}
+
+set pd_deffont {courier 12 bold}
+
+set help_top_directory $pd_guidir/doc
+
+# it's unfortunate but we seem to have to turn off global bindings
+# for Text objects to get control-s and control-t to do what we want for
+# "text" dialogs below.  Also we have to get rid of tab's changing the focus.
+
+bind all <Key-Tab> ""
+bind all <<PrevWindow>> ""
+bind Text <Control-t> {}
+bind Text <Control-s> {}
+# puts stderr [bind all]
+
+################## set up main window #########################
+# the menus are instantiated here for the main window
+# for the patch windows, they are created by pdtk_canvas_new
+menu .mbar
+canvas .dummy -height 2p -width 6c
+
+frame .controls
+pack .controls .dummy -side top -fill x
+menu .mbar.file -tearoff $pd_tearoff
+.mbar add cascade -label "File" -menu .mbar.file
+menu .mbar.find -tearoff $pd_tearoff
+.mbar add cascade -label "Find" -menu .mbar.find
+menu .mbar.windows -postcommand [concat pdtk_fixwindowmenu] -tearoff $pd_tearoff
+menu .mbar.audio -tearoff $pd_tearoff
+if {$pd_nt != 2} {
+    .mbar add cascade -label "Windows" -menu .mbar.windows
+    .mbar add cascade -label "Media" -menu .mbar.audio
+    menu .mbar.help -tearoff $pd_tearoff
+    .mbar add cascade -label "Help" -menu .mbar.help
+} else {
+    menu .mbar.apple -tearoff 0
+    .mbar add cascade -label "Apple" -menu .mbar.apple 
+# arrange menus according to Apple HIG
+    .mbar add cascade -label "Media" -menu .mbar.audio
+    .mbar add cascade -label "Window" -menu .mbar.windows
+    menu .mbar.help -tearoff $pd_tearoff
+    .mbar add cascade -label "Help" -menu .mbar.help
+}
+
+set ctrls_audio_on 0
+set ctrls_meter_on 0
+set ctrls_inlevel 0
+set ctrls_outlevel 0
+
+frame .controls.switches
+checkbutton .controls.switches.audiobutton -text {compute audio} \
+    -variable ctrls_audio_on \
+    -anchor w \
+    -command {pd [concat pd dsp $ctrls_audio_on \;]}
+
+checkbutton .controls.switches.meterbutton -text {peak meters} \
+    -variable ctrls_meter_on \
+    -anchor w \
+    -command {pd [concat pd meters $ctrls_meter_on \;]}
+
+pack .controls.switches.audiobutton .controls.switches.meterbutton -side top
+
+frame .controls.inout
+frame .controls.inout.in
+label .controls.inout.in.label -text IN
+entry .controls.inout.in.level -textvariable ctrls_inlevel -width 3
+button .controls.inout.in.clip -text {CLIP} -state disabled
+pack .controls.inout.in.label .controls.inout.in.level \
+      .controls.inout.in.clip -side top -pady 2
+
+frame .controls.inout.out
+label .controls.inout.out.label -text OUT
+entry .controls.inout.out.level -textvariable ctrls_outlevel -width 3
+button .controls.inout.out.clip -text {CLIP} -state disabled
+pack .controls.inout.out.label .controls.inout.out.level \
+      .controls.inout.out.clip -side top -pady 2
+
+button .controls.dio -text "DIO\nerrors" \
+    -command {pd [concat pd audiostatus \;]}
+
+pack .controls.inout.in .controls.inout.out -side left -padx 6
+pack .controls.inout -side left -padx 14
+pack .controls.switches -side right
+pack .controls.dio -side right -padx 20
+
+
+frame .printout
+text .printout.text -relief raised -bd 2 -font -*-courier-bold--normal--12-* \
+    -yscrollcommand ".printout.scroll set" -width 80
+# .printout.text insert end "\n\n\n\n\n\n\n\n\n\n"
+scrollbar .printout.scroll -command ".printout.text yview"
+pack .printout.scroll -side right -fill y
+pack .printout.text -side left -fill both -expand 1
+pack .printout -side bottom -fill both -expand 1
+
+proc pdtk_post {stuff} {
+    .printout.text insert end $stuff
+    .printout.text yview end-2char
+}
+
+proc pdtk_standardkeybindings {id} {
+    global pd_nt
+    bind $id <Control-Key> {pdtk_pd_ctrlkey %W %K 0}
+    bind $id <Control-Shift-Key> {pdtk_pd_ctrlkey %W %K 1}
+    if {$pd_nt == 2} {
+        bind $id <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
+        bind $id <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
+    }
+}
+
+pdtk_standardkeybindings .
+
+wm title . "Pd"
+. configure -menu .mbar -width 200 -height 150
+
+# Intercept closing the main pd window: MP 20060413:
+wm protocol . WM_DELETE_WINDOW menu_quit
+
+############### set up global variables ################################
+
+set untitled_number 1
+set untitled_directory [pwd]
+set saveas_client doggy
+set pd_opendir $untitled_directory
+set pd_savedir $untitled_directory
+set pd_undoaction no
+set pd_redoaction no
+set pd_undocanvas no
+
+################ utility functions #########################
+
+# enquote a string to send it to a tcl function
+proc pdtk_enquote {x} {
+    set foo [string map {"," "" ";" "" \" ""} $x]
+    set foo2 [string map {" " "\\ "} $foo]
+    concat $foo2
+}
+
+#enquote a string to send it to Pd.  Blow off semi and comma; alias spaces
+#we also blow off "{", "}", "\" because they'll just cause bad trouble later.
+proc pdtk_unspace {x} {
+    set y [string map {" " "_" ";" "" "," "" "{" "" "}" "" "\\" ""} $x]
+    if {$y == ""} {set y "empty"}
+    concat $y
+}
+
+#enquote a string for preferences (command strings etc.)
+proc pdtk_encodedialog {x} {
+    concat +[string map {" " "+_" "$" "+d" ";" "+s" "," "+c" "+" "++"} $x]
+}
+
+proc pdtk_debug {x} {
+    tk_messageBox -message $x -type ok
+}
+
+proc pdtk_watchdog {} {
+    pd [concat pd watchdog \;]
+    after 2000 {pdtk_watchdog}
+}
+
+proc pdtk_ping {} {
+    pd [concat pd ping \;]
+}
+
+##### routine to ask user if OK and, if so, send a message on to Pd ######
+proc pdtk_check {x message default} {
+    set answer [tk_messageBox \-message $x \-type yesno -default $default \
+        -icon question]
+    if {! [string compare $answer yes]}  {pd $message}
+}
+
+set menu_windowlist {} 
+
+proc pdtk_fixwindowmenu {} {
+    global menu_windowlist
+    .mbar.windows delete 0 end
+    foreach i $menu_windowlist {
+        .mbar.windows add command -label [lindex $i 0] \
+            -command [concat menu_domenuwindow [lindex $i 1]]
+        menu_fixwindowmenu [lindex $i 1]
+    }
+}
+
+####### Odd little function to make better Mac accelerators #####
+
+proc accel_munge {acc} {
+    global pd_nt
+
+    if {$pd_nt == 2} {
+        if [string is upper [string index $acc end]] {
+            return [format "%s%s" "Shift+" \
+                        [string toupper [string map {Ctrl Meta} $acc] end]]
+        } else {
+            return [string toupper [string map {Ctrl Meta} $acc] end]
+        }
+    } else {
+        return $acc
+    }
+}
+
+
+
+###############  the "New" menu command  ########################
+proc menu_new {} {
+    global untitled_number
+    global untitled_directory
+    pd [concat pd filename Untitled-$untitled_number $untitled_directory \;]
+    pd {
+        #N canvas;
+        #X pop 1;
+    }
+    set untitled_number [expr $untitled_number + 1]
+}
+
+################## the "Open" menu command #########################
+
+proc menu_open {} {
+    global pd_opendir
+    set filename [tk_getOpenFile -defaultextension .pd \
+        -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} \
+        -initialdir $pd_opendir]
+    if {$filename != ""} {open_file $filename}
+}
+
+proc open_file {filename} {
+    global pd_opendir
+    set directory [string range $filename 0 [expr [string last / $filename] - 1]]
+    set pd_opendir $directory
+    set basename [string range $filename [expr [string last / $filename] + 1] end]
+    if {[string last .pd $filename] >= 0} {
+        pd "pd open [pdtk_enquote $basename] [pdtk_enquote $directory] ;"
+    }
+}
+
+catch {
+    package require tkdnd
+    dnd bindtarget . text/uri-list <Drop> {
+        foreach file %D {open_file $file}
+    }
+}
+
+################## the "Message" menu command #########################
+proc menu_send {} {
+    toplevel .sendpanel
+    entry .sendpanel.entry -textvariable send_textvariable
+    pack .sendpanel.entry -side bottom -fill both -ipadx 100
+    .sendpanel.entry select from 0
+    .sendpanel.entry select adjust end
+    bind .sendpanel.entry <KeyPress-Return> {
+        pd [concat $send_textvariable \;]
+    }
+    pdtk_standardkeybindings .sendpanel.entry
+    focus .sendpanel.entry
+}
+
+################## the "Quit" menu command #########################
+proc menu_really_quit {} {pd {pd quit;}}
+
+proc menu_quit {} {pd {pd verifyquit;}}
+
+######### the "Pd" menu command, which puts the Pd window on top ########
+proc menu_pop_pd {} {raise .}
+
+######### the "audio" menu command  ###############
+proc menu_audio {flag} {pd [concat pd dsp $flag \;]}
+
+######### the "documentation" menu command  ###############
+
+set doc_number 1
+
+# open text docs in a Pd window
+proc menu_opentext {filename} {
+    global doc_number
+    global pd_guidir
+    global pd_myversion
+    set name [format ".help%d" $doc_number]
+    toplevel $name
+    text $name.text -relief raised -bd 2 -font -*-times-regular--normal--14-* \
+        -yscrollcommand "$name.scroll set" -background white
+    scrollbar $name.scroll -command "$name.text yview"
+    pack $name.scroll -side right -fill y
+    pack $name.text -side left -fill both -expand 1
+    
+    set f [open $filename]
+    while {![eof $f]} {
+        set bigstring [read $f 1000]
+        regsub -all PD_BASEDIR $bigstring $pd_guidir bigstring2
+        regsub -all PD_VERSION $bigstring2 $pd_myversion bigstring3
+        $name.text insert end $bigstring3
+    }
+    close $f
+    set doc_number [expr $doc_number + 1] 
+}
+
+# open HTML docs from the menu using the OS-default HTML viewer
+proc menu_openhtml {filename} {
+    global pd_nt         
+
+    if {$pd_nt == 0} {
+        exec sh -c \
+            [format "firefox file:%s || mozilla file:%s " \
+                $filename $filename] &
+    } elseif {$pd_nt == 2} {
+        puts stderr [format "open %s" $filename]
+            exec sh -c [format "open %s" $filename]
+    } else {
+        exec rundll32 url.dll,FileProtocolHandler \
+            [format "file://%s" $filename] &
+    }
+}
+
+proc menu_doc_open {subdir basename} {
+    global pd_guidir
+ 
+    set dirname $pd_guidir/$subdir
+
+    if {[regexp ".*\.(txt|c)$" $basename]} {
+        menu_opentext $dirname/$basename
+    } elseif {[regexp ".*\.html?$" $basename]} {
+                  menu_openhtml $dirname/$basename
+    } else {
+        pd [concat pd open [pdtk_enquote $basename] \
+                [pdtk_enquote $dirname] \;]
+    }
+}
+
+
+################## help browser and support functions #########################
+proc menu_doc_browser {dir} {
+	global .mbar
+	if {![file isdirectory $dir]} {
+		puts stderr "menu_doc_browser non-directory $dir\n"
+	}
+	if { [winfo exists .help_browser.frame] } {
+		raise .help_browser
+	} else {
+		toplevel .help_browser -menu .mbar
+		wm title .help_browser "Pd Documentation Browser"
+		frame .help_browser.frame
+		pack .help_browser.frame -side top -fill both
+		doc_make_listbox .help_browser.frame $dir 0
+         }
+    }
+
+proc doc_make_listbox {base dir count} {
+	# check for [file readable]?
+	#if { [info tclversion] >= 8.5 } {
+		# requires Tcl 8.5 but probably deals with special chars better
+#		destroy {expand}[lrange [winfo children $base] [expr {2 * $count}] end]
+	#} else {
+		if { [catch { eval destroy [lrange [winfo children $base] \
+										[expr { 2 * $count }] end] } \
+				  errorMessage] } {
+			puts stderr "doc_make_listbox: error listing $dir\n"
+		}
+	#}
+	# exportselection 0 looks good, but selection gets easily out-of-sync
+	set current_listbox [listbox "[set b "$base.listbox$count"]-list" -yscrollcommand \
+							 [list "$b-scroll" set] -height 20 -exportselection 0]
+	pack $current_listbox [scrollbar "$b-scroll" -command [list $current_listbox yview]] \
+		-side left -expand 1 -fill y -anchor w
+	foreach item [concat [lsort -dictionary [glob -directory $dir -nocomplain -types {d} -- *]] \
+					  [lsort -dictionary [glob -directory $dir -nocomplain -types {f} -- *]]]  {
+		$current_listbox insert end "[file tail $item][expr {[file isdirectory $item] ? {/} : {}}]"
+	}
+	bind $current_listbox <Button-1> [list doc_navigate $dir $count %W %x %y]
+	bind $current_listbox <Double-Button-1> [list doc_double_button $dir $count %W %x %y]
+}
+
+proc doc_navigate {dir count width x y} {
+	if {[set newdir [$width get [$width index "@$x,$y"]]] eq {}} {
+		return
+	}
+	set dir_to_open [file join $dir $newdir]
+	if {[file isdirectory $dir_to_open]} {
+		doc_make_listbox [winfo parent $width] $dir_to_open [incr count]
+	}
+}
+
+proc doc_double_button {dir count width x y} {
+	global pd_guidir
+	if {[set newdir [$width get [$width index "@$x,$y"]]] eq {}} {
+		return
+	}
+	set dir_to_open [file join $dir $newdir]
+	if {[file isdirectory $dir_to_open]} {
+		 doc_navigate $dir $count $width $x $y
+	} else {
+		regsub -- $pd_guidir [file dirname $dir_to_open] "" subdir
+		set file [file tail $dir_to_open]
+		if { [catch {menu_doc_open $subdir $file} fid] } {
+			puts stderr "Could not open $pd_guidir/$subdir/$file\n"
+		}
+		return; 
+	}
+}
+
+############# routine to add media, help, and apple menu items ###############
+
+proc menu_addstd {mbar} {
+    global pd_apilist pd_midiapilist pd_nt pd_tearoff
+#          the "Audio" menu
+    $mbar.audio add command -label {audio ON} -accelerator [accel_munge "Ctrl+/"] \
+        -command {menu_audio 1} 
+    $mbar.audio add command -label {audio OFF} -accelerator [accel_munge "Ctrl+."] \
+        -command {menu_audio 0} 
+    for {set x 0} {$x<[llength $pd_apilist]} {incr x} {
+        $mbar.audio add radiobutton -label [lindex [lindex $pd_apilist $x] 0] \
+            -command {menu_audio 0} -variable pd_whichapi \
+                -value [lindex [lindex $pd_apilist $x] 1]\
+                -command {pd [concat pd audio-setapi $pd_whichapi \;]}
+    }
+    for {set x 0} {$x<[llength $pd_midiapilist]} {incr x} {
+        $mbar.audio add radiobutton -label [lindex [lindex $pd_midiapilist $x] 0] \
+            -command {menu_midi 0} -variable pd_whichmidiapi \
+                -value [lindex [lindex $pd_midiapilist $x] 1]\
+                -command {pd [concat pd midi-setapi $pd_whichmidiapi \;]}
+    }
+         if {$pd_nt != 2} {
+    $mbar.audio add command -label {Audio settings...} \
+        -command {pd pd audio-properties \;}
+    $mbar.audio add command -label {MIDI settings...} \
+        -command {pd pd midi-properties \;}
+         }
+         
+    $mbar.audio add command -label {Test Audio and MIDI} \
+        -command {menu_doc_open doc/7.stuff/tools testtone.pd} 
+    $mbar.audio add command -label {Load Meter} \
+        -command {menu_doc_open doc/7.stuff/tools load-meter.pd} 
+
+#       the MacOS X app menu
+
+# The menu on the main menubar named $whatever.apple while be treated
+# as a special menu on MacOS X.  Tcl/Tk assigns the $whatever.apple menu
+# to the app-specific menu in MacOS X that is named after the app,
+# so in our case, the Pd menu.  <hans@at.or.at>
+# See SPECIAL MENUS IN MENUBARS http://www.tcl.tk/man/tcl8.4/TkCmd/menu.htm
+         if {$pd_nt == 2} {
+                  $mbar.apple add command -label "About Pd..." -command \
+                                {menu_doc_open doc/1.manual 1.introduction.txt} 
+                  menu $mbar.apple.preferences -tearoff 0
+                  $mbar.apple add cascade -label "Preferences" -menu $mbar.apple.preferences
+                  $mbar.apple.preferences add command -label "Path..." \
+                                -command {pd pd start-path-dialog \;}
+                  $mbar.apple.preferences add command -label "Startup..." \
+                                -command {pd pd start-startup-dialog \;}
+                  $mbar.apple.preferences add command -label "Audio Settings..." \
+                                -command {pd pd audio-properties \;}
+                  $mbar.apple.preferences add command -label "MIDI settings..." \
+                                -command {pd pd midi-properties \;}
+         }
+
+
+        # the "Help" menu
+    if {$pd_nt != 2} {
+        $mbar.help add command -label {About Pd} \
+            -command {menu_doc_open doc/1.manual 1.introduction.txt} 
+    }
+    $mbar.help add command -label {Html ...} \
+        -command {menu_doc_open doc/1.manual index.htm} 
+    $mbar.help add command -label {Browser ...} \
+        -command {menu_doc_browser $help_top_directory} 
+}
+
+#################### the "File" menu for the Pd window ##############
+
+.mbar.file add command -label New -command {menu_new} \
+    -accelerator [accel_munge "Ctrl+n"]
+.mbar.file add command -label Open -command {menu_open} \
+    -accelerator [accel_munge "Ctrl+o"]
+.mbar.file add  separator
+.mbar.file add command -label Message -command {menu_send} \
+    -accelerator [accel_munge "Ctrl+m"]
+# On MacOS X, these are in the standard HIG locations
+# i.e. the Preferences menu under "Pd"
+if {$pd_nt != 2} {
+.mbar.file add command -label Path... \
+    -command {pd pd start-path-dialog \;}
+.mbar.file add command -label Startup... \
+    -command {pd pd start-startup-dialog \;}
+}
+.mbar.file add  separator
+.mbar.file add command -label Quit -command {menu_quit} \
+    -accelerator [accel_munge "Ctrl+q"]
+
+#################### the "Find" menu for the Pd window ##############
+.mbar.find add command -label {Find last error} -command {menu_finderror} 
+
+###########  functions for menu functions on document windows ########
+
+proc menu_save {name} {
+    pdtk_canvas_checkgeometry $name
+    pd [concat $name menusave \;]
+}
+
+proc menu_saveas {name} {
+    pdtk_canvas_checkgeometry $name
+    pd [concat $name menusaveas \;]
+}
+
+proc menu_print {name} {
+    set filename [tk_getSaveFile -initialfile pd.ps \
+       -defaultextension .ps \
+       -filetypes { {{postscript} {.ps}} }]
+
+    if {$filename != ""} {
+        $name.c postscript -file $filename 
+    }
+}
+
+proc menu_close {name} {
+    pdtk_canvas_checkgeometry $name
+    pd [concat $name menuclose 0 \;]
+}
+
+proc menu_really_close {name} {
+    pdtk_canvas_checkgeometry $name
+    pd [concat $name menuclose 1 \;]
+}
+
+proc menu_undo {name} {
+    global pd_undoaction
+    global pd_redoaction
+    global pd_undocanvas
+    if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
+        pd [concat $name undo \;]
+    }
+}
+
+proc menu_redo {name} {
+    global pd_undoaction
+    global pd_redoaction
+    global pd_undocanvas
+    if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
+        pd [concat $name redo \;]
+    }
+}
+
+proc menu_cut {name} {
+    pd [concat $name cut \;]
+}
+
+proc menu_copy {name} {
+    pd [concat $name copy \;]
+}
+
+proc menu_paste {name} {
+    pd [concat $name paste \;]
+}
+
+proc menu_duplicate {name} {
+    pd [concat $name duplicate \;]
+}
+
+proc menu_selectall {name} {
+    pd [concat $name selectall \;]
+}
+
+proc menu_texteditor {name} {
+    pd [concat $name texteditor \;]
+}
+
+proc menu_font {name} {
+    pd [concat $name menufont \;]
+}
+
+proc menu_tidyup {name} {
+    pd [concat $name tidy \;]
+}
+
+proc menu_editmode {name} {
+    pd [concat $name editmode 0 \;]
+}
+
+proc menu_object {name accel} {
+    pd [concat $name obj $accel \;]
+}
+
+proc menu_message {name accel} {
+    pd [concat $name msg $accel \;]
+}
+
+proc menu_floatatom {name accel} {
+    pd [concat $name floatatom $accel \;]
+}
+
+proc menu_symbolatom {name accel} {
+    pd [concat $name symbolatom $accel \;]
+}
+
+proc menu_comment {name accel} {
+    pd [concat $name text $accel \;]
+}
+
+proc menu_graph {name} {
+    pd [concat $name graph \;]
+}
+
+proc menu_array {name} {
+    pd [concat $name menuarray \;]
+}
+
+############iemlib##################
+proc menu_bng {name accel} {
+    pd [concat $name bng $accel \;]
+}
+
+proc menu_toggle {name accel} {
+    pd [concat $name toggle $accel \;]
+}
+
+proc menu_numbox {name accel} {
+    pd [concat $name numbox $accel \;]
+}
+
+proc menu_vslider {name accel} {
+    pd [concat $name vslider $accel \;]
+}
+
+proc menu_hslider {name accel} {
+    pd [concat $name hslider $accel \;]
+}
+
+proc menu_hradio {name accel} {
+    pd [concat $name hradio $accel \;]
+}
+
+proc menu_vradio {name accel} {
+    pd [concat $name vradio $accel \;]
+}
+
+proc menu_vumeter {name accel} {
+    pd [concat $name vumeter $accel \;]
+}
+
+proc menu_mycnv {name accel} {
+    pd [concat $name mycnv $accel \;]
+}
+
+############iemlib##################
+
+# correct edit menu, enabling or disabling undo/redo
+# LATER also cut/copy/paste
+proc menu_fixeditmenu {name} {
+    global pd_undoaction
+    global pd_redoaction
+    global pd_undocanvas
+#    puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction]
+    if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
+        $name.m.edit entryconfigure "Undo*" -state normal \
+            -label [concat "Undo " $pd_undoaction]
+    } else {
+        $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo"
+    }
+    if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
+        $name.m.edit entryconfigure "Redo*" -state normal\
+            -label [concat "Redo " $pd_redoaction]
+    } else {
+        $name.m.edit entryconfigure "Redo*" -state disabled
+    }
+}
+
+# message from Pd to update the currently available undo/redo action
+proc pdtk_undomenu {name undoaction redoaction} {
+    global pd_undoaction
+    global pd_redoaction
+    global pd_undocanvas
+#    puts stderr [concat pdtk_undomenu $name $undoaction $redoaction]
+    set pd_undocanvas $name
+    set pd_undoaction $undoaction
+    set pd_redoaction $redoaction
+    if {$name != "nobody"} {
+#    unpleasant way of avoiding a more unpleasant bug situation --atl 2002.11.25
+        menu_fixeditmenu $name
+    }
+}
+
+proc menu_windowparent {name} {
+    pd [concat $name findparent \;]
+}
+
+proc menu_findagain {name} {
+    pd [concat $name findagain \;]
+}
+
+proc menu_finderror {} {
+    pd [concat pd finderror \;]
+}
+
+proc menu_domenuwindow {i} {
+    raise $i
+}
+
+proc menu_fixwindowmenu {name} {
+    global menu_windowlist
+    global pd_tearoff
+    $name.m.windows add command
+    if $pd_tearoff {
+        $name.m.windows delete 4 end
+    } else {
+        $name.m.windows delete 3 end
+    }
+    foreach i $menu_windowlist {
+        $name.m.windows add command -label [lindex $i 0] \
+            -command [concat menu_domenuwindow [lindex $i 1]]
+    }
+}
+
+################## the "find" menu item ###################
+
+set find_canvas nobody
+set find_string ""
+set find_count 1
+
+proc find_apply {name} {
+    global find_string
+    global find_canvas
+    regsub -all \; $find_string " _semi_ " find_string2
+    regsub -all \, $find_string2 " _comma_ " find_string3
+#    puts stderr [concat $find_canvas find $find_string3 \
+#       \;]
+    pd [concat $find_canvas find $find_string3 \
+        \;]
+    after 50 destroy $name
+}
+
+proc find_cancel {name} {
+    after 50 destroy $name
+}
+
+proc menu_findobject {canvas} {
+    global find_string
+    global find_canvas
+    global find_count
+    
+    set name [format ".find%d" $find_count]
+    set find_count [expr $find_count + 1]
+
+    set find_canvas $canvas
+    
+    toplevel $name
+
+    label $name.label -text {find...}
+    pack $name.label -side top
+
+    entry $name.entry -textvariable find_string
+    pack $name.entry -side top
+
+    frame $name.buttonframe
+    pack $name.buttonframe -side bottom -fill x -pady 2m
+    button $name.buttonframe.cancel -text {Cancel}\
+        -command "find_cancel $name"
+    button $name.buttonframe.ok -text {OK}\
+        -command "find_apply $name"
+    pack $name.buttonframe.cancel -side left -expand 1
+    pack $name.buttonframe.ok -side left -expand 1
+    
+    $name.entry select from 0
+    $name.entry select adjust end
+    bind $name.entry <KeyPress-Return> [ concat find_apply $name]
+    pdtk_standardkeybindings $name.entry
+    focus $name.entry
+}
+
+
+############# pdtk_canvas_new -- create a new canvas ###############
+proc pdtk_canvas_new {name width height geometry editable} {
+    global pd_opendir
+    global pd_tearoff
+    global pd_nt
+    global tcl_version
+
+    toplevel $name -menu $name.m
+# slide offscreen windows into view
+    if {$tcl_version >= 8.4} {
+        set geometry [split $geometry +]
+        set i 1
+        foreach geo {width height} {
+            set screen($geo) [winfo screen$geo .]
+            if {[expr [lindex $geometry $i] + [set $geo]] > $screen($geo)} {
+                set pos($geo) [expr $screen($geo) - [set $geo]]
+                if {$pos($geo) < 0} {set pos($geo) 0}
+                lset geometry $i $pos($geo)
+            }
+            incr i
+        }
+        set geometry [join $geometry +] 
+   }
+   wm geometry $name $geometry
+   canvas $name.c -width $width -height $height -background white \
+        -yscrollcommand "$name.scrollvert set" \
+        -xscrollcommand "$name.scrollhort set" \
+        -scrollregion [concat 0 0 $width $height] 
+
+    scrollbar $name.scrollvert -command "$name.c yview"
+    scrollbar $name.scrollhort -command "$name.c xview" \
+        -orient horizontal
+
+    pack $name.scrollhort -side bottom -fill x
+    pack $name.scrollvert -side right -fill y
+    pack $name.c -side left -expand 1 -fill both
+    wm minsize $name 1 1
+    wm geometry $name $geometry
+# the file menu
+
+# The menus are instantiated here for the patch windows.
+# For the main window, they are created on load, at the 
+# top of this file.
+    menu $name.m
+    menu $name.m.file -tearoff $pd_tearoff
+    $name.m add cascade -label File -menu $name.m.file
+
+    $name.m.file add command -label New -command {menu_new} \
+        -accelerator [accel_munge "Ctrl+n"]
+
+    $name.m.file add command -label Open -command {menu_open} \
+        -accelerator [accel_munge "Ctrl+o"]
+
+    $name.m.file add  separator
+    $name.m.file add command -label Message -command {menu_send} \
+        -accelerator [accel_munge "Ctrl+m"]
+
+         # arrange menus according to Apple HIG
+         # these are now part of Preferences...
+         if {$pd_nt != 2 } {
+    $name.m.file add command -label Path... \
+        -command {pd pd start-path-dialog \;} 
+
+    $name.m.file add command -label Startup... \
+        -command {pd pd start-startup-dialog \;} 
+         }
+
+    $name.m.file add  separator
+    $name.m.file add command -label Close \
+        -command [concat menu_close $name] \
+        -accelerator [accel_munge "Ctrl+w"]
+
+    $name.m.file add command -label Save -command [concat menu_save $name] \
+        -accelerator [accel_munge "Ctrl+s"]
+
+    $name.m.file add command -label "Save as..." \
+        -command [concat menu_saveas $name] \
+        -accelerator [accel_munge "Ctrl+S"]
+
+    $name.m.file add command -label Print -command [concat menu_print $name] \
+        -accelerator [accel_munge "Ctrl+p"]
+
+    $name.m.file add separator
+
+    $name.m.file add command -label Quit -command {menu_quit} \
+        -accelerator [accel_munge "Ctrl+q"]
+
+# the edit menu
+    menu $name.m.edit -postcommand [concat menu_fixeditmenu $name] -tearoff $pd_tearoff
+    $name.m add cascade -label Edit -menu $name.m.edit
+    
+    $name.m.edit add command -label Undo -command [concat menu_undo $name] \
+        -accelerator [accel_munge "Ctrl+z"]
+
+    $name.m.edit add command -label Redo -command [concat menu_redo $name] \
+        -accelerator [accel_munge "Ctrl+Z"]
+
+    $name.m.edit add separator
+
+    $name.m.edit add command -label Cut -command [concat menu_cut $name] \
+        -accelerator [accel_munge "Ctrl+x"]
+
+    $name.m.edit add command -label Copy -command [concat menu_copy $name] \
+        -accelerator [accel_munge "Ctrl+c"]
+
+    $name.m.edit add command -label Paste \
+        -command [concat menu_paste $name] \
+        -accelerator [accel_munge "Ctrl+v"]
+
+    $name.m.edit add command -label Duplicate \
+        -command [concat menu_duplicate $name] \
+        -accelerator [accel_munge "Ctrl+d"]
+
+    $name.m.edit add command -label {Select all} \
+        -command [concat menu_selectall $name] \
+        -accelerator [accel_munge "Ctrl+a"]
+
+    $name.m.edit add separator
+
+    $name.m.edit add command -label {Text Editor} \
+        -command [concat menu_texteditor $name] \
+        -accelerator [accel_munge "Ctrl+t"]
+
+    $name.m.edit add command -label Font \
+        -command [concat menu_font $name] 
+
+    $name.m.edit add command -label {Tidy Up} \
+        -command [concat menu_tidyup $name]
+
+    $name.m.edit add separator
+    
+# Apple, Microsoft, and others put find functions in the Edit menu.
+    $name.m.edit add command -label {Find...} \
+                  -accelerator [accel_munge "Ctrl+f"] \
+                  -command [concat menu_findobject $name] 
+    $name.m.edit add command -label {Find Again} \
+                  -accelerator [accel_munge "Ctrl+g"] \
+                  -command [concat menu_findagain $name] 
+    $name.m.edit add command -label {Find last error} \
+                  -command [concat menu_finderror] 
+
+    $name.m.edit add separator
+
+############iemlib##################
+# instead of "red = #BC3C60" we take "grey85", so there is no difference,
+# if widget is selected or not.
+
+    $name.m.edit add checkbutton -label "Edit mode" \
+        -indicatoron true -selectcolor grey85 \
+        -command [concat menu_editmode $name] \
+        -accelerator [accel_munge "Ctrl+e"]     
+
+    if { $editable == 0 } {
+            $name.m.edit entryconfigure "Edit mode" -indicatoron false }
+
+        
+############iemlib##################
+
+
+# the put menu
+    menu $name.m.put -tearoff $pd_tearoff
+    $name.m add cascade -label Put -menu $name.m.put
+
+    $name.m.put add command -label Object \
+        -command [concat menu_object $name 0] \
+        -accelerator [accel_munge "Ctrl+1"]
+
+    $name.m.put add command -label Message \
+        -command [concat menu_message $name 0] \
+        -accelerator [accel_munge "Ctrl+2"]
+
+    $name.m.put add command -label Number \
+        -command [concat menu_floatatom $name 0] \
+        -accelerator [accel_munge "Ctrl+3"]
+
+    $name.m.put add command -label Symbol \
+        -command [concat menu_symbolatom $name 0] \
+        -accelerator [accel_munge "Ctrl+4"]
+
+    $name.m.put add command -label Comment \
+        -command [concat menu_comment $name 0] \
+        -accelerator [accel_munge "Ctrl+5"]
+
+    $name.m.put add separator
+        
+############iemlib##################
+
+    $name.m.put add command -label Bang \
+        -command [concat menu_bng $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+b"]
+    
+    $name.m.put add command -label Toggle \
+        -command [concat menu_toggle $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+t"]
+    
+    $name.m.put add command -label Number2 \
+        -command [concat menu_numbox $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+n"]
+    
+    $name.m.put add command -label Vslider \
+        -command [concat menu_vslider $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+v"]
+    
+    $name.m.put add command -label Hslider \
+        -command [concat menu_hslider $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+h"]
+    
+    $name.m.put add command -label Vradio \
+        -command [concat menu_vradio $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+d"]
+    
+    $name.m.put add command -label Hradio \
+        -command [concat menu_hradio $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+i"]
+    
+    $name.m.put add command -label VU \
+        -command [concat menu_vumeter $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+u"]
+    
+    $name.m.put add command -label Canvas \
+        -command [concat menu_mycnv $name 0] \
+        -accelerator [accel_munge "Shift+Ctrl+c"]
+
+############iemlib##################
+    
+    $name.m.put add separator
+        
+    $name.m.put add command -label Graph \
+        -command [concat menu_graph $name] 
+
+    $name.m.put add command -label Array \
+        -command [concat menu_array $name] 
+
+# the find menu
+# Apple, Microsoft, and others put find functions in the Edit menu.
+# But in order to move these items to the Edit menu, the Find menu
+# handling needs to be dealt with, including this line in g_canvas.c:
+#         sys_vgui(".mbar.find delete %d\n", i);
+# <hans@at.or.at>
+    menu $name.m.find -tearoff $pd_tearoff
+    $name.m add cascade -label Find -menu $name.m.find
+
+    $name.m.find add command -label {Find...} \
+        -accelerator [accel_munge "Ctrl+f"] \
+        -command [concat menu_findobject $name] 
+    $name.m.find add command -label {Find Again} \
+        -accelerator [accel_munge "Ctrl+g"] \
+        -command [concat menu_findagain $name] 
+    $name.m.find add command -label {Find last error} \
+        -command [concat menu_finderror] 
+    
+# the window menu
+    menu $name.m.windows -postcommand [concat menu_fixwindowmenu $name] \
+        -tearoff $pd_tearoff
+
+    $name.m.windows add command -label {parent window}\
+        -command [concat menu_windowparent $name] 
+    $name.m.windows add command -label {Pd window} -command menu_pop_pd
+    $name.m.windows add separator
+
+# the audio menu
+    menu $name.m.audio -tearoff $pd_tearoff
+
+    if {$pd_nt != 2} {
+        $name.m add cascade -label Windows -menu $name.m.windows
+        $name.m add cascade -label Media -menu $name.m.audio
+    } else {
+        $name.m add cascade -label Media -menu $name.m.audio
+        $name.m add cascade -label Window -menu $name.m.windows
+# the MacOS X app menu
+                  menu $name.m.apple -tearoff $pd_tearoff
+                  $name.m add cascade -label "Apple" -menu $name.m.apple 
+    }
+
+# the help menu
+
+    menu $name.m.help -tearoff $pd_tearoff
+    $name.m add cascade -label Help -menu $name.m.help
+
+    menu_addstd $name.m
+
+# the popup menu
+    menu $name.popup -tearoff false
+    $name.popup add command -label {Properties} \
+        -command [concat popup_action $name 0] 
+    $name.popup add command -label {Open} \
+        -command [concat popup_action $name 1] 
+    $name.popup add command -label {Help} \
+        -command [concat popup_action $name 2] 
+
+# WM protocol
+    wm protocol $name WM_DELETE_WINDOW [concat menu_close $name]
+
+# bindings.
+# this is idiotic -- how do you just sense what mod keys are down and
+# pass them on? I can't find it anywhere.
+# Here we encode shift as 1, control 2, alt 4, in agreement
+# with definitions in g_canvas.c.  The third button gets "8" but we don't
+# bother with modifiers there.
+# We don't handle multiple clicks yet.
+
+    bind $name.c <Button> {pdtk_canvas_click %W %x %y %b 0}
+    bind $name.c <Shift-Button> {pdtk_canvas_click %W %x %y %b 1}
+    bind $name.c <Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 3}
+    # Alt key is called Option on the Mac
+    if {$pd_nt == 2} {
+        bind $name.c <Option-Button> {pdtk_canvas_click %W %x %y %b 4}
+        bind $name.c <Option-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
+        bind $name.c <Option-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
+        bind $name.c <Option-Control-Shift-Button> \
+            {pdtk_canvas_click %W %x %y %b 7}
+    } else {
+        bind $name.c <Alt-Button> {pdtk_canvas_click %W %x %y %b 4}
+        bind $name.c <Alt-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
+        bind $name.c <Alt-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
+        bind $name.c <Alt-Control-Shift-Button> \
+            {pdtk_canvas_click %W %x %y %b 7}
+    }
+    global pd_nt
+# button 2 is the right button on Mac; on other platforms it's button 3.
+    if {$pd_nt == 2} {
+        bind $name.c <Button-2> {pdtk_canvas_click %W %x %y %b 8}
+        bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 8}
+    } else {
+        bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
+        bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
+    }
+#on linux, button 2 "pastes" from the X windows clipboard
+    if {$pd_nt == 0} {
+        bind $name.c <Button-2> {\
+            pdtk_canvas_click %W %x %y %b 0;\
+             pdtk_canvas_mouseup %W %x %y %b;\
+             pdtk_pastetext}
+    }
+
+    bind $name.c <ButtonRelease> {pdtk_canvas_mouseup %W %x %y %b}
+    bind $name.c <Control-Key> {pdtk_canvas_ctrlkey %W %K 0}
+    bind $name.c <Control-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
+#    bind $name.c <Mod1-Key> {puts stderr [concat mod1 %W %K %A]}
+    if {$pd_nt == 2} {
+        bind $name.c <Mod1-Key> {pdtk_canvas_ctrlkey %W %K 0}
+        bind $name.c <Mod1-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
+    }
+    bind $name.c <Key> {pdtk_canvas_key %W %K %A 0}
+    bind $name.c <Shift-Key> {pdtk_canvas_key %W %K %A 1}
+    bind $name.c <KeyRelease> {pdtk_canvas_keyup %W %K %A}
+    bind $name.c <Motion> {pdtk_canvas_motion %W %x %y 0}
+    bind $name.c <Control-Motion> {pdtk_canvas_motion %W %x %y 2}
+    if {$pd_nt == 2} {
+        bind $name.c <Option-Motion> {pdtk_canvas_motion %W %x %y 4}
+    } else { 
+        bind $name.c <Alt-Motion> {pdtk_canvas_motion %W %x %y 4}
+    }   
+    bind $name.c <Map> {pdtk_canvas_map %W}
+    bind $name.c <Unmap> {pdtk_canvas_unmap %W}
+    focus $name.c
+
+    switch $pd_nt { 0 {
+        bind $name.c <Button-4>  "pdtk_canvas_scroll $name.c y -1"
+        bind $name.c <Button-5>  "pdtk_canvas_scroll $name.c y +1"
+        bind $name.c <Shift-Button-4>  "pdtk_canvas_scroll $name.c x -1"
+        bind $name.c <Shift-Button-5>  "pdtk_canvas_scroll $name.c x +1"
+    } default {
+        bind $name.c  <MouseWheel> \
+            "pdtk_canvas_scroll $name.c y \[expr -abs(%D)/%D\]"
+        bind $name.c  <Shift-MouseWheel> \
+            "pdtk_canvas_scroll $name.c x \[expr -abs(%D)/%D\]"
+    }}
+
+    catch {
+        dnd bindtarget $name.c text/uri-list <Drop> \
+            "pdtk_canvas_makeobjs $name %D %x %y"
+    }
+
+#    puts stderr "all done"
+#   after 1 [concat raise $name]
+    global pdtk_canvas_mouseup_name
+    set pdtk_canvas_mouseup_name ""
+}
+
+#### jsarlo #####
+proc pdtk_array_listview_setpage {arrayName page} {
+    global pd_array_listview_page
+    set pd_array_listview_page($arrayName) $page
+}
+
+proc pdtk_array_listview_changepage {arrayName np} {
+    global pd_array_listview_page
+    pdtk_array_listview_setpage \
+      $arrayName [expr $pd_array_listview_page($arrayName) + $np]
+    pdtk_array_listview_fillpage $arrayName
+}
+
+proc pdtk_array_listview_fillpage {arrayName} {
+    global pd_array_listview_page
+    global pd_array_listview_id
+    set windowName [format ".%sArrayWindow" $arrayName]
+    set topItem [expr [lindex [$windowName.lb yview] 0] * \
+                 [$windowName.lb size]]
+   
+    if {[winfo exists $windowName]} {
+      set cmd "$pd_array_listview_id($arrayName) \
+               arrayviewlistfillpage \
+               $pd_array_listview_page($arrayName) \
+               $topItem"
+   
+      pd [concat $cmd \;]
+    }
+}
+
+proc pdtk_array_listview_new {id arrayName page} {
+    global pd_nt
+    global pd_array_listview_page
+    global pd_array_listview_id
+    set pd_array_listview_page($arrayName) $page
+    set pd_array_listview_id($arrayName) $id
+    set windowName [format ".%sArrayWindow" $arrayName]
+    if [winfo exists $windowName] then [destroy $windowName]
+    toplevel $windowName
+    wm protocol $windowName WM_DELETE_WINDOW \
+      "pdtk_array_listview_close $id $arrayName"
+    wm title $windowName [concat $arrayName "(list view)"]
+    # FIXME
+    set font 12
+    set $windowName.lb [listbox $windowName.lb -height 20 -width 25\
+                        -selectmode extended \
+                        -relief solid -background white -borderwidth 1 \
+                        -font [format -*-courier-bold--normal--%d-* \
+                               $font] \
+                        -yscrollcommand "$windowName.lb.sb set"]
+    set $windowName.lb.sb [scrollbar $windowName.lb.sb \
+                           -command "$windowName.lb yview" -orient vertical]
+    place configure $windowName.lb.sb -relheight 1 -relx 0.9 -relwidth 0.1
+    pack $windowName.lb -expand 1 -fill both
+    bind $windowName.lb <Double-ButtonPress-1> \
+         "pdtk_array_listview_edit $arrayName $page $font"
+    # handle copy/paste
+    if {$pd_nt == 0} {
+      selection handle $windowName.lb \
+            "pdtk_array_listview_lbselection $arrayName"
+    } else {
+      if {$pd_nt == 1} {
+        bind $windowName.lb <ButtonPress-3> \
+           "pdtk_array_listview_popup $arrayName"
+      } 
+    }
+    set $windowName.prevBtn [button $windowName.prevBtn -text "<-" \
+        -command "pdtk_array_listview_changepage $arrayName -1"]
+    set $windowName.nextBtn [button $windowName.nextBtn -text "->" \
+        -command "pdtk_array_listview_changepage $arrayName 1"]
+    pack $windowName.prevBtn -side left -ipadx 20 -pady 10 -anchor s
+    pack $windowName.nextBtn -side right -ipadx 20 -pady 10 -anchor s
+    focus $windowName
+}
+
+proc pdtk_array_listview_lbselection {arrayName off size} {
+    set windowName [format ".%sArrayWindow" $arrayName]
+    set itemNums [$windowName.lb curselection]
+    set cbString ""
+    for {set i 0} {$i < [expr [llength $itemNums] - 1]} {incr i} {
+      set listItem [$windowName.lb get [lindex $itemNums $i]]
+      append cbString [string range $listItem \
+                        [expr [string first ") " $listItem] + 2] \
+                        end]
+      append cbString "\n"
+    }
+    set listItem [$windowName.lb get [lindex $itemNums $i]]
+    append cbString [string range $listItem \
+                      [expr [string first ") " $listItem] + 2] \
+                      end]
+    set last $cbString
+}
+
+# Win32 uses a popup menu for copy/paste
+proc pdtk_array_listview_popup {arrayName} {
+    set windowName [format ".%sArrayWindow" $arrayName]
+    if [winfo exists $windowName.popup] then [destroy $windowName.popup]
+    menu $windowName.popup -tearoff false
+    $windowName.popup add command -label {Copy} \
+        -command "pdtk_array_listview_copy $arrayName; \
+                  destroy $windowName.popup"
+    $windowName.popup add command -label {Paste} \
+        -command "pdtk_array_listview_paste $arrayName; \
+                  destroy $windowName.popup"
+    tk_popup $windowName.popup [winfo pointerx $windowName] \
+             [winfo pointery $windowName] 0
+}
+
+proc pdtk_array_listview_copy {arrayName} {
+    set windowName [format ".%sArrayWindow" $arrayName]
+    set itemNums [$windowName.lb curselection]
+    set cbString ""
+    for {set i 0} {$i < [expr [llength $itemNums] - 1]} {incr i} {
+      set listItem [$windowName.lb get [lindex $itemNums $i]]
+      append cbString [string range $listItem \
+                        [expr [string first ") " $listItem] + 2] \
+                        end]
+      append cbString "\n"
+    }
+    set listItem [$windowName.lb get [lindex $itemNums $i]]
+    append cbString [string range $listItem \
+                      [expr [string first ") " $listItem] + 2] \
+                      end]
+    clipboard clear
+    clipboard append $cbString
+}
+
+proc pdtk_array_listview_paste {arrayName} {
+    global pd_array_listview_page
+    global pd_array_listview_pagesize
+    set cbString [selection get -selection CLIPBOARD]
+    set lbName [format ".%sArrayWindow.lb" $arrayName]
+    set itemNum [lindex [$lbName curselection] 0]
+    set splitChars ", \n"
+    set itemString [split $cbString $splitChars]
+    set flag 1
+    for {set i 0; set counter 0} {$i < [llength $itemString]} {incr i} {
+      if {[lindex $itemString $i] != {}} {
+        pd [concat $arrayName [expr $itemNum + \
+           [expr $counter + \
+           [expr $pd_array_listview_pagesize \
+                 * $pd_array_listview_page($arrayName)]]] \
+           [lindex $itemString $i] \;]
+        incr counter
+        set flag 0
+      }
+    }
+}
+
+proc pdtk_array_listview_edit {arrayName page font} {
+    global pd_array_listview_entry
+    global pd_nt
+    if {$pd_nt == 0} {
+      set font [expr $font - 2]
+    }
+    set lbName [format ".%sArrayWindow.lb" $arrayName]
+    if {[winfo exists $lbName.entry]} {
+      pdtk_array_listview_update_entry \
+        $arrayName $pd_array_listview_entry($arrayName)
+      unset pd_array_listview_entry($arrayName)
+    }
+    set itemNum [$lbName index active]
+    set pd_array_listview_entry($arrayName) $itemNum
+    set bbox [$lbName bbox $itemNum]
+    set y [expr [lindex $bbox 1] - 4]
+    set $lbName.entry [entry $lbName.entry \
+                       -font [format -*-courier-bold--normal--%d-* $font]]
+    $lbName.entry insert 0 []
+    place configure $lbName.entry -relx 0 -y $y -relwidth 1
+    lower $lbName.entry
+    focus $lbName.entry
+    bind $lbName.entry <Return> \
+         "pdtk_array_listview_update_entry $arrayName $itemNum;"
+}
+
+proc pdtk_array_listview_update_entry {arrayName itemNum} {
+    global pd_array_listview_page
+    global pd_array_listview_pagesize
+    set lbName [format ".%sArrayWindow.lb" $arrayName]
+    set splitChars ", \n"
+    set itemString [split [$lbName.entry get] $splitChars]
+    set flag 1
+    for {set i 0; set counter 0} {$i < [llength $itemString]} {incr i} {
+      if {[lindex $itemString $i] != {}} {
+        pd [concat $arrayName [expr $itemNum + \
+           [expr $counter + \
+           [expr $pd_array_listview_pagesize \
+                 * $pd_array_listview_page($arrayName)]]] \
+           [lindex $itemString $i] \;]
+        incr counter
+        set flag 0
+      }
+    }
+    pdtk_array_listview_fillpage $arrayName
+    destroy $lbName.entry
+}
+
+proc pdtk_array_listview_closeWindow {arrayName} {
+    set windowName [format ".%sArrayWindow" $arrayName]
+    destroy $windowName
+}
+
+proc pdtk_array_listview_close {id arrayName} {
+    pdtk_array_listview_closeWindow $arrayName
+    set cmd [concat $id "arrayviewclose" \;]
+    pd $cmd
+}
+##### end jsarlo #####
+
+#################### event binding procedures ################
+
+#get the name of the toplevel window for a canvas; this is also
+#the name of the canvas object in Pd.
+
+proc canvastosym {name} {
+    string range $name 0 [expr [string length $name] - 3]
+}
+
+set pdtk_lastcanvasconfigured ""
+set pdtk_lastcanvasconfiguration ""
+set pdtk_lastcanvasconfiguration2 ""
+
+proc pdtk_canvas_checkgeometry {topname} {
+    set boo [winfo geometry $topname.c]
+    set boo2 [wm geometry $topname]
+    global pdtk_lastcanvasconfigured
+    global pdtk_lastcanvasconfiguration
+    global pdtk_lastcanvasconfiguration2
+    if {$topname != $pdtk_lastcanvasconfigured || \
+        $boo != $pdtk_lastcanvasconfiguration || \
+        $boo2 != $pdtk_lastcanvasconfiguration2} {
+            set pdtk_lastcanvasconfigured $topname
+            set pdtk_lastcanvasconfiguration $boo
+            set pdtk_lastcanvasconfiguration2 $boo2
+            pd $topname relocate $boo $boo2 \;
+    }
+}
+
+proc pdtk_canvas_click {name x y b f} {
+    global pd_nt
+    if {$pd_nt == 0} {focus $name}
+    pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b $f \;
+}
+
+proc pdtk_canvas_shiftclick {name x y b} {
+    pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 1 \;
+}
+
+proc pdtk_canvas_ctrlclick {name x y b} {
+    pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 2 \;
+}
+
+proc pdtk_canvas_altclick {name x y b} {
+    pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 3 \;
+}
+
+proc pdtk_canvas_dblclick {name x y b} {
+    pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 4 \;
+}
+
+set pdtk_canvas_mouseup_name 0
+set pdtk_canvas_mouseup_xminval 0
+set pdtk_canvas_mouseup_xmaxval 0
+set pdtk_canvas_mouseup_yminval 0
+set pdtk_canvas_mouseup_ymaxval 0
+
+proc pdtk_canvas_mouseup {name x y b} {
+    pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
+        [$name canvasy $y] $b \;]
+}
+
+proc pdtk_canvas_getscroll {name} {
+    global pdtk_canvas_mouseup_name
+    global pdtk_canvas_mouseup_xminval
+    global pdtk_canvas_mouseup_xmaxval
+    global pdtk_canvas_mouseup_yminval
+    global pdtk_canvas_mouseup_ymaxval
+
+    set size [$name bbox all]
+    if {$size != ""} {
+        set xminval 0
+        set yminval 0
+        set xmaxval 100
+        set ymaxval 100
+        set x1 [lindex $size 0]
+        set x2 [lindex $size 2]
+        set y1 [lindex $size 1]
+        set y2 [lindex $size 3]
+        
+        if {$x1 < 0} {set xminval $x1}
+        if {$y1 < 0} {set yminval $y1}
+
+        if {$x2 > 100} {set xmaxval $x2}
+        if {$y2 > 100} {set ymaxval $y2}
+        
+        if {$pdtk_canvas_mouseup_name != $name || \
+            $pdtk_canvas_mouseup_xminval != $xminval || \
+            $pdtk_canvas_mouseup_xmaxval != $xmaxval || \
+            $pdtk_canvas_mouseup_yminval != $yminval || \
+            $pdtk_canvas_mouseup_ymaxval != $ymaxval } {
+            
+                set newsize "$xminval $yminval $xmaxval $ymaxval"
+                $name configure -scrollregion $newsize
+                set pdtk_canvas_mouseup_name $name
+                set pdtk_canvas_mouseup_xminval $xminval
+                set pdtk_canvas_mouseup_xmaxval $xmaxval
+                set pdtk_canvas_mouseup_yminval $yminval
+                set pdtk_canvas_mouseup_ymaxval $ymaxval
+        }
+
+    }
+    pdtk_canvas_checkgeometry [canvastosym $name]
+}
+
+proc pdtk_canvas_key {name key iso shift} {
+#    puts stderr [concat down key= $key iso= $iso]
+#    .controls.switches.meterbutton configure -text $key
+#  HACK for MAC OSX -- backspace seems different; I don't understand why.
+#  invesigate this LATER...
+    global pd_nt
+    if {$pd_nt == 2} {
+        if {$key == "BackSpace"} {
+            set key 8
+            set keynum 8
+        }
+        if {$key == "Delete"} {
+            set key 8
+            set keynum 8
+        }
+    }
+    if {$key == "KP_Delete"} {
+        set key 127
+        set keynum 127
+    }
+    if {$iso != ""} {
+        scan $iso %c keynum 
+        pd [canvastosym $name] key 1 $keynum $shift\;
+    } else {
+        pd [canvastosym $name] key 1 $key $shift\;
+    }
+}
+
+proc pdtk_canvas_keyup {name key iso} {
+#    puts stderr [concat up key= $key iso= $iso]
+    if {$iso != ""} {
+        scan $iso %c keynum 
+        pd [canvastosym $name] key 0 $keynum 0 \;
+    } else {
+        pd [canvastosym $name] key 0 $key 0 \;
+    }
+}
+
+proc pdtk_canvas_ctrlkey {name key shift} {
+# first get rid of ".c" suffix; we'll refer to the toplevel instead
+    set topname [string trimright $name .c]
+#   puts stderr [concat ctrl-key $key $topname]
+
+    if {$key == "1"} {menu_object $topname 1}
+    if {$key == "2"} {menu_message $topname 1}
+    if {$key == "3"} {menu_floatatom $topname 1}
+    if {$key == "4"} {menu_symbolatom $topname 1}
+    if {$key == "5"} {menu_comment $topname 1}
+    if {$key == "slash"} {menu_audio 1}
+    if {$key == "period"} {menu_audio 0}
+    if {$shift == 1} {
+        if {$key == "q" || $key == "Q"} {menu_really_quit}
+        if {$key == "w" || $key == "W"} {menu_really_close $topname}
+        if {$key == "s" || $key == "S"} {menu_saveas $topname}
+        if {$key == "z" || $key == "Z"} {menu_redo $topname}
+        if {$key == "b" || $key == "B"} {menu_bng $topname 1}
+        if {$key == "t" || $key == "T"} {menu_toggle $topname 1}
+        if {$key == "n" || $key == "N"} {menu_numbox $topname 1}
+        if {$key == "v" || $key == "V"} {menu_vslider $topname 1}
+        if {$key == "h" || $key == "H"} {menu_hslider $topname 1}
+        if {$key == "i" || $key == "I"} {menu_hradio $topname 1}
+        if {$key == "d" || $key == "D"} {menu_vradio $topname 1}
+        if {$key == "u" || $key == "U"} {menu_vumeter $topname 1}
+        if {$key == "c" || $key == "C"} {menu_mycnv $topname 1}
+    } else {
+        if {$key == "e" || $key == "E"} {menu_editmode $topname}
+        if {$key == "q" || $key == "Q"} {menu_quit}
+        if {$key == "s" || $key == "S"} {menu_save $topname}
+        if {$key == "z" || $key == "Z"} {menu_undo $topname}
+        if {$key == "n" || $key == "N"} {menu_new}
+        if {$key == "o" || $key == "O"} {menu_open}
+        if {$key == "m" || $key == "M"} {menu_send}
+        if {$key == "w" || $key == "W"} {menu_close $topname}
+        if {$key == "p" || $key == "P"} {menu_print $topname}
+        if {$key == "x" || $key == "X"} {menu_cut $topname}
+        if {$key == "c" || $key == "C"} {menu_copy $topname}
+        if {$key == "v" || $key == "V"} {menu_paste $topname}
+        if {$key == "d" || $key == "D"} {menu_duplicate $topname}
+        if {$key == "a" || $key == "A"} {menu_selectall $topname}
+        if {$key == "t" || $key == "T"} {menu_texteditor $topname}
+        if {$key == "f" || $key == "F"} {menu_findobject $topname}
+        if {$key == "g" || $key == "G"} {menu_findagain $topname}
+    }
+}
+
+proc pdtk_canvas_scroll {canvas xy distance} {
+    $canvas [list $xy]view scroll $distance units
+}
+
+proc pdtk_canvas_motion {name x y mods} {
+#    puts stderr [concat [canvastosym $name] $name $x $y]
+    pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
+}
+
+# "map" event tells us when the canvas becomes visible (arg is "0") or
+# invisible (arg is "").  Invisibility means the Window Manager has minimized
+# us.  We don't get a final "unmap" event when we destroy the window.
+proc pdtk_canvas_map {name} {
+#   puts stderr [concat map $name]
+    pd [canvastosym $name] map 1 \;
+}
+
+proc pdtk_canvas_unmap {name} {
+#   puts stderr [concat unmap $name]
+    pd [canvastosym $name] map 0 \;
+}
+
+proc pdtk_canvas_makeobjs {name files x y} {
+    set c 0
+    for {set n 0} {$n < [llength $files]} {incr n} {
+        if {[regexp {.*/(.+).pd$} [lindex $files $n] file obj] == 1} {
+            pd $name obj $x [expr $y + ($c * 30)] [pdtk_enquote $obj] \;
+            incr c
+        }
+    } 
+}
+
+set saveas_dir nowhere
+
+############ pdtk_canvas_saveas -- run a saveas dialog ##############
+
+proc pdtk_canvas_saveas {name initfile initdir} {
+    global pd_nt
+    set filename [tk_getSaveFile -initialfile $initfile \
+       -initialdir $initdir  -defaultextension .pd \
+        -filetypes { {{pd files} {.pd}} {{max files} {.pat}} }]
+
+    if {$filename != ""} {
+# yes, we need the extent even if we're on a mac.
+        if {$pd_nt == 2} {
+          if {[string last .pd $filename] < 0 && \
+            [string last .PD $filename] < 0 && \
+            [string last .pat $filename] < 0 && \
+            [string last .PAT $filename] < 0} {
+                set filename $filename.pd
+                if {[file exists $filename]} {
+                        set answer [tk_messageBox \
+                        \-message [concat overwrite $filename "?"] \
+                         \-type yesno \-icon question]
+                        if {! [string compare $answer no]} {return}
+                }
+          }
+        }
+
+        set directory [string range $filename 0 \
+            [expr [string last / $filename ] - 1]]
+        set basename [string range $filename \
+            [expr [string last / $filename ] + 1] end]
+        pd [concat $name savetofile [pdtk_enquote $basename] \
+             [pdtk_enquote $directory] \;]
+#       pd [concat $name savetofile $basename $directory \;]
+    }
+}
+
+############ pdtk_canvas_dofont -- run a font and resize dialog #########
+
+set fontsize 0
+set stretchval 0
+set whichstretch 0
+
+proc dofont_apply {name} {
+    global fontsize
+    global stretchval
+    global whichstretch
+    set cmd [concat $name font $fontsize $stretchval $whichstretch \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc dofont_cancel {name} {
+    set cmd [concat $name cancel \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc pdtk_canvas_dofont {name initsize} {
+    
+    global fontsize
+    set fontsize $initsize
+    
+    global stretchval
+    set stretchval 100
+    
+    global whichstretch
+    set whichstretch 1
+    
+    toplevel $name
+    wm title $name  {FONT BOMB}
+    wm protocol $name WM_DELETE_WINDOW [concat dofont_cancel $name]
+
+    frame $name.buttonframe
+    pack $name.buttonframe -side bottom -fill x -pady 2m
+    button $name.buttonframe.cancel -text {Cancel}\
+        -command "dofont_cancel $name"
+    button $name.buttonframe.ok -text {Do it}\
+        -command "dofont_apply $name"
+    pack $name.buttonframe.cancel -side left -expand 1
+    pack $name.buttonframe.ok -side left -expand 1
+    
+    frame $name.radiof
+    pack $name.radiof -side left
+    
+    label $name.radiof.label -text {Font Size:}
+    pack $name.radiof.label -side top
+
+    radiobutton $name.radiof.radio8 -value 8 -variable fontsize -text "8"
+    radiobutton $name.radiof.radio10 -value 10 -variable fontsize -text "10"
+    radiobutton $name.radiof.radio12 -value 12 -variable fontsize -text "12"
+    radiobutton $name.radiof.radio16 -value 16 -variable fontsize -text "16"
+    radiobutton $name.radiof.radio24 -value 24 -variable fontsize -text "24"
+    radiobutton $name.radiof.radio36 -value 36 -variable fontsize -text "36"
+    pack $name.radiof.radio8 -side top -anchor w
+    pack $name.radiof.radio10 -side top -anchor w
+    pack $name.radiof.radio12 -side top -anchor w
+    pack $name.radiof.radio16 -side top -anchor w
+    pack $name.radiof.radio24 -side top -anchor w
+    pack $name.radiof.radio36 -side top -anchor w
+
+    frame $name.stretchf
+    pack $name.stretchf -side left
+    
+    label $name.stretchf.label -text {Stretch:}
+    pack $name.stretchf.label -side top
+    
+    entry $name.stretchf.entry -textvariable stretchval -width 5
+    pack $name.stretchf.entry -side left
+
+    radiobutton $name.stretchf.radio1 \
+        -value 1 -variable whichstretch -text "X and Y"
+    radiobutton $name.stretchf.radio2 \
+        -value 2 -variable whichstretch -text "X only"
+    radiobutton $name.stretchf.radio3 \
+        -value 3 -variable whichstretch -text "Y only"
+
+    pack $name.stretchf.radio1 -side top -anchor w
+    pack $name.stretchf.radio2 -side top -anchor w
+    pack $name.stretchf.radio3 -side top -anchor w
+
+}
+
+############ pdtk_gatom_dialog -- run a gatom dialog #########
+
+# dialogs like this one can come up in many copies; but in TK the easiest
+# way to get data from an "entry", etc., is to set an associated variable
+# name.  This is especially true for grouped "radio buttons".  So we have
+# to synthesize variable names for each instance of the dialog.  The dialog
+# gets a TK pathname $id, from which it strips the leading "." to make a
+# variable suffix $vid.  Then you can get the actual value out by asking for
+# [eval concat $$variablename].  There should be an easier way but I don't see
+# it yet.
+
+proc gatom_escape {sym} {
+    if {[string length $sym] == 0} {
+        set ret "-"
+#       puts stderr [concat escape1 $sym $ret]
+    } else {
+        if {[string equal -length 1 $sym "-"]} {
+        set ret [string replace $sym 0 0 "--"]
+#       puts stderr [concat escape $sym $ret]
+        } else {
+            set ret [string map {"$" "#"} $sym]
+#            puts stderr [concat unescape $sym $ret]
+        }
+    }
+    pdtk_unspace $ret
+}
+
+proc gatom_unescape {sym} {
+    if {[string equal -length 1 $sym "-"]} {
+        set ret [string replace $sym 0 0 ""]
+#       puts stderr [concat unescape $sym $ret]
+    } else {
+        set ret [string map {"#" "$"} $sym]
+#        puts stderr [concat unescape $sym $ret]
+    }
+    concat $ret
+}
+        
+proc dogatom_apply {id} {
+    set vid [string trimleft $id .]
+
+    set var_gatomwidth [concat gatomwidth_$vid]
+    global $var_gatomwidth
+    set var_gatomlo [concat gatomlo_$vid]
+    global $var_gatomlo
+    set var_gatomhi [concat gatomhi_$vid]
+    global $var_gatomhi
+    set var_gatomwherelabel [concat gatomwherelabel_$vid]
+    global $var_gatomwherelabel
+    set var_gatomlabel [concat gatomlabel_$vid]
+    global $var_gatomlabel
+    set var_gatomsymfrom [concat gatomsymfrom_$vid]
+    global $var_gatomsymfrom
+    set var_gatomsymto [concat gatomsymto_$vid]
+    global $var_gatomsymto
+
+#    set cmd [concat $id param $gatomwidth $gatomlo $gatomhi \;]
+    
+    set cmd [concat $id param \
+        [eval concat $$var_gatomwidth] \
+        [eval concat $$var_gatomlo] \
+        [eval concat $$var_gatomhi] \
+        [eval gatom_escape $$var_gatomlabel] \
+        [eval concat $$var_gatomwherelabel] \
+        [eval gatom_escape $$var_gatomsymfrom] \
+        [eval gatom_escape $$var_gatomsymto] \
+        \;]
+
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc dogatom_cancel {name} {
+    set cmd [concat $name cancel \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc dogatom_ok {name} {
+    dogatom_apply $name
+    dogatom_cancel $name
+}
+
+proc pdtk_gatom_dialog {id initwidth initlo inithi \
+    wherelabel label symfrom symto} {
+
+    set vid [string trimleft $id .]
+
+    set var_gatomwidth [concat gatomwidth_$vid]
+    global $var_gatomwidth
+    set var_gatomlo [concat gatomlo_$vid]
+    global $var_gatomlo
+    set var_gatomhi [concat gatomhi_$vid]
+    global $var_gatomhi
+    set var_gatomwherelabel [concat gatomwherelabel_$vid]
+    global $var_gatomwherelabel
+    set var_gatomlabel [concat gatomlabel_$vid]
+    global $var_gatomlabel
+    set var_gatomsymfrom [concat gatomsymfrom_$vid]
+    global $var_gatomsymfrom
+    set var_gatomsymto [concat gatomsymto_$vid]
+    global $var_gatomsymto
+
+    set $var_gatomwidth $initwidth
+    set $var_gatomlo $initlo
+    set $var_gatomhi $inithi
+    set $var_gatomwherelabel $wherelabel
+    set $var_gatomlabel [gatom_unescape $label]
+    set $var_gatomsymfrom [gatom_unescape $symfrom]
+    set $var_gatomsymto [gatom_unescape $symto]
+
+    toplevel $id
+    wm title $id {Atom}
+    wm protocol $id WM_DELETE_WINDOW [concat dogatom_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "dogatom_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "dogatom_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "dogatom_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+
+    frame $id.paramsymto
+    pack $id.paramsymto -side bottom
+    label $id.paramsymto.entryname -text {send symbol}
+    entry $id.paramsymto.entry -textvariable $var_gatomsymto -width 20
+    pack $id.paramsymto.entryname $id.paramsymto.entry -side left
+
+    frame $id.paramsymfrom
+    pack $id.paramsymfrom -side bottom
+    label $id.paramsymfrom.entryname -text {receive symbol}
+    entry $id.paramsymfrom.entry -textvariable $var_gatomsymfrom -width 20
+    pack $id.paramsymfrom.entryname $id.paramsymfrom.entry -side left
+    
+    frame $id.radio
+    pack $id.radio -side bottom
+    label $id.radio.label -text {show label on:}
+    frame $id.radio.l
+    frame $id.radio.r
+    pack $id.radio.label -side top
+    pack $id.radio.l $id.radio.r -side left
+    radiobutton $id.radio.l.radio0 -value 0 \
+        -variable $var_gatomwherelabel \
+        -text "left"
+    radiobutton $id.radio.l.radio1 -value 1 \
+        -variable $var_gatomwherelabel \
+        -text "right"
+    radiobutton $id.radio.r.radio2 -value 2 \
+        -variable $var_gatomwherelabel \
+        -text "top"
+    radiobutton $id.radio.r.radio3 -value 3 \
+        -variable $var_gatomwherelabel \
+        -text "bottom"
+    pack $id.radio.l.radio0 $id.radio.l.radio1 -side top -anchor w
+    pack $id.radio.r.radio2 $id.radio.r.radio3 -side top -anchor w
+        
+
+    frame $id.paramlabel
+    pack $id.paramlabel -side bottom
+    label $id.paramlabel.entryname -text label
+    entry $id.paramlabel.entry -textvariable $var_gatomlabel -width 20
+    pack $id.paramlabel.entryname $id.paramlabel.entry -side left
+
+    frame $id.paramhi
+    pack $id.paramhi -side bottom
+    label $id.paramhi.entryname -text "upper limit"
+    entry $id.paramhi.entry -textvariable $var_gatomhi -width 8
+    pack $id.paramhi.entryname $id.paramhi.entry -side left
+
+    frame $id.paramlo
+    pack $id.paramlo -side bottom
+    label $id.paramlo.entryname -text "lower limit"
+    entry $id.paramlo.entry -textvariable $var_gatomlo -width 8
+    pack $id.paramlo.entryname $id.paramlo.entry -side left
+
+    frame $id.params
+    pack $id.params -side bottom
+    label $id.params.entryname -text width
+    entry $id.params.entry -textvariable $var_gatomwidth -width 4
+    pack $id.params.entryname $id.params.entry -side left
+
+
+
+    bind $id.paramhi.entry <KeyPress-Return> [concat dogatom_ok $id]
+    bind $id.paramlo.entry <KeyPress-Return> [concat dogatom_ok $id]
+    bind $id.params.entry <KeyPress-Return> [concat dogatom_ok $id]
+    pdtk_standardkeybindings $id.paramhi.entry
+    pdtk_standardkeybindings $id.paramlo.entry
+    pdtk_standardkeybindings $id.params.entry
+    $id.params.entry select from 0
+    $id.params.entry select adjust end
+    focus $id.params.entry
+}
+
+############ pdtk_canvas_popup -- popup menu for canvas #########
+
+set popup_xpix 0
+set popup_ypix 0
+
+proc popup_action {name action} {
+    global popup_xpix popup_ypix
+    set cmd [concat $name done-popup $action $popup_xpix $popup_ypix \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc pdtk_canvas_popup {name xpix ypix canprop canopen} {
+    global popup_xpix popup_ypix
+    set popup_xpix $xpix
+    set popup_ypix $ypix
+    if {$canprop == 0} {$name.popup entryconfigure 0 -state disabled}
+    if {$canprop == 1} {$name.popup entryconfigure 0 -state active}
+    if {$canopen == 0} {$name.popup entryconfigure 1 -state disabled}
+    if {$canopen == 1} {$name.popup entryconfigure 1 -state active}
+    tk_popup $name.popup [expr $xpix + [winfo rootx $name.c]] \
+         [expr $ypix + [winfo rooty $name.c]] 0
+}
+
+
+# begin of change "iemlib"
+############ pdtk_iemgui_dialog -- dialog window for iem guis #########
+
+set iemgui_define_min_flashhold 50
+set iemgui_define_min_flashbreak 10
+set iemgui_define_min_fontsize 4
+
+proc iemgui_clip_dim {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_wdt [concat iemgui_wdt_$vid]
+    global $var_iemgui_wdt
+    set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+    global $var_iemgui_min_wdt
+    set var_iemgui_hgt [concat iemgui_hgt_$vid]
+    global $var_iemgui_hgt
+    set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+    global $var_iemgui_min_hgt
+    
+    if {[eval concat $$var_iemgui_wdt] < [eval concat $$var_iemgui_min_wdt]} {
+        set $var_iemgui_wdt [eval concat $$var_iemgui_min_wdt]
+        $id.dim.w_ent configure -textvariable $var_iemgui_wdt
+    }
+    if {[eval concat $$var_iemgui_hgt] < [eval concat $$var_iemgui_min_hgt]} {
+        set $var_iemgui_hgt [eval concat $$var_iemgui_min_hgt]
+        $id.dim.h_ent configure -textvariable $var_iemgui_hgt
+    }
+}
+
+proc iemgui_clip_num {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_num [concat iemgui_num_$vid]
+    global $var_iemgui_num
+    
+    if {[eval concat $$var_iemgui_num] > 2000} {
+        set $var_iemgui_num 2000
+        $id.para.num_ent configure -textvariable $var_iemgui_num
+    }
+    if {[eval concat $$var_iemgui_num] < 1} {
+        set $var_iemgui_num 1
+        $id.para.num_ent configure -textvariable $var_iemgui_num
+    }
+}
+
+proc iemgui_sched_rng {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+    global $var_iemgui_min_rng
+    set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+    global $var_iemgui_max_rng
+    set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
+    global $var_iemgui_rng_sch
+
+    global iemgui_define_min_flashhold
+    global iemgui_define_min_flashbreak
+    
+    if {[eval concat $$var_iemgui_rng_sch] == 2} {
+        if {[eval concat $$var_iemgui_max_rng] < [eval concat $$var_iemgui_min_rng]} {
+            set hhh [eval concat $$var_iemgui_min_rng]
+            set $var_iemgui_min_rng [eval concat $$var_iemgui_max_rng]
+            set $var_iemgui_max_rng $hhh
+            $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+            $id.rng.min_ent configure -textvariable $var_iemgui_min_rng }
+        if {[eval concat $$var_iemgui_max_rng] < $iemgui_define_min_flashhold} {
+            set $var_iemgui_max_rng $iemgui_define_min_flashhold
+            $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+        }
+        if {[eval concat $$var_iemgui_min_rng] < $iemgui_define_min_flashbreak} {
+            set $var_iemgui_min_rng $iemgui_define_min_flashbreak
+            $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+        }
+    }
+    if {[eval concat $$var_iemgui_rng_sch] == 1} {
+        if {[eval concat $$var_iemgui_min_rng] == 0.0} {
+            set $var_iemgui_min_rng 1.0
+            $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+        }
+    }
+}
+
+proc iemgui_verify_rng {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+    global $var_iemgui_min_rng
+    set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+    global $var_iemgui_max_rng
+    set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+    global $var_iemgui_lin0_log1
+    
+    if {[eval concat $$var_iemgui_lin0_log1] == 1} {
+        if {[eval concat $$var_iemgui_max_rng] == 0.0 && [eval concat $$var_iemgui_min_rng] == 0.0} {
+            set $var_iemgui_max_rng 1.0
+            $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+            }
+        if {[eval concat $$var_iemgui_max_rng] > 0} {
+            if {[eval concat $$var_iemgui_min_rng] <= 0} {
+                set $var_iemgui_min_rng [expr [eval concat $$var_iemgui_max_rng] * 0.01]
+                $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+            }
+        } else {
+            if {[eval concat $$var_iemgui_min_rng] > 0} {
+                set $var_iemgui_max_rng [expr [eval concat $$var_iemgui_min_rng] * 0.01]
+                $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+            }
+        }
+    }
+}
+
+proc iemgui_clip_fontsize {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+    global $var_iemgui_gn_fs
+    
+    global iemgui_define_min_fontsize
+
+    if {[eval concat $$var_iemgui_gn_fs] < $iemgui_define_min_fontsize} {
+        set $var_iemgui_gn_fs $iemgui_define_min_fontsize
+        $id.gnfs.fs_ent configure -textvariable $var_iemgui_gn_fs
+    }
+}
+
+proc iemgui_set_col_example {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_bcol [concat iemgui_bcol_$vid]
+    global $var_iemgui_bcol
+    set var_iemgui_fcol [concat iemgui_fcol_$vid]
+    global $var_iemgui_fcol
+    set var_iemgui_lcol [concat iemgui_lcol_$vid]
+    global $var_iemgui_lcol
+    
+    $id.col_example_choose.lb_bk configure \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]]
+    
+    if { [eval concat $$var_iemgui_fcol] >= 0 } {
+       $id.col_example_choose.fr_bk configure \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]]
+    } else {
+       $id.col_example_choose.fr_bk configure \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]]}
+}
+
+proc iemgui_preset_col {id presetcol} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+    global $var_iemgui_l2_f1_b0
+    set var_iemgui_bcol [concat iemgui_bcol_$vid]
+    global $var_iemgui_bcol
+    set var_iemgui_fcol [concat iemgui_fcol_$vid]
+    global $var_iemgui_fcol
+    set var_iemgui_lcol [concat iemgui_lcol_$vid]
+    global $var_iemgui_lcol
+    
+    if { [eval concat $$var_iemgui_l2_f1_b0] == 0 } { set $var_iemgui_bcol $presetcol }
+    if { [eval concat $$var_iemgui_l2_f1_b0] == 1 } { set $var_iemgui_fcol $presetcol }
+    if { [eval concat $$var_iemgui_l2_f1_b0] == 2 } { set $var_iemgui_lcol $presetcol }
+    iemgui_set_col_example $id
+}
+
+proc iemgui_choose_col_bkfrlb {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+    global $var_iemgui_l2_f1_b0
+    set var_iemgui_bcol [concat iemgui_bcol_$vid]
+    global $var_iemgui_bcol
+    set var_iemgui_fcol [concat iemgui_fcol_$vid]
+    global $var_iemgui_fcol
+    set var_iemgui_lcol [concat iemgui_lcol_$vid]
+    global $var_iemgui_lcol
+    
+    if {[eval concat $$var_iemgui_l2_f1_b0] == 0} {
+        set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC]
+        set helpstring [tk_chooseColor -title "Background-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_bcol]]]
+        if { $helpstring != "" } {
+              set $var_iemgui_bcol [string replace $helpstring 0 0 "0x"]
+              set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC] }
+    }
+    if {[eval concat $$var_iemgui_l2_f1_b0] == 1} {
+        set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC]
+        set helpstring [tk_chooseColor -title "Front-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_fcol]]]
+        if { $helpstring != "" } {
+              set $var_iemgui_fcol [string replace $helpstring 0 0 "0x"]
+              set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC] }
+    }
+    if {[eval concat $$var_iemgui_l2_f1_b0] == 2} {
+        set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC]
+        set helpstring [tk_chooseColor -title "Label-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_lcol]]]
+        if { $helpstring != "" } {
+              set $var_iemgui_lcol [string replace $helpstring 0 0 "0x"]
+              set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC] }
+    }
+    iemgui_set_col_example $id
+}
+
+proc iemgui_lilo {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+    global $var_iemgui_lin0_log1
+    set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+    global $var_iemgui_lilo0
+    set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+    global $var_iemgui_lilo1
+   
+    iemgui_sched_rng $id
+
+    if {[eval concat $$var_iemgui_lin0_log1] == 0} {
+        set $var_iemgui_lin0_log1 1
+        $id.para.lilo configure -text [eval concat $$var_iemgui_lilo1]
+        iemgui_verify_rng $id
+        iemgui_sched_rng $id
+    } else {
+        set $var_iemgui_lin0_log1 0
+        $id.para.lilo configure -text [eval concat $$var_iemgui_lilo0]
+    }
+}
+
+proc iemgui_toggle_font {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+    global $var_iemgui_gn_f
+    
+    set $var_iemgui_gn_f [expr [eval concat $$var_iemgui_gn_f] + 1]
+    if {[eval concat $$var_iemgui_gn_f] > 2} {set $var_iemgui_gn_f 0}
+    if {[eval concat $$var_iemgui_gn_f] == 0} {$id.gnfs.fb configure -text "courier" -font {courier 10 bold}}
+    if {[eval concat $$var_iemgui_gn_f] == 1} {$id.gnfs.fb configure -text "helvetica" -font {helvetica 10 bold}}
+    if {[eval concat $$var_iemgui_gn_f] == 2} {$id.gnfs.fb configure -text "times" -font {times 10 bold}}
+}
+
+proc iemgui_lb {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+    global $var_iemgui_loadbang
+
+    if {[eval concat $$var_iemgui_loadbang] == 0} {
+        set $var_iemgui_loadbang 1
+        $id.para.lb configure -text "init"
+    } else {
+        set $var_iemgui_loadbang 0
+        $id.para.lb configure -text "no init"
+    }
+}
+
+proc iemgui_stdy_jmp {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_steady [concat iemgui_steady_$vid]
+    global $var_iemgui_steady
+    
+    if {[eval concat $$var_iemgui_steady]} {
+        set $var_iemgui_steady 0
+        $id.para.stdy_jmp configure -text "jump on click"
+    } else {
+        set $var_iemgui_steady 1
+        $id.para.stdy_jmp configure -text "steady on click"
+    }
+}
+
+proc iemgui_apply {id} {
+    set vid [string trimleft $id .]
+
+    set var_iemgui_wdt [concat iemgui_wdt_$vid]
+    global $var_iemgui_wdt
+    set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+    global $var_iemgui_min_wdt
+    set var_iemgui_hgt [concat iemgui_hgt_$vid]
+    global $var_iemgui_hgt
+    set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+    global $var_iemgui_min_hgt
+    set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+    global $var_iemgui_min_rng
+    set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+    global $var_iemgui_max_rng
+    set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+    global $var_iemgui_lin0_log1
+    set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+    global $var_iemgui_lilo0
+    set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+    global $var_iemgui_lilo1
+    set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+    global $var_iemgui_loadbang
+    set var_iemgui_num [concat iemgui_num_$vid]
+    global $var_iemgui_num
+    set var_iemgui_steady [concat iemgui_steady_$vid]
+    global $var_iemgui_steady
+    set var_iemgui_snd [concat iemgui_snd_$vid]
+    global $var_iemgui_snd
+    set var_iemgui_rcv [concat iemgui_rcv_$vid]
+    global $var_iemgui_rcv
+    set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
+    global $var_iemgui_gui_nam
+    set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
+    global $var_iemgui_gn_dx
+    set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
+    global $var_iemgui_gn_dy
+    set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+    global $var_iemgui_gn_f
+    set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+    global $var_iemgui_gn_fs
+    set var_iemgui_bcol [concat iemgui_bcol_$vid]
+    global $var_iemgui_bcol
+    set var_iemgui_fcol [concat iemgui_fcol_$vid]
+    global $var_iemgui_fcol
+    set var_iemgui_lcol [concat iemgui_lcol_$vid]
+    global $var_iemgui_lcol
+    
+    iemgui_clip_dim $id
+    iemgui_clip_num $id
+    iemgui_sched_rng $id
+    iemgui_verify_rng $id
+    iemgui_sched_rng $id
+    iemgui_clip_fontsize $id
+    
+    if {[eval concat $$var_iemgui_snd] == ""} {set hhhsnd "empty"} else {set hhhsnd [eval concat $$var_iemgui_snd]}
+    if {[eval concat $$var_iemgui_rcv] == ""} {set hhhrcv "empty"} else {set hhhrcv [eval concat $$var_iemgui_rcv]}
+    if {[eval concat $$var_iemgui_gui_nam] == ""} {set hhhgui_nam "empty"
+        } else {
+    set hhhgui_nam [eval concat $$var_iemgui_gui_nam]}
+
+    if {[string index $hhhsnd 0] == "$"} {
+       set hhhsnd [string replace $hhhsnd 0 0 #] }
+    if {[string index $hhhrcv 0] == "$"} {
+       set hhhrcv [string replace $hhhrcv 0 0 #] }
+    if {[string index $hhhgui_nam 0] == "$"} {
+       set hhhgui_nam [string replace $hhhgui_nam 0 0 #] }
+    
+    set hhhsnd [pdtk_unspace $hhhsnd]
+    set hhhrcv [pdtk_unspace $hhhrcv]
+    set hhhgui_nam [pdtk_unspace $hhhgui_nam]
+    
+    pd [concat $id dialog \
+        [eval concat $$var_iemgui_wdt] \
+        [eval concat $$var_iemgui_hgt] \
+        [eval concat $$var_iemgui_min_rng] \
+        [eval concat $$var_iemgui_max_rng] \
+        [eval concat $$var_iemgui_lin0_log1] \
+        [eval concat $$var_iemgui_loadbang] \
+        [eval concat $$var_iemgui_num] \
+        $hhhsnd \
+        $hhhrcv \
+        $hhhgui_nam \
+        [eval concat $$var_iemgui_gn_dx] \
+        [eval concat $$var_iemgui_gn_dy] \
+        [eval concat $$var_iemgui_gn_f] \
+        [eval concat $$var_iemgui_gn_fs] \
+        [eval concat $$var_iemgui_bcol] \
+        [eval concat $$var_iemgui_fcol] \
+        [eval concat $$var_iemgui_lcol] \
+        [eval concat $$var_iemgui_steady] \
+        \;]
+}
+
+proc iemgui_cancel {id} {pd [concat $id cancel \;]}
+
+proc iemgui_ok {id} {
+    iemgui_apply $id
+    iemgui_cancel $id
+}
+
+proc pdtk_iemgui_dialog {id mainheader \
+        dim_header wdt min_wdt wdt_label hgt min_hgt hgt_label \
+        rng_header min_rng min_rng_label max_rng max_rng_label rng_sched \
+        lin0_log1 lilo0_label lilo1_label loadbang steady num_label num \
+        snd rcv \
+        gui_name \
+        gn_dx gn_dy \
+        gn_f gn_fs \
+        bcol fcol lcol} {
+
+    set vid [string trimleft $id .]
+
+    set var_iemgui_wdt [concat iemgui_wdt_$vid]
+    global $var_iemgui_wdt
+    set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+    global $var_iemgui_min_wdt
+    set var_iemgui_hgt [concat iemgui_hgt_$vid]
+    global $var_iemgui_hgt
+    set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+    global $var_iemgui_min_hgt
+    set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+    global $var_iemgui_min_rng
+    set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+    global $var_iemgui_max_rng
+    set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
+    global $var_iemgui_rng_sch
+    set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+    global $var_iemgui_lin0_log1
+    set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+    global $var_iemgui_lilo0
+    set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+    global $var_iemgui_lilo1
+    set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+    global $var_iemgui_loadbang
+    set var_iemgui_num [concat iemgui_num_$vid]
+    global $var_iemgui_num
+    set var_iemgui_steady [concat iemgui_steady_$vid]
+    global $var_iemgui_steady
+    set var_iemgui_snd [concat iemgui_snd_$vid]
+    global $var_iemgui_snd
+    set var_iemgui_rcv [concat iemgui_rcv_$vid]
+    global $var_iemgui_rcv
+    set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
+    global $var_iemgui_gui_nam
+    set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
+    global $var_iemgui_gn_dx
+    set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
+    global $var_iemgui_gn_dy
+    set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+    global $var_iemgui_gn_f
+    set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+    global $var_iemgui_gn_fs
+    set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+    global $var_iemgui_l2_f1_b0
+    set var_iemgui_bcol [concat iemgui_bcol_$vid]
+    global $var_iemgui_bcol
+    set var_iemgui_fcol [concat iemgui_fcol_$vid]
+    global $var_iemgui_fcol
+    set var_iemgui_lcol [concat iemgui_lcol_$vid]
+    global $var_iemgui_lcol
+
+    set $var_iemgui_wdt $wdt
+    set $var_iemgui_min_wdt $min_wdt
+    set $var_iemgui_hgt $hgt
+    set $var_iemgui_min_hgt $min_hgt
+    set $var_iemgui_min_rng $min_rng
+    set $var_iemgui_max_rng $max_rng
+    set $var_iemgui_rng_sch $rng_sched
+    set $var_iemgui_lin0_log1 $lin0_log1
+    set $var_iemgui_lilo0 $lilo0_label
+    set $var_iemgui_lilo1 $lilo1_label
+    set $var_iemgui_loadbang $loadbang
+    set $var_iemgui_num $num
+    set $var_iemgui_steady $steady
+    if {$snd == "empty"} {set $var_iemgui_snd [format ""]
+        } else {set $var_iemgui_snd [format "%s" $snd]}
+    if {$rcv == "empty"} {set $var_iemgui_rcv [format ""]
+        } else {set $var_iemgui_rcv [format "%s" $rcv]}
+    if {$gui_name == "empty"} {set $var_iemgui_gui_nam [format ""]
+        } else {set $var_iemgui_gui_nam [format "%s" $gui_name]}
+    
+    if {[string index [eval concat $$var_iemgui_snd] 0] == "#"} {
+       set $var_iemgui_snd [string replace [eval concat $$var_iemgui_snd] 0 0 $] }
+    if {[string index [eval concat $$var_iemgui_rcv] 0] == "#"} {
+       set $var_iemgui_rcv [string replace [eval concat $$var_iemgui_rcv] 0 0 $] }
+    if {[string index [eval concat $$var_iemgui_gui_nam] 0] == "#"} {
+       set $var_iemgui_gui_nam [string replace [eval concat $$var_iemgui_gui_nam] 0 0 $] }
+    set $var_iemgui_gn_dx $gn_dx
+    set $var_iemgui_gn_dy $gn_dy
+    set $var_iemgui_gn_f $gn_f
+    set $var_iemgui_gn_fs $gn_fs
+    
+    set $var_iemgui_bcol $bcol
+    set $var_iemgui_fcol $fcol
+    set $var_iemgui_lcol $lcol
+    
+    set $var_iemgui_l2_f1_b0 0
+
+    toplevel $id
+    wm title $id [format "%s-PROPERTIES" $mainheader]
+    wm protocol $id WM_DELETE_WINDOW [concat iemgui_cancel $id]
+    
+    frame $id.dim
+    pack $id.dim -side top
+    label $id.dim.head -text $dim_header
+    label $id.dim.w_lab -text $wdt_label -width 6
+    entry $id.dim.w_ent -textvariable $var_iemgui_wdt -width 5
+    label $id.dim.dummy1 -text " " -width 10
+    label $id.dim.h_lab -text $hgt_label -width 6
+    entry $id.dim.h_ent -textvariable $var_iemgui_hgt -width 5
+    pack $id.dim.head -side top
+    pack $id.dim.w_lab $id.dim.w_ent $id.dim.dummy1 -side left
+    if { $hgt_label != "empty" } {
+        pack $id.dim.h_lab $id.dim.h_ent -side left}
+
+    frame $id.rng
+    pack $id.rng -side top
+    label $id.rng.head -text $rng_header
+    label $id.rng.min_lab -text $min_rng_label -width 6
+    entry $id.rng.min_ent -textvariable $var_iemgui_min_rng -width 9
+    label $id.rng.dummy1 -text " " -width 1
+    label $id.rng.max_lab -text $max_rng_label -width 8
+    entry $id.rng.max_ent -textvariable $var_iemgui_max_rng -width 9
+    if { $rng_header != "empty" } {
+        pack $id.rng.head -side top
+        if { $min_rng_label != "empty" } {
+            pack $id.rng.min_lab $id.rng.min_ent -side left}
+        if { $max_rng_label != "empty" } {
+            pack $id.rng.dummy1 \
+            $id.rng.max_lab $id.rng.max_ent -side left} }
+    
+    if { [eval concat $$var_iemgui_lin0_log1] >= 0 || [eval concat $$var_iemgui_loadbang] >= 0 || [eval concat $$var_iemgui_num] > 0 || [eval concat $$var_iemgui_steady] >= 0 } {
+        label $id.space1 -text "---------------------------------"
+        pack $id.space1 -side top }
+
+    frame $id.para
+    pack $id.para -side top
+    label $id.para.dummy2 -text "" -width 1
+    label $id.para.dummy3 -text "" -width 1
+    if {[eval concat $$var_iemgui_lin0_log1] == 0} {
+        button $id.para.lilo -text [eval concat $$var_iemgui_lilo0] -width 5 -command "iemgui_lilo $id" }
+    if {[eval concat $$var_iemgui_lin0_log1] == 1} {
+        button $id.para.lilo -text [eval concat $$var_iemgui_lilo1] -width 5 -command "iemgui_lilo $id" }
+    if {[eval concat $$var_iemgui_loadbang] == 0} {
+        button $id.para.lb -text "no init" -width 5 -command "iemgui_lb $id" }
+    if {[eval concat $$var_iemgui_loadbang] == 1} {
+        button $id.para.lb -text "init" -width 5 -command "iemgui_lb $id" }
+    label $id.para.num_lab -text $num_label -width 9
+    entry $id.para.num_ent -textvariable $var_iemgui_num -width 4
+    if {[eval concat $$var_iemgui_steady] == 0} {
+        button $id.para.stdy_jmp -text "jump on click" -width 11 -command "iemgui_stdy_jmp $id" }
+    if {[eval concat $$var_iemgui_steady] == 1} {
+        button $id.para.stdy_jmp -text "steady on click" -width 11 -command "iemgui_stdy_jmp $id" }
+    if {[eval concat $$var_iemgui_lin0_log1] >= 0} {
+        pack $id.para.lilo -side left -expand 1}
+    if {[eval concat $$var_iemgui_loadbang] >= 0} {
+        pack $id.para.dummy2 $id.para.lb -side left -expand 1}
+    if {[eval concat $$var_iemgui_num] > 0} {
+        pack $id.para.dummy3 $id.para.num_lab $id.para.num_ent -side left -expand 1}
+    if {[eval concat $$var_iemgui_steady] >= 0} {
+        pack $id.para.dummy3 $id.para.stdy_jmp -side left -expand 1}
+    if { $snd != "nosndno" || $rcv != "norcvno" } {
+        label $id.space2 -text "---------------------------------"
+        pack $id.space2 -side top }
+    
+    frame $id.snd
+    pack $id.snd -side top
+    label $id.snd.dummy1 -text "" -width 2
+    label $id.snd.lab -text "send-symbol:" -width 12
+    entry $id.snd.ent -textvariable $var_iemgui_snd -width 20
+    if { $snd != "nosndno" } {
+        pack $id.snd.dummy1 $id.snd.lab $id.snd.ent -side left}
+    
+    frame $id.rcv
+    pack $id.rcv -side top
+    label $id.rcv.lab -text "receive-symbol:" -width 15
+    entry $id.rcv.ent -textvariable $var_iemgui_rcv -width 20
+    if { $rcv != "norcvno" } {
+        pack $id.rcv.lab $id.rcv.ent -side left}
+    
+    frame $id.gnam
+    pack $id.gnam -side top
+    label $id.gnam.head -text "--------------label:---------------"
+    label $id.gnam.dummy1 -text "" -width 1
+    label $id.gnam.lab -text "name:" -width 6
+    entry $id.gnam.ent -textvariable $var_iemgui_gui_nam -width 29
+    label $id.gnam.dummy2 -text "" -width 1
+    pack $id.gnam.head -side top
+    pack $id.gnam.dummy1 $id.gnam.lab $id.gnam.ent $id.gnam.dummy2 -side left
+    
+    frame $id.gnxy
+    pack $id.gnxy -side top
+    label $id.gnxy.x_lab -text "x_off:" -width 6
+    entry $id.gnxy.x_ent -textvariable $var_iemgui_gn_dx -width 5
+    label $id.gnxy.dummy1 -text " " -width 10
+    label $id.gnxy.y_lab -text "y_off:" -width 6
+    entry $id.gnxy.y_ent -textvariable $var_iemgui_gn_dy -width 5
+    pack $id.gnxy.x_lab $id.gnxy.x_ent $id.gnxy.dummy1 \
+         $id.gnxy.y_lab $id.gnxy.y_ent -side left
+    
+    frame $id.gnfs
+    pack $id.gnfs -side top
+    label $id.gnfs.f_lab -text "font:" -width 6
+    if {[eval concat $$var_iemgui_gn_f] == 0} {
+        button $id.gnfs.fb -text "courier" -font {courier 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+    if {[eval concat $$var_iemgui_gn_f] == 1} {
+        button $id.gnfs.fb -text "helvetica" -font {helvetica 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+    if {[eval concat $$var_iemgui_gn_f] == 2} {
+        button $id.gnfs.fb -text "times" -font {times 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+    label $id.gnfs.dummy1 -text "" -width 1
+    label $id.gnfs.fs_lab -text "fontsize:" -width 8
+    entry $id.gnfs.fs_ent -textvariable $var_iemgui_gn_fs -width 5
+    pack $id.gnfs.f_lab $id.gnfs.fb $id.gnfs.dummy1 \
+         $id.gnfs.fs_lab $id.gnfs.fs_ent -side left
+    
+    label $id.col_head -text "--------------colors:--------------"
+    pack $id.col_head -side top
+    
+    frame $id.col_select
+    pack $id.col_select -side top
+    radiobutton $id.col_select.radio0 -value 0 -variable $var_iemgui_l2_f1_b0 \
+       -text "backgd" -width 5
+    radiobutton $id.col_select.radio1 -value 1 -variable $var_iemgui_l2_f1_b0 \
+       -text "front" -width 5
+    radiobutton $id.col_select.radio2 -value 2 -variable $var_iemgui_l2_f1_b0 \
+       -text "label" -width 5
+    if { [eval concat $$var_iemgui_fcol] >= 0 } {
+         pack $id.col_select.radio0 $id.col_select.radio1 $id.col_select.radio2 -side left
+       } else {pack $id.col_select.radio0 $id.col_select.radio2 -side left}
+    
+    frame $id.col_example_choose
+    pack $id.col_example_choose -side top
+    button $id.col_example_choose.but -text "compose color" -width 10 \
+             -command "iemgui_choose_col_bkfrlb $id"
+    label $id.col_example_choose.dummy1 -text "" -width 1
+    if { [eval concat $$var_iemgui_fcol] >= 0 } {
+      button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] -pady 2
+    } else {
+      button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] -pady 2}
+    button $id.col_example_choose.lb_bk -text "testlabel" -width 7 \
+       -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+       -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
+       -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] -pady 2
+    
+    pack $id.col_example_choose.but $id.col_example_choose.dummy1 \
+       $id.col_example_choose.fr_bk $id.col_example_choose.lb_bk -side left
+    
+    label $id.space3 -text "------or click color preset:-------"
+    pack $id.space3 -side top
+    
+    frame $id.bcol
+    pack $id.bcol -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 16579836 14737632 12369084 \
+      16572640 16572608 16579784 14220504 14220540 14476540 16308476 } {
+        button $id.bcol.c$i -background [format "#%6.6x" $hexcol] \
+            -activebackground [format "#%6.6x" $hexcol] \
+            -font {courier 2 normal} -padx 7 -pady 6 \
+            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+    pack $id.bcol.c0 $id.bcol.c1 $id.bcol.c2 $id.bcol.c3 $id.bcol.c4 \
+        $id.bcol.c5 $id.bcol.c6 $id.bcol.c7 $id.bcol.c8 $id.bcol.c9 -side left
+    
+    frame $id.fcol
+    pack $id.fcol -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 10526880 8158332 6316128 \
+      16525352 16559172 15263784 1370132 2684148 3952892 16003312 } {
+        button $id.fcol.c$i -background [format "#%6.6x" $hexcol] \
+            -activebackground [format "#%6.6x" $hexcol] \
+            -font {courier 2 normal} -padx 7 -pady 6 \
+            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+    pack $id.fcol.c0 $id.fcol.c1 $id.fcol.c2 $id.fcol.c3 $id.fcol.c4 \
+        $id.fcol.c5 $id.fcol.c6 $id.fcol.c7 $id.fcol.c8 $id.fcol.c9 -side left
+    
+    frame $id.lcol
+    pack $id.lcol -side top
+    foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 4210752 2105376 0 \
+      9177096 5779456 7874580 2641940 17488 5256 5767248 } {
+        button $id.lcol.c$i -background [format "#%6.6x" $hexcol] \
+            -activebackground [format "#%6.6x" $hexcol] \
+            -font {courier 2 normal} -padx 7 -pady 6 \
+            -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+    pack $id.lcol.c0 $id.lcol.c1 $id.lcol.c2 $id.lcol.c3 $id.lcol.c4 \
+        $id.lcol.c5 $id.lcol.c6 $id.lcol.c7 $id.lcol.c8 $id.lcol.c9 -side left
+    
+    
+    label $id.space4 -text "---------------------------------"
+    pack $id.space4 -side top
+    
+    frame $id.cao
+    pack $id.cao -side top
+    button $id.cao.cancel -text {Cancel} -width 6 \
+        -command "iemgui_cancel $id"
+    label $id.cao.dummy1 -text "" -width 3
+    button $id.cao.apply -text {Apply} -width 6 \
+        -command "iemgui_apply $id"
+    label $id.cao.dummy2 -text "" -width 3
+    button $id.cao.ok -text {OK} -width 6 \
+        -command "iemgui_ok $id"
+    pack $id.cao.cancel $id.cao.dummy1 \
+        $id.cao.apply $id.cao.dummy2 \
+        $id.cao.ok -side left
+    
+    label $id.space5 -text ""
+    pack $id.space5 -side top
+
+    if {[info tclversion] < 8.4} {
+        bind $id <Key-Tab> {tkTabToWindow [tk_focusNext %W]}
+        bind $id <<PrevWindow>> {tkTabToWindow [tk_focusPrev %W]}
+    } else {
+        bind $id <Key-Tab> {tk::TabToWindow [tk_focusNext %W]}
+        bind $id <<PrevWindow>> {tk::TabToWindow [tk_focusPrev %W]}
+    }
+    
+    bind $id.dim.w_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.dim.h_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.rng.min_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.rng.max_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.para.num_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.snd.ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.rcv.ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.gnam.ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.gnxy.x_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.gnxy.y_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.gnfs.fs_ent <KeyPress-Return> [concat iemgui_ok $id]
+    bind $id.cao.ok <KeyPress-Return> [concat iemgui_ok $id]
+    pdtk_standardkeybindings $id.dim.w_ent
+    pdtk_standardkeybindings $id.dim.h_ent
+    pdtk_standardkeybindings $id.rng.min_ent
+    pdtk_standardkeybindings $id.rng.max_ent
+    pdtk_standardkeybindings $id.para.num_ent
+    pdtk_standardkeybindings $id.snd.ent
+    pdtk_standardkeybindings $id.rcv.ent
+    pdtk_standardkeybindings $id.gnam.ent
+    pdtk_standardkeybindings $id.gnxy.x_ent
+    pdtk_standardkeybindings $id.gnxy.y_ent
+    pdtk_standardkeybindings $id.gnfs.fs_ent
+    pdtk_standardkeybindings $id.cao.ok
+    
+    $id.dim.w_ent select from 0
+    $id.dim.w_ent select adjust end
+    focus $id.dim.w_ent
+}
+# end of change "iemlib"
+
+############ pdtk_array_dialog -- dialog window for arrays #########
+# see comments above (pdtk_gatom_dialog) about variable name handling 
+
+proc array_apply {id} {
+# strip "." from the TK id to make a variable name suffix 
+    set vid [string trimleft $id .]
+# for each variable, make a local variable to hold its name...
+    set var_array_name [concat array_name_$vid]
+    global $var_array_name
+    set var_array_n [concat array_n_$vid]
+    global $var_array_n
+    set var_array_saveit [concat array_saveit_$vid]
+    global $var_array_saveit
+    set var_array_drawasrects [concat array_drawasrects_$vid]
+    global $var_array_drawasrects
+    set var_array_otherflag [concat array_otherflag_$vid]
+    global $var_array_otherflag
+    set mofo [eval concat $$var_array_name]
+    if {[string index $mofo 0] == "$"} {
+       set mofo [string replace $mofo 0 0 #] }
+
+    set saveit [eval concat $$var_array_saveit]
+    set drawasrects [eval concat $$var_array_drawasrects]
+
+    pd [concat $id arraydialog $mofo \
+        [eval concat $$var_array_n] \
+        [expr $saveit + 2 * $drawasrects] \
+        [eval concat $$var_array_otherflag] \
+        \;]
+}
+
+# jsarlo
+proc array_viewlist {id name page} {
+    pd [concat $id arrayviewlistnew\;]
+}
+# end jsarlo
+
+proc array_cancel {id} {
+    set cmd [concat $id cancel \;]
+    pd $cmd
+}
+
+proc array_ok {id} {
+    array_apply $id
+    array_cancel $id
+}
+
+proc pdtk_array_dialog {id name n flags newone} {
+    set vid [string trimleft $id .]
+
+    set var_array_name [concat array_name_$vid]
+    global $var_array_name
+    set var_array_n [concat array_n_$vid]
+    global $var_array_n
+    set var_array_saveit [concat array_saveit_$vid]
+    global $var_array_saveit
+    set var_array_drawasrects [concat array_drawasrects_$vid]
+    global $var_array_drawasrects
+    set var_array_otherflag [concat array_otherflag_$vid]
+    global $var_array_otherflag
+
+    set $var_array_name $name
+    set $var_array_n $n
+    set $var_array_saveit [expr ( $flags & 1 ) != 0]
+    set $var_array_drawasrects [expr ( $flags & 2 ) != 0]
+    set $var_array_otherflag 0
+
+    toplevel $id
+    wm title $id {array}
+    wm protocol $id WM_DELETE_WINDOW [concat array_cancel $id]
+
+    frame $id.name
+    pack $id.name -side top
+    label $id.name.label -text "name"
+    entry $id.name.entry -textvariable $var_array_name
+    pack $id.name.label $id.name.entry -side left
+
+    frame $id.n
+    pack $id.n -side top
+    label $id.n.label -text "size"
+    entry $id.n.entry -textvariable $var_array_n
+    pack $id.n.label $id.n.entry -side left
+
+    checkbutton $id.saveme -text {save contents} -variable $var_array_saveit \
+        -anchor w
+    pack $id.saveme -side top
+
+    frame $id.drawasrects
+    pack $id.drawasrects -side top
+    radiobutton $id.drawasrects.drawasrects0 -value 0 \
+        -variable $var_array_drawasrects \
+        -text "draw as points"
+    radiobutton $id.drawasrects.drawasrects1 -value 1 \
+        -variable $var_array_drawasrects \
+        -text "polygon"
+    radiobutton $id.drawasrects.drawasrects2 -value 2 \
+        -variable $var_array_drawasrects \
+        -text "bezier curve"
+    pack $id.drawasrects.drawasrects0 -side top -anchor w
+    pack $id.drawasrects.drawasrects1 -side top -anchor w
+    pack $id.drawasrects.drawasrects2 -side top -anchor w
+
+    if {$newone != 0} {
+        frame $id.radio
+        pack $id.radio -side top
+        radiobutton $id.radio.radio0 -value 0 \
+            -variable $var_array_otherflag \
+            -text "in new graph"
+        radiobutton $id.radio.radio1 -value 1 \
+            -variable $var_array_otherflag \
+            -text "in last graph"
+        pack $id.radio.radio0 -side top -anchor w
+        pack $id.radio.radio1 -side top -anchor w
+    } else {    
+        checkbutton $id.deleteme -text {delete me} \
+            -variable $var_array_otherflag -anchor w
+        pack $id.deleteme -side top
+    }
+    # jsarlo
+    if {$newone == 0} {
+      button $id.listview -text {View list}\
+        -command "array_viewlist $id $name 0"
+      pack $id.listview -side left
+    }
+    # end jsarlo
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "array_cancel $id"
+    if {$newone == 0} {button $id.buttonframe.apply -text {Apply}\
+        -command "array_apply $id"}
+    button $id.buttonframe.ok -text {OK}\
+        -command "array_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    if {$newone == 0} {pack $id.buttonframe.apply -side left -expand 1}
+    pack $id.buttonframe.ok -side left -expand 1
+    
+    bind $id.name.entry <KeyPress-Return> [concat array_ok $id]
+    bind $id.n.entry <KeyPress-Return> [concat array_ok $id]
+    pdtk_standardkeybindings $id.name.entry
+    pdtk_standardkeybindings $id.n.entry
+    $id.name.entry select from 0
+    $id.name.entry select adjust end
+    focus $id.name.entry
+}
+
+############ pdtk_canvas_dialog -- dialog window for canvass #########
+# see comments above (pdtk_gatom_dialog) about variable name handling 
+
+proc canvas_apply {id} {
+# strip "." from the TK id to make a variable name suffix 
+    set vid [string trimleft $id .]
+# for each variable, make a local variable to hold its name...
+
+    set var_canvas_xscale [concat canvas_xscale_$vid]
+    global $var_canvas_xscale
+    set var_canvas_yscale [concat canvas_yscale_$vid]
+    global $var_canvas_yscale
+    set var_canvas_graphme [concat canvas_graphme_$vid]
+    global $var_canvas_graphme
+    set var_canvas_hidetext [concat canvas_hidetext_$vid]
+    global $var_canvas_hidetext
+    set var_canvas_x1 [concat canvas_x1_$vid]
+    global $var_canvas_x1
+    set var_canvas_x2 [concat canvas_x2_$vid]
+    global $var_canvas_x2
+    set var_canvas_xpix [concat canvas_xpix_$vid]
+    global $var_canvas_xpix
+    set var_canvas_xmargin [concat canvas_xmargin_$vid]
+    global $var_canvas_xmargin
+    set var_canvas_y1 [concat canvas_y1_$vid]
+    global $var_canvas_y1
+    set var_canvas_y2 [concat canvas_y2_$vid]
+    global $var_canvas_y2
+    set var_canvas_ypix [concat canvas_ypix_$vid]
+    global $var_canvas_ypix
+    set var_canvas_ymargin [concat canvas_ymargin_$vid]
+    global $var_canvas_ymargin
+
+    pd [concat $id donecanvasdialog \
+        [eval concat $$var_canvas_xscale] \
+        [eval concat $$var_canvas_yscale] \
+        [expr [eval concat $$var_canvas_graphme]+2*[eval concat $$var_canvas_hidetext]] \
+        [eval concat $$var_canvas_x1] \
+        [eval concat $$var_canvas_y1] \
+        [eval concat $$var_canvas_x2] \
+        [eval concat $$var_canvas_y2] \
+        [eval concat $$var_canvas_xpix] \
+        [eval concat $$var_canvas_ypix] \
+        [eval concat $$var_canvas_xmargin] \
+        [eval concat $$var_canvas_ymargin] \
+        \;]
+}
+
+proc canvas_cancel {id} {
+    set cmd [concat $id cancel \;]
+    pd $cmd
+}
+
+proc canvas_ok {id} {
+    canvas_apply $id
+    canvas_cancel $id
+}
+
+proc canvas_checkcommand {id} {
+    set vid [string trimleft $id .]
+#    puts stderr [concat canvas_checkcommand $id $vid]
+
+    set var_canvas_xscale [concat canvas_xscale_$vid]
+    global $var_canvas_xscale
+    set var_canvas_yscale [concat canvas_yscale_$vid]
+    global $var_canvas_yscale
+    set var_canvas_graphme [concat canvas_graphme_$vid]
+    global $var_canvas_graphme
+    set var_canvas_hidetext [concat canvas_hidetext_$vid]
+    global $var_canvas_hidetext
+    set var_canvas_x1 [concat canvas_x1_$vid]
+    global $var_canvas_x1
+    set var_canvas_x2 [concat canvas_x2_$vid]
+    global $var_canvas_x2
+    set var_canvas_xpix [concat canvas_xpix_$vid]
+    global $var_canvas_xpix
+    set var_canvas_xmargin [concat canvas_xmargin_$vid]
+    global $var_canvas_xmargin
+    set var_canvas_y1 [concat canvas_y1_$vid]
+    global $var_canvas_y1
+    set var_canvas_y2 [concat canvas_y2_$vid]
+    global $var_canvas_y2
+    set var_canvas_ypix [concat canvas_ypix_$vid]
+    global $var_canvas_ypix
+    set var_canvas_ymargin [concat canvas_ymargin_$vid]
+    global $var_canvas_ymargin
+
+    if { [eval concat $$var_canvas_graphme] != 0 } {
+        $id.hidetext configure -state normal
+        $id.xrange.entry1 configure -state normal
+        $id.xrange.entry2 configure -state normal
+        $id.xrange.entry3 configure -state normal
+        $id.xrange.entry4 configure -state normal
+        $id.yrange.entry1 configure -state normal
+        $id.yrange.entry2 configure -state normal
+        $id.yrange.entry3 configure -state normal
+        $id.yrange.entry4 configure -state normal
+        $id.xscale.entry configure -state disabled
+        $id.yscale.entry configure -state disabled
+        set x1 [eval concat $$var_canvas_x1]
+        set y1 [eval concat $$var_canvas_y1]
+        set x2 [eval concat $$var_canvas_x2]
+        set y2 [eval concat $$var_canvas_y2]
+        if { [eval concat $$var_canvas_x1] == 0 && \
+             [eval concat $$var_canvas_y1] == 0 && \
+             [eval concat $$var_canvas_x2] == 0 && \
+             [eval concat $$var_canvas_y2] == 0 } {
+                set $var_canvas_x2 1
+                set $var_canvas_y2 1
+        }
+        if { [eval concat $$var_canvas_xpix] == 0 } {
+            set $var_canvas_xpix 85
+            set $var_canvas_xmargin 100
+        }
+        if { [eval concat $$var_canvas_ypix] == 0 } {
+            set $var_canvas_ypix 60
+            set $var_canvas_ymargin 100
+        }
+    } else {
+        $id.hidetext configure -state disabled
+        $id.xrange.entry1 configure -state disabled
+        $id.xrange.entry2 configure -state disabled
+        $id.xrange.entry3 configure -state disabled
+        $id.xrange.entry4 configure -state disabled
+        $id.yrange.entry1 configure -state disabled
+        $id.yrange.entry2 configure -state disabled
+        $id.yrange.entry3 configure -state disabled
+        $id.yrange.entry4 configure -state disabled
+        $id.xscale.entry configure -state normal
+        $id.yscale.entry configure -state normal
+        if { [eval concat $$var_canvas_xscale] == 0 } {
+            set $var_canvas_xscale 1
+        }
+        if { [eval concat $$var_canvas_yscale] == 0 } {
+            set $var_canvas_yscale -1
+        }
+    }
+}
+
+proc pdtk_canvas_dialog {id xscale yscale graphme x1 y1 x2 y2 \
+    xpix ypix xmargin ymargin} {
+    set vid [string trimleft $id .]
+
+    set var_canvas_xscale [concat canvas_xscale_$vid]
+    global $var_canvas_xscale
+    set var_canvas_yscale [concat canvas_yscale_$vid]
+    global $var_canvas_yscale
+    set var_canvas_graphme [concat canvas_graphme_$vid]
+    global $var_canvas_graphme
+    set var_canvas_hidetext [concat canvas_hidetext_$vid]
+    global $var_canvas_hidetext
+    set var_canvas_x1 [concat canvas_x1_$vid]
+    global $var_canvas_x1
+    set var_canvas_x2 [concat canvas_x2_$vid]
+    global $var_canvas_x2
+    set var_canvas_xpix [concat canvas_xpix_$vid]
+    global $var_canvas_xpix
+    set var_canvas_xmargin [concat canvas_xmargin_$vid]
+    global $var_canvas_xmargin
+    set var_canvas_y1 [concat canvas_y1_$vid]
+    global $var_canvas_y1
+    set var_canvas_y2 [concat canvas_y2_$vid]
+    global $var_canvas_y2
+    set var_canvas_ypix [concat canvas_ypix_$vid]
+    global $var_canvas_ypix
+    set var_canvas_ymargin [concat canvas_ymargin_$vid]
+    global $var_canvas_ymargin
+
+    set $var_canvas_xscale $xscale
+    set $var_canvas_yscale $yscale
+    set $var_canvas_graphme [expr ($graphme!=0)?1:0]
+    set $var_canvas_hidetext [expr ($graphme&2)?1:0]
+    set $var_canvas_x1 $x1
+    set $var_canvas_y1 $y1
+    set $var_canvas_x2 $x2
+    set $var_canvas_y2 $y2
+    set $var_canvas_xpix $xpix
+    set $var_canvas_ypix $ypix
+    set $var_canvas_xmargin $xmargin
+    set $var_canvas_ymargin $ymargin
+
+    toplevel $id
+    wm title $id {canvas}
+    wm protocol $id WM_DELETE_WINDOW [concat canvas_cancel $id]
+
+    label $id.toplabel -text "Canvas Properties"
+    pack $id.toplabel -side top
+    
+    frame $id.xscale
+    pack $id.xscale -side top
+    label $id.xscale.label -text "X units per pixel"
+    entry $id.xscale.entry -textvariable $var_canvas_xscale -width 10
+    pack $id.xscale.label $id.xscale.entry -side left
+
+    frame $id.yscale
+    pack $id.yscale -side top
+    label $id.yscale.label -text "Y units per pixel"
+    entry $id.yscale.entry -textvariable $var_canvas_yscale -width 10
+    pack $id.yscale.label $id.yscale.entry -side left
+
+    checkbutton $id.graphme -text {graph on parent} \
+        -variable $var_canvas_graphme -anchor w \
+        -command [concat canvas_checkcommand $id]
+    pack $id.graphme -side top
+
+    checkbutton $id.hidetext -text {hide object name and arguments} \
+        -variable $var_canvas_hidetext -anchor w \
+        -command [concat canvas_checkcommand $id]
+    pack $id.hidetext -side top
+
+    frame $id.xrange
+    pack $id.xrange -side top
+    label $id.xrange.label1 -text "X range: from"
+    entry $id.xrange.entry1 -textvariable $var_canvas_x1 -width 6
+    label $id.xrange.label2 -text "to"
+    entry $id.xrange.entry2 -textvariable $var_canvas_x2 -width 6
+    label $id.xrange.label3 -text "size"
+    entry $id.xrange.entry3 -textvariable $var_canvas_xpix -width 4
+    label $id.xrange.label4 -text "margin"
+    entry $id.xrange.entry4 -textvariable $var_canvas_xmargin -width 4
+    pack $id.xrange.label1 $id.xrange.entry1 \
+        $id.xrange.label2 $id.xrange.entry2 \
+        $id.xrange.label3 $id.xrange.entry3 \
+        $id.xrange.label4 $id.xrange.entry4 \
+        -side left
+
+    frame $id.yrange
+    pack $id.yrange -side top
+    label $id.yrange.label1 -text "Y range: from"
+    entry $id.yrange.entry1 -textvariable $var_canvas_y1 -width 6
+    label $id.yrange.label2 -text "to"
+    entry $id.yrange.entry2 -textvariable $var_canvas_y2 -width 6
+    label $id.yrange.label3 -text "size"
+    entry $id.yrange.entry3 -textvariable $var_canvas_ypix -width 4
+    label $id.yrange.label4 -text "margin"
+    entry $id.yrange.entry4 -textvariable $var_canvas_ymargin -width 4
+    pack $id.yrange.label1 $id.yrange.entry1 \
+        $id.yrange.label2 $id.yrange.entry2 \
+        $id.yrange.label3 $id.yrange.entry3 \
+        $id.yrange.label4 $id.yrange.entry4 \
+        -side left
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "canvas_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "canvas_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "canvas_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+
+    bind $id.xscale.entry <KeyPress-Return> [concat canvas_ok $id]
+    bind $id.yscale.entry <KeyPress-Return> [concat canvas_ok $id]
+    pdtk_standardkeybindings $id.xscale.entry
+    pdtk_standardkeybindings $id.yscale.entry
+    $id.xscale.entry select from 0
+    $id.xscale.entry select adjust end
+    focus $id.xscale.entry
+    canvas_checkcommand $id
+}
+
+############ pdtk_data_dialog -- run a data dialog #########
+proc dodata_send {name} {
+#    puts stderr [$name.text get 0.0 end]
+
+    for {set i 1} {[$name.text compare [concat $i.0 + 3 chars] < end]} \
+            {incr i 1} {
+#       puts stderr [concat it's [$name.text get $i.0 [expr $i + 1].0]]
+        set cmd [concat $name data [$name.text get $i.0 [expr $i + 1].0] \;]
+#       puts stderr $cmd
+        pd $cmd
+    }
+    set cmd [concat $name end \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc dodata_cancel {name} {
+    set cmd [concat $name cancel \;]
+#    puts stderr $cmd
+    pd $cmd
+}
+
+proc dodata_ok {name} {
+    dodata_send $name
+    dodata_cancel $name
+}
+
+proc pdtk_data_dialog {name stuff} {
+    global pd_deffont
+    toplevel $name
+    wm title $name {Atom}
+    wm protocol $name WM_DELETE_WINDOW [concat dodata_cancel $name]
+
+    frame $name.buttonframe
+    pack $name.buttonframe -side bottom -fill x -pady 2m
+    button $name.buttonframe.send -text {Send (Ctrl s)}\
+        -command [concat dodata_send $name]
+    button $name.buttonframe.ok -text {OK (Ctrl t)}\
+        -command [concat dodata_ok $name]
+    pack $name.buttonframe.send -side left -expand 1
+    pack $name.buttonframe.ok -side left -expand 1
+
+    text $name.text -relief raised -bd 2 -height 40 -width 60 \
+        -yscrollcommand "$name.scroll set" -font $pd_deffont
+    scrollbar $name.scroll -command "$name.text yview"
+    pack $name.scroll -side right -fill y
+    pack $name.text -side left -fill both -expand 1
+    $name.text insert end $stuff
+    focus $name.text
+    bind $name.text <Control-t> [concat dodata_ok $name]
+    bind $name.text <Control-s> [concat dodata_send $name]
+}
+
+############ check or uncheck the "edit" menu item ##############
+#####################iemlib#######################
+proc pdtk_canvas_editval {name value} {
+    if { $value } {
+        $name.m.edit entryconfigure "Edit mode" -indicatoron true
+    } else {                          
+        $name.m.edit entryconfigure "Edit mode" -indicatoron false
+    }                                                 
+}
+#####################iemlib#######################
+
+############ pdtk_text_new -- create a new text object #2###########
+proc pdtk_text_new {canvasname myname x y text font color} {
+#    if {$font < 13} {set fontname [format -*-courier-bold----%d-* $font]}
+#    if {$font >= 13} {set fontname [format -*-courier-----%d-* $font]}
+
+        global pd_fontlist 
+        switch -- $font {
+                8  { set typeface [lindex $pd_fontlist 0] }
+                9  { set typeface [lindex $pd_fontlist 1] }
+                10 { set typeface [lindex $pd_fontlist 2] }
+                12 { set typeface [lindex $pd_fontlist 3] }
+                14 { set typeface [lindex $pd_fontlist 4] }
+                16 { set typeface [lindex $pd_fontlist 5] }
+                18 { set typeface [lindex $pd_fontlist 6] }
+                24 { set typeface [lindex $pd_fontlist 7] }
+                30 { set typeface [lindex $pd_fontlist 8] }
+                36 { set typeface [lindex $pd_fontlist 9] }
+        }
+
+    $canvasname create text $x $y \
+        -font $typeface \
+        -tags $myname -text $text -fill $color  -anchor nw 
+#    pd [concat $myname size [$canvasname bbox $myname] \;]
+}
+
+################ pdtk_text_set -- change the text ##################
+proc pdtk_text_set {canvasname myname text} {
+    $canvasname itemconfig $myname -text $text
+#    pd [concat $myname size [$canvasname bbox $myname] \;]
+}
+
+############### event binding procedures for Pd window ################
+
+proc pdtk_pd_ctrlkey {name key shift} {
+#    puts stderr [concat key $key shift $shift]
+#    .dummy itemconfig goo -text [concat ---> control-key event $key];
+    if {$key == "n" || $key == "N"} {menu_new}
+    if {$key == "o" || $key == "O"} {menu_open}
+    if {$key == "m" || $key == "M"} {menu_send}
+    if {$key == "q" || $key == "Q"} {
+        if {$shift == 1} {menu_really_quit} else    {menu_quit}
+    }
+    if {$key == "slash"} {menu_audio 1}
+    if {$key == "period"} {menu_audio 0}
+}
+
+######### startup function.  ##############
+# Tell pd the current directory; this is used in case the command line
+# asked pd to open something.  Also, get character width and height for
+# seven "useful" font sizes.
+
+# tb: user defined typefaces
+proc pdtk_pd_startup {version apilist midiapilist fontname} {
+#    puts stderr [concat $version $apilist $fontname]
+    global pd_myversion pd_apilist pd_midiapilist
+    set pd_myversion $version
+    set pd_apilist $apilist
+    set pd_midiapilist $midiapilist
+    global pd_fontlist
+    set pd_fontlist {}
+
+    set fontlist ""
+    foreach i {8 9 10 12 14 16 18 24 30 36} {
+       set font [concat $fontname -$i bold]
+       set pd_fontlist [linsert $pd_fontlist 100000 $font] 
+       set width0 [font measure  $font x]
+       set height0 [lindex [font metrics $font] 5]
+       set fontlist [concat $fontlist $i [font measure  $font x] \
+	   [lindex [font metrics $font] 5]]
+    }
+
+    set tclpatch [info patchlevel]
+    if {$tclpatch == "8.3.0" || \
+	$tclpatch == "8.3.1" || \
+	$tclpatch == "8.3.2" || \
+	$tclpatch == "8.3.3" } {
+	set oldtclversion 1
+    } else {
+	set oldtclversion 0
+    }
+    pd [concat pd init [pdtk_enquote [pwd]] $oldtclversion $fontlist \;];
+
+    # add the audio and help menus to the Pd window.  We delayed this
+    # so that we'd know the value of "apilist".
+    menu_addstd .mbar 
+
+    global pd_nt
+    if {$pd_nt == 2} {
+        global pd_macdropped pd_macready
+        set pd_macready 1
+        foreach file $pd_macdropped {
+            pd [concat pd open [pdtk_enquote [file tail $file]] \
+                [pdtk_enquote  [file dirname $file]] \;]
+                menu_doc_open [file dirname $file] [file tail $file]
+        }
+    }
+}
+
+##################### DSP ON/OFF, METERS, DIO ERROR ###################
+proc pdtk_pd_dsp {value} {
+    global ctrls_audio_on
+    if {$value == "ON"} {set ctrls_audio_on 1} else {set ctrls_audio_on 0}
+#    puts stderr [concat its $ctrls_audio_on]
+}
+
+proc pdtk_pd_meters {indb outdb inclip outclip} {
+#    puts stderr [concat meters $indb $outdb $inclip $outclip]
+    global ctrls_inlevel ctrls_outlevel
+    set ctrls_inlevel $indb
+    if {$inclip == 1} {
+        .controls.inout.in.clip configure -background red
+    } else {
+        .controls.inout.in.clip configure -background grey
+    }
+    set ctrls_outlevel $outdb
+    if {$outclip == 1} {
+        .controls.inout.out.clip configure -background red
+    } else {
+        .controls.inout.out.clip configure -background grey
+    }
+    
+}
+
+proc pdtk_pd_dio {red} {
+#    puts stderr [concat dio $red]
+    if {$red == 1} {
+        .controls.dio configure -background red -activebackground red
+    } else {
+        .controls.dio configure -background grey -activebackground lightgrey
+    }
+        
+}
+
+############# text editing from the "edit" menu ###################
+set edit_number 1
+
+proc texteditor_send {name} {
+    set topname [string trimright $name .text]
+    for {set i 0} \
+        {[$name compare [concat 0.0 + [expr $i + 1] chars] < end]} \
+            {incr i 1} {
+        set cha [$name get [concat 0.0 + $i chars]]
+        scan $cha %c keynum
+        pd [concat pd key 1 $keynum 0 \;]
+    }
+}
+
+proc texteditor_ok {name} {
+    set topname [string trimright $name .text]
+    texteditor_send $name
+    destroy $topname
+}
+
+
+proc pdtk_pd_texteditor {stuff} {
+    global edit_number pd_deffont
+    set name [format ".text%d" $edit_number]
+    set edit_number [expr $edit_number + 1]
+
+    toplevel $name
+    wm title $name {TEXT}
+
+    frame $name.buttons
+    pack $name.buttons -side bottom -fill x -pady 2m
+    button $name.buttons.send -text {Send (Ctrl s)}\
+        -command "texteditor_send $name.text"
+    button $name.buttons.ok -text {OK (Ctrl t)}\
+        -command "texteditor_ok $name.text"
+    pack $name.buttons.send -side left -expand 1
+    pack $name.buttons.ok -side left -expand 1
+
+    text $name.text -relief raised -bd 2 -height 12 -width 60 \
+        -yscrollcommand "$name.scroll set" -font $pd_deffont
+    scrollbar $name.scroll -command "$name.text yview"
+    pack $name.scroll -side right -fill y
+    pack $name.text -side left -fill both -expand 1
+    $name.text insert end $stuff
+    focus $name.text
+    bind $name.text <Control-t> {texteditor_ok %W}
+    bind $name.text <Control-s> {texteditor_send %W}
+}
+
+#  paste text into a text box
+proc pdtk_pastetext {} {
+    global pdtk_pastebuffer
+    set pdtk_pastebuffer ""
+    catch {global pdtk_pastebuffer; set pdtk_pastebuffer [selection get]}
+#    puts stderr [concat paste $pdtk_pastebuffer]
+    for {set i 0} {$i < [string length $pdtk_pastebuffer]} {incr i 1} {
+        set cha [string index $pdtk_pastebuffer $i]
+        scan $cha %c keynum
+        pd [concat pd key 1 $keynum 0 \;]
+    }
+}
+
+############# open and save dialogs for objects in Pd ##########
+
+proc pdtk_openpanel {target localdir} {
+    global pd_opendir
+    if {$localdir == ""} {
+      set localdir $pd_opendir
+    }
+    set filename [tk_getOpenFile -initialdir $localdir]
+    if {$filename != ""} {
+        set directory [string range $filename 0 \
+            [expr [string last / $filename ] - 1]]
+        set pd_opendir $directory
+
+        pd [concat $target callback [pdtk_enquote $filename] \;]
+    }
+}
+
+proc pdtk_savepanel {target localdir} {
+    global pd_savedir
+    if {$localdir == ""} {
+      set localdir $pd_savedir
+    }
+    set filename [tk_getSaveFile -initialdir $localdir]
+    if {$filename != ""} {
+        pd [concat $target callback [pdtk_enquote $filename] \;]
+    }
+}
+
+########################### comport hack ########################
+
+set com1 0
+set com2 0
+set com3 0
+set com4 0
+
+proc com1_open {} {
+    global com1
+    set com1 [open com1 w]
+    .dummy itemconfig goo -text $com1
+    fconfigure $com1 -buffering none
+    fconfigure $com1 -mode 19200,e,8,2
+}
+
+proc com1_send {str} {
+    global com1
+    puts -nonewline $com1 $str
+}
+
+
+############# start a polling process to watch the socket ##############
+# this is needed for nt, and presumably for Mac as well.
+# in UNIX this is handled by a tcl callback (set up in t_tkcmd.c)
+
+if {$pd_nt == 1} {
+    proc polleofloop {} {
+        pd_pollsocket
+        after 20 polleofloop
+    }
+
+    polleofloop
+}
+
+####################### audio dialog ##################3
+
+proc audio_apply {id} {
+    global audio_indev1 audio_indev2 audio_indev3 audio_indev4 
+    global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
+    global audio_inenable1 audio_inenable2 audio_inenable3 audio_inenable4
+    global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4 
+    global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
+    global audio_outenable1 audio_outenable2 audio_outenable3 audio_outenable4
+    global audio_sr audio_advance audio_callback
+
+    pd [concat pd audio-dialog \
+        $audio_indev1 \
+        $audio_indev2 \
+        $audio_indev3 \
+        $audio_indev4 \
+        [expr $audio_inchan1 * ( $audio_inenable1 ? 1 : -1 ) ]\
+        [expr $audio_inchan2 * ( $audio_inenable2 ? 1 : -1 ) ]\
+        [expr $audio_inchan3 * ( $audio_inenable3 ? 1 : -1 ) ]\
+        [expr $audio_inchan4 * ( $audio_inenable4 ? 1 : -1 ) ]\
+        $audio_outdev1 \
+        $audio_outdev2 \
+        $audio_outdev3 \
+        $audio_outdev4 \
+        [expr $audio_outchan1 * ( $audio_outenable1 ? 1 : -1 ) ]\
+        [expr $audio_outchan2 * ( $audio_outenable2 ? 1 : -1 ) ]\
+        [expr $audio_outchan3 * ( $audio_outenable3 ? 1 : -1 ) ]\
+        [expr $audio_outchan4 * ( $audio_outenable4 ? 1 : -1 ) ]\
+        $audio_sr \
+        $audio_advance \
+        $audio_callback \
+        \;]
+}
+
+proc audio_cancel {id} {
+    pd [concat $id cancel \;]
+}
+
+proc audio_ok {id} {
+    audio_apply $id
+    audio_cancel $id
+}
+
+# callback from popup menu
+proc audio_popup_action {buttonname varname devlist index} {
+    global audio_indevlist audio_outdevlist $varname
+    $buttonname configure -text [lindex $devlist $index]
+#    puts stderr [concat popup_action $buttonname $varname $index]
+    set $varname $index
+}
+
+# create a popup menu
+proc audio_popup {name buttonname varname devlist} {
+    if [winfo exists $name.popup] {destroy $name.popup}
+    menu $name.popup -tearoff false
+#    puts stderr [concat $devlist ]
+    for {set x 0} {$x<[llength $devlist]} {incr x} {
+        $name.popup add command -label [lindex $devlist $x] \
+            -command [list audio_popup_action \
+                $buttonname $varname $devlist $x] 
+    }
+    tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
+}
+
+# start a dialog window to select audio devices and settings.  "multi"
+# is 0 if only one device is allowed; 1 if one apiece may be specified for
+# input and output; and 2 if we can select multiple devices.  "longform"
+# (which only makes sense if "multi" is 2) asks us to make controls for
+# opening several devices; if not, we get an extra button to turn longform
+# on and restart the dialog.
+
+proc pdtk_audio_dialog {id indev1 indev2 indev3 indev4 \
+        inchan1 inchan2 inchan3 inchan4 \
+        outdev1 outdev2 outdev3 outdev4 \
+        outchan1 outchan2 outchan3 outchan4 sr advance multi callback \
+        longform} {
+    global audio_indev1 audio_indev2 audio_indev3 audio_indev4 
+    global audio_inchan1 audio_inchan2 audio_inchan3 audio_inchan4
+    global audio_inenable1 audio_inenable2 audio_inenable3 audio_inenable4
+    global audio_outdev1 audio_outdev2 audio_outdev3 audio_outdev4
+    global audio_outchan1 audio_outchan2 audio_outchan3 audio_outchan4
+    global audio_outenable1 audio_outenable2 audio_outenable3 audio_outenable4
+    global audio_sr audio_advance audio_callback
+    global audio_indevlist audio_outdevlist
+    global pd_indev pd_outdev
+
+    set audio_indev1 $indev1
+    set audio_indev2 $indev2
+    set audio_indev3 $indev3
+    set audio_indev4 $indev4
+
+    set audio_inchan1 [expr ( $inchan1 > 0 ? $inchan1 : -$inchan1 ) ]
+    set audio_inenable1 [expr $inchan1 > 0 ]
+    set audio_inchan2 [expr ( $inchan2 > 0 ? $inchan2 : -$inchan2 ) ]
+    set audio_inenable2 [expr $inchan2 > 0 ]
+    set audio_inchan3 [expr ( $inchan3 > 0 ? $inchan3 : -$inchan3 ) ]
+    set audio_inenable3 [expr $inchan3 > 0 ]
+    set audio_inchan4 [expr ( $inchan4 > 0 ? $inchan4 : -$inchan4 ) ]
+    set audio_inenable4 [expr $inchan4 > 0 ]
+
+    set audio_outdev1 $outdev1
+    set audio_outdev2 $outdev2
+    set audio_outdev3 $outdev3
+    set audio_outdev4 $outdev4
+
+    set audio_outchan1 [expr ( $outchan1 > 0 ? $outchan1 : -$outchan1 ) ]
+    set audio_outenable1 [expr $outchan1 > 0 ]
+    set audio_outchan2 [expr ( $outchan2 > 0 ? $outchan2 : -$outchan2 ) ]
+    set audio_outenable2 [expr $outchan2 > 0 ]
+    set audio_outchan3 [expr ( $outchan3 > 0 ? $outchan3 : -$outchan3 ) ]
+    set audio_outenable3 [expr $outchan3 > 0 ]
+    set audio_outchan4 [expr ( $outchan4 > 0 ? $outchan4 : -$outchan4 ) ]
+    set audio_outenable4 [expr $outchan4 > 0 ]
+
+    set audio_sr $sr
+    set audio_advance $advance
+    set audio_callback $callback
+    toplevel $id
+    wm title $id {audio}
+    wm protocol $id WM_DELETE_WINDOW [concat audio_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "audio_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "audio_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "audio_ok $id"
+    button $id.buttonframe.save -text {Save all settings}\
+        -command "audio_apply $id \; pd pd save-preferences \\;"
+    pack $id.buttonframe.cancel $id.buttonframe.apply $id.buttonframe.ok \
+        $id.buttonframe.save -side left -expand 1
+    
+        # sample rate and advance
+    frame $id.srf
+    pack $id.srf -side top
+    
+    label $id.srf.l1 -text "sample rate:"
+    entry $id.srf.x1 -textvariable audio_sr -width 7
+    label $id.srf.l2 -text "delay (msec):"
+    entry $id.srf.x2 -textvariable audio_advance -width 4
+    pack $id.srf.l1 $id.srf.x1 $id.srf.l2 $id.srf.x2 -side left
+    if {$audio_callback >= 0} {
+        checkbutton $id.srf.x3 -variable audio_callback \
+            -text {use callbacks} -anchor e
+        pack $id.srf.x3 -side left
+    }
+        # input device 1
+    frame $id.in1f
+    pack $id.in1f -side top
+
+    checkbutton $id.in1f.x0 -variable audio_inenable1 \
+        -text {input device 1} -anchor e
+    button $id.in1f.x1 -text [lindex $audio_indevlist $audio_indev1] \
+        -command [list audio_popup $id $id.in1f.x1 audio_indev1 $audio_indevlist]
+    label $id.in1f.l2 -text "channels:"
+    entry $id.in1f.x2 -textvariable audio_inchan1 -width 3
+    pack $id.in1f.x0 $id.in1f.x1 $id.in1f.l2 $id.in1f.x2 -side left
+
+        # input device 2
+    if {$longform && $multi > 1 && [llength $audio_indevlist] > 1} {
+        frame $id.in2f
+        pack $id.in2f -side top
+
+        checkbutton $id.in2f.x0 -variable audio_inenable2 \
+            -text {input device 2} -anchor e
+        button $id.in2f.x1 -text [lindex $audio_indevlist $audio_indev2] \
+            -command [list audio_popup $id $id.in2f.x1 audio_indev2 \
+                $audio_indevlist]
+        label $id.in2f.l2 -text "channels:"
+        entry $id.in2f.x2 -textvariable audio_inchan2 -width 3
+        pack $id.in2f.x0 $id.in2f.x1 $id.in2f.l2 $id.in2f.x2 -side left
+    }
+
+        # input device 3
+    if {$longform && $multi > 1 && [llength $audio_indevlist] > 2} {
+        frame $id.in3f
+        pack $id.in3f -side top
+
+        checkbutton $id.in3f.x0 -variable audio_inenable3 \
+            -text {input device 3} -anchor e
+        button $id.in3f.x1 -text [lindex $audio_indevlist $audio_indev3] \
+            -command [list audio_popup $id $id.in3f.x1 audio_indev3 \
+                $audio_indevlist]
+        label $id.in3f.l2 -text "channels:"
+        entry $id.in3f.x2 -textvariable audio_inchan3 -width 3
+        pack $id.in3f.x0 $id.in3f.x1 $id.in3f.l2 $id.in3f.x2 -side left
+    }
+
+        # input device 4
+    if {$longform && $multi > 1 && [llength $audio_indevlist] > 3} {
+        frame $id.in4f
+        pack $id.in4f -side top
+
+        checkbutton $id.in4f.x0 -variable audio_inenable4 \
+            -text {input device 4} -anchor e
+        button $id.in4f.x1 -text [lindex $audio_indevlist $audio_indev4] \
+            -command [list audio_popup $id $id.in4f.x1 audio_indev4 \
+                $audio_indevlist]
+        label $id.in4f.l2 -text "channels:"
+        entry $id.in4f.x2 -textvariable audio_inchan4 -width 3
+        pack $id.in4f.x0 $id.in4f.x1 $id.in4f.l2 $id.in4f.x2 -side left
+    }
+
+        # output device 1
+    frame $id.out1f
+    pack $id.out1f -side top
+
+    checkbutton $id.out1f.x0 -variable audio_outenable1 \
+        -text {output device 1} -anchor e
+    if {$multi == 0} {
+        label $id.out1f.l1 \
+            -text "(same as input device) ..............      "
+    } else {
+        button $id.out1f.x1 -text [lindex $audio_outdevlist $audio_outdev1] \
+            -command  [list audio_popup $id $id.out1f.x1 audio_outdev1 \
+                $audio_outdevlist]
+    }
+    label $id.out1f.l2 -text "channels:"
+    entry $id.out1f.x2 -textvariable audio_outchan1 -width 3
+    if {$multi == 0} {
+        pack $id.out1f.x0 $id.out1f.l1 $id.out1f.x2 -side left
+    } else {
+        pack $id.out1f.x0 $id.out1f.x1 $id.out1f.l2 $id.out1f.x2 -side left
+    }
+
+        # output device 2
+    if {$longform && $multi > 1 && [llength $audio_outdevlist] > 1} {
+        frame $id.out2f
+        pack $id.out2f -side top
+
+        checkbutton $id.out2f.x0 -variable audio_outenable2 \
+            -text {output device 2} -anchor e
+        button $id.out2f.x1 -text [lindex $audio_outdevlist $audio_outdev2] \
+            -command \
+            [list audio_popup $id $id.out2f.x1 audio_outdev2 $audio_outdevlist]
+        label $id.out2f.l2 -text "channels:"
+        entry $id.out2f.x2 -textvariable audio_outchan2 -width 3
+        pack $id.out2f.x0 $id.out2f.x1 $id.out2f.l2 $id.out2f.x2 -side left
+    }
+
+        # output device 3
+    if {$longform && $multi > 1 && [llength $audio_outdevlist] > 2} {
+        frame $id.out3f
+        pack $id.out3f -side top
+
+        checkbutton $id.out3f.x0 -variable audio_outenable3 \
+            -text {output device 3} -anchor e
+        button $id.out3f.x1 -text [lindex $audio_outdevlist $audio_outdev3] \
+            -command \
+            [list audio_popup $id $id.out3f.x1 audio_outdev3 $audio_outdevlist]
+        label $id.out3f.l2 -text "channels:"
+        entry $id.out3f.x2 -textvariable audio_outchan3 -width 3
+        pack $id.out3f.x0 $id.out3f.x1 $id.out3f.l2 $id.out3f.x2 -side left
+    }
+
+        # output device 4
+    if {$longform && $multi > 1 && [llength $audio_outdevlist] > 3} {
+        frame $id.out4f
+        pack $id.out4f -side top
+
+        checkbutton $id.out4f.x0 -variable audio_outenable4 \
+            -text {output device 4} -anchor e
+        button $id.out4f.x1 -text [lindex $audio_outdevlist $audio_outdev4] \
+            -command \
+            [list audio_popup $id $id.out4f.x1 audio_outdev4 $audio_outdevlist]
+        label $id.out4f.l2 -text "channels:"
+        entry $id.out4f.x2 -textvariable audio_outchan4 -width 3
+        pack $id.out4f.x0 $id.out4f.x1 $id.out4f.l2 $id.out4f.x2 -side left
+    }
+
+        # if not the "long form" but if "multi" is 2, make a button to
+        # restart with longform set. 
+    
+    if {$longform == 0 && $multi > 1} {
+        frame $id.longbutton
+        pack $id.longbutton -side top
+        button $id.longbutton.b -text {use multiple devices} \
+            -command  {pd pd audio-properties 1 \;}
+        pack $id.longbutton.b
+    }
+    bind $id.srf.x1 <KeyPress-Return> [concat audio_ok $id]
+    bind $id.srf.x2 <KeyPress-Return> [concat audio_ok $id]
+    bind $id.in1f.x2 <KeyPress-Return> [concat audio_ok $id]
+    bind $id.out1f.x2 <KeyPress-Return> [concat audio_ok $id]
+    $id.srf.x1 select from 0
+    $id.srf.x1 select adjust end
+    focus $id.srf.x1
+    pdtk_standardkeybindings $id.srf.x1
+    pdtk_standardkeybindings $id.srf.x2
+    pdtk_standardkeybindings $id.in1f.x2
+    pdtk_standardkeybindings $id.out1f.x2
+}
+
+####################### midi dialog ##################
+
+proc midi_apply {id} {
+    global midi_indev1 midi_indev2 midi_indev3 midi_indev4 
+    global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
+    global midi_alsain midi_alsaout
+
+    pd [concat pd midi-dialog \
+        $midi_indev1 \
+        $midi_indev2 \
+        $midi_indev3 \
+        $midi_indev4 \
+        $midi_outdev1 \
+        $midi_outdev2 \
+        $midi_outdev3 \
+        $midi_outdev4 \
+        $midi_alsain \
+        $midi_alsaout \
+        \;]
+}
+
+proc midi_cancel {id} {
+    pd [concat $id cancel \;]
+}
+
+proc midi_ok {id} {
+    midi_apply $id
+    midi_cancel $id
+}
+
+# callback from popup menu
+proc midi_popup_action {buttonname varname devlist index} {
+    global midi_indevlist midi_outdevlist $varname
+    $buttonname configure -text [lindex $devlist $index]
+#    puts stderr [concat popup_action $buttonname $varname $index]
+    set $varname $index
+}
+
+# create a popup menu
+proc midi_popup {name buttonname varname devlist} {
+    if [winfo exists $name.popup] {destroy $name.popup}
+    menu $name.popup -tearoff false
+#    puts stderr [concat $devlist ]
+    for {set x 0} {$x<[llength $devlist]} {incr x} {
+        $name.popup add command -label [lindex $devlist $x] \
+            -command [list midi_popup_action \
+                $buttonname $varname $devlist $x] 
+    }
+    tk_popup $name.popup [winfo pointerx $name] [winfo pointery $name] 0
+}
+
+# start a dialog window to select midi devices.  "longform" asks us to make
+# controls for opening several devices; if not, we get an extra button to
+# turn longform on and restart the dialog.
+proc pdtk_midi_dialog {id indev1 indev2 indev3 indev4 \
+        outdev1 outdev2 outdev3 outdev4 longform} {
+    global midi_indev1 midi_indev2 midi_indev3 midi_indev4 
+    global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
+    global midi_indevlist midi_outdevlist
+    global midi_alsain midi_alsaout
+
+    set midi_indev1 $indev1
+    set midi_indev2 $indev2
+    set midi_indev3 $indev3
+    set midi_indev4 $indev4
+    set midi_outdev1 $outdev1
+    set midi_outdev2 $outdev2
+    set midi_outdev3 $outdev3
+    set midi_outdev4 $outdev4
+    set midi_alsain [llength $midi_indevlist]
+    set midi_alsaout [llength $midi_outdevlist]
+
+    toplevel $id
+    wm title $id {midi}
+    wm protocol $id WM_DELETE_WINDOW [concat midi_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "midi_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "midi_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "midi_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+    
+        # input device 1
+    frame $id.in1f
+    pack $id.in1f -side top
+
+    label $id.in1f.l1 -text "input device 1:"
+    button $id.in1f.x1 -text [lindex $midi_indevlist $midi_indev1] \
+        -command [list midi_popup $id $id.in1f.x1 midi_indev1 $midi_indevlist]
+    pack $id.in1f.l1 $id.in1f.x1 -side left
+
+        # input device 2
+    if {$longform && [llength $midi_indevlist] > 2} {
+        frame $id.in2f
+        pack $id.in2f -side top
+
+        label $id.in2f.l1 -text "input device 2:"
+        button $id.in2f.x1 -text [lindex $midi_indevlist $midi_indev2] \
+            -command [list midi_popup $id $id.in2f.x1 midi_indev2 \
+                $midi_indevlist]
+        pack $id.in2f.l1 $id.in2f.x1 -side left
+    }
+
+        # input device 3
+    if {$longform && [llength $midi_indevlist] > 3} {
+        frame $id.in3f
+        pack $id.in3f -side top
+
+        label $id.in3f.l1 -text "input device 3:"
+        button $id.in3f.x1 -text [lindex $midi_indevlist $midi_indev3] \
+            -command [list midi_popup $id $id.in3f.x1 midi_indev3 \
+                $midi_indevlist]
+        pack $id.in3f.l1 $id.in3f.x1 -side left
+    }
+
+        # input device 4
+    if {$longform && [llength $midi_indevlist] > 4} {
+        frame $id.in4f
+        pack $id.in4f -side top
+
+        label $id.in4f.l1 -text "input device 4:"
+        button $id.in4f.x1 -text [lindex $midi_indevlist $midi_indev4] \
+            -command [list midi_popup $id $id.in4f.x1 midi_indev4 \
+                $midi_indevlist]
+        pack $id.in4f.l1 $id.in4f.x1 -side left
+    }
+
+        # output device 1
+
+    frame $id.out1f
+    pack $id.out1f -side top
+    label $id.out1f.l1 -text "output device 1:"
+    button $id.out1f.x1 -text [lindex $midi_outdevlist $midi_outdev1] \
+        -command [list midi_popup $id $id.out1f.x1 midi_outdev1 \
+            $midi_outdevlist]
+    pack $id.out1f.l1 $id.out1f.x1 -side left
+
+        # output device 2
+    if {$longform && [llength $midi_outdevlist] > 2} {
+        frame $id.out2f
+        pack $id.out2f -side top
+        label $id.out2f.l1 -text "output device 2:"
+        button $id.out2f.x1 -text [lindex $midi_outdevlist $midi_outdev2] \
+            -command \
+            [list midi_popup $id $id.out2f.x1 midi_outdev2 $midi_outdevlist]
+        pack $id.out2f.l1 $id.out2f.x1 -side left
+    }
+
+        # output device 3
+    if {$longform && [llength $midi_midi_outdevlist] > 3} {
+        frame $id.out3f
+        pack $id.out3f -side top
+        label $id.out3f.l1 -text "output device 3:"
+        button $id.out3f.x1 -text [lindex $midi_outdevlist $midi_outdev3] \
+            -command \
+            [list midi_popup $id $id.out3f.x1 midi_outdev3 $midi_outdevlist]
+        pack $id.out3f.l1 $id.out3f.x1 -side left
+    }
+
+        # output device 4
+    if {$longform && [llength $midi_midi_outdevlist] > 4} {
+        frame $id.out4f
+        pack $id.out4f -side top
+        label $id.out4f.l1 -text "output device 4:"
+        button $id.out4f.x1 -text [lindex $midi_outdevlist $midi_outdev4] \
+            -command \
+            [list midi_popup $id $id.out4f.x1 midi_outdev4 $midi_outdevlist]
+        pack $id.out4f.l1 $id.out4f.x1 -side left
+    }
+
+        # if not the "long form" make a button to
+        # restart with longform set. 
+    
+    if {$longform == 0} {
+        frame $id.longbutton
+        pack $id.longbutton -side top
+        button $id.longbutton.b -text {use multiple devices} \
+            -command  {pd pd midi-properties 1 \;}
+        pack $id.longbutton.b
+    }
+}
+
+proc pdtk_alsa_midi_dialog {id indev1 indev2 indev3 indev4 \
+        outdev1 outdev2 outdev3 outdev4 longform alsa} {
+    global midi_indev1 midi_indev2 midi_indev3 midi_indev4 
+    global midi_outdev1 midi_outdev2 midi_outdev3 midi_outdev4
+    global midi_indevlist midi_outdevlist
+    global midi_alsain midi_alsaout
+
+    set midi_indev1 $indev1
+    set midi_indev2 $indev2
+    set midi_indev3 $indev3
+    set midi_indev4 $indev4
+    set midi_outdev1 $outdev1
+    set midi_outdev2 $outdev2
+    set midi_outdev3 $outdev3
+    set midi_outdev4 $outdev4
+    set midi_alsain [llength $midi_indevlist]
+    set midi_alsaout [llength $midi_outdevlist]
+    
+    toplevel $id
+    wm title $id {midi}
+    wm protocol $id WM_DELETE_WINDOW [concat midi_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "midi_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "midi_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "midi_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+
+    frame $id.in1f
+    pack $id.in1f -side top
+
+  if {$alsa == 0} {
+        # input device 1
+    label $id.in1f.l1 -text "input device 1:"
+    button $id.in1f.x1 -text [lindex $midi_indevlist $midi_indev1] \
+        -command [list midi_popup $id $id.in1f.x1 midi_indev1 $midi_indevlist]
+    pack $id.in1f.l1 $id.in1f.x1 -side left
+
+        # input device 2
+    if {$longform && [llength $midi_indevlist] > 2} {
+        frame $id.in2f
+        pack $id.in2f -side top
+
+        label $id.in2f.l1 -text "input device 2:"
+        button $id.in2f.x1 -text [lindex $midi_indevlist $midi_indev2] \
+            -command [list midi_popup $id $id.in2f.x1 midi_indev2 \
+                $midi_indevlist]
+        pack $id.in2f.l1 $id.in2f.x1 -side left
+    }
+
+        # input device 3
+    if {$longform && [llength $midi_indevlist] > 3} {
+        frame $id.in3f
+        pack $id.in3f -side top
+
+        label $id.in3f.l1 -text "input device 3:"
+        button $id.in3f.x1 -text [lindex $midi_indevlist $midi_indev3] \
+            -command [list midi_popup $id $id.in3f.x1 midi_indev3 \
+                $midi_indevlist]
+        pack $id.in3f.l1 $id.in3f.x1 -side left
+    }
+
+        # input device 4
+    if {$longform && [llength $midi_indevlist] > 4} {
+        frame $id.in4f
+        pack $id.in4f -side top
+
+        label $id.in4f.l1 -text "input device 4:"
+        button $id.in4f.x1 -text [lindex $midi_indevlist $midi_indev4] \
+            -command [list midi_popup $id $id.in4f.x1 midi_indev4 \
+                $midi_indevlist]
+        pack $id.in4f.l1 $id.in4f.x1 -side left
+    }
+
+        # output device 1
+
+    frame $id.out1f
+    pack $id.out1f -side top
+    label $id.out1f.l1 -text "output device 1:"
+    button $id.out1f.x1 -text [lindex $midi_outdevlist $midi_outdev1] \
+        -command [list midi_popup $id $id.out1f.x1 midi_outdev1 \
+            $midi_outdevlist]
+    pack $id.out1f.l1 $id.out1f.x1 -side left
+
+        # output device 2
+    if {$longform && [llength $midi_outdevlist] > 2} {
+        frame $id.out2f
+        pack $id.out2f -side top
+        label $id.out2f.l1 -text "output device 2:"
+        button $id.out2f.x1 -text [lindex $midi_outdevlist $midi_outdev2] \
+            -command \
+            [list midi_popup $id $id.out2f.x1 midi_outdev2 $midi_outdevlist]
+        pack $id.out2f.l1 $id.out2f.x1 -side left
+    }
+
+        # output device 3
+    if {$longform && [llength $midi_outdevlist] > 3} {
+        frame $id.out3f
+        pack $id.out3f -side top
+        label $id.out3f.l1 -text "output device 3:"
+        button $id.out3f.x1 -text [lindex $midi_outdevlist $midi_outdev3] \
+            -command \
+            [list midi_popup $id $id.out3f.x1 midi_outdev3 $midi_outdevlist]
+        pack $id.out3f.l1 $id.out3f.x1 -side left
+    }
+
+        # output device 4
+    if {$longform && [llength $midi_outdevlist] > 4} {
+        frame $id.out4f
+        pack $id.out4f -side top
+        label $id.out4f.l1 -text "output device 4:"
+        button $id.out4f.x1 -text [lindex $midi_outdevlist $midi_outdev4] \
+            -command \
+            [list midi_popup $id $id.out4f.x1 midi_outdev4 $midi_outdevlist]
+        pack $id.out4f.l1 $id.out4f.x1 -side left
+    }
+
+        # if not the "long form" make a button to
+        # restart with longform set. 
+    
+    if {$longform == 0} {
+        frame $id.longbutton
+        pack $id.longbutton -side top
+        button $id.longbutton.b -text {use multiple alsa devices} \
+            -command  {pd pd midi-properties 1 \;}
+        pack $id.longbutton.b
+    }
+    }
+    if {$alsa} {
+        label $id.in1f.l1 -text "In Ports:"
+        entry $id.in1f.x1 -textvariable midi_alsain -width 4
+        pack $id.in1f.l1 $id.in1f.x1 -side left
+        label $id.in1f.l2 -text "Out Ports:"
+        entry $id.in1f.x2 -textvariable midi_alsaout -width 4
+        pack $id.in1f.l2 $id.in1f.x2 -side left
+    }
+}
+
+############ pdtk_path_dialog -- dialog window for search path #########
+
+proc path_apply {id} {
+    global pd_extrapath pd_verbose
+    global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4 
+    global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9 
+
+    pd [concat pd path-dialog $pd_extrapath $pd_verbose \
+    [pdtk_encodedialog $pd_path0] [pdtk_encodedialog $pd_path1] \
+    [pdtk_encodedialog $pd_path2] [pdtk_encodedialog $pd_path3] \
+    [pdtk_encodedialog $pd_path4] [pdtk_encodedialog $pd_path5] \
+    [pdtk_encodedialog $pd_path6] [pdtk_encodedialog $pd_path7] \
+    [pdtk_encodedialog $pd_path8] [pdtk_encodedialog $pd_path9] \;]
+}
+
+proc path_cancel {id} {
+    pd [concat $id cancel \;]
+}
+
+proc path_ok {id} {
+    path_apply $id
+    path_cancel $id
+}
+
+proc pdtk_path_dialog {id extrapath verbose} {
+    global pd_extrapath pd_verbose
+    global pd_path0 pd_path1 pd_path2 pd_path3 pd_path4 
+    global pd_path5 pd_path6 pd_path7 pd_path8 pd_path9 
+
+    set pd_extrapath $extrapath
+    set pd_verbose $verbose
+    toplevel $id
+    wm title $id {PD search path for patches and other files}
+    wm protocol $id WM_DELETE_WINDOW [concat path_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "path_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "path_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "path_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+    
+    frame $id.extraframe
+    pack $id.extraframe -side bottom -fill x -pady 2m
+    checkbutton $id.extraframe.extra -text {use standard extensions} \
+        -variable pd_extrapath -anchor w 
+    checkbutton $id.extraframe.verbose -text {verbose} \
+        -variable pd_verbose -anchor w 
+    button $id.extraframe.save -text {Save all settings}\
+        -command "path_apply $id \; pd pd save-preferences \\;"
+    pack $id.extraframe.extra $id.extraframe.verbose $id.extraframe.save \
+        -side left -expand 1
+    
+    for {set x 0} {$x < 10} {incr x} {
+        entry $id.f$x -textvariable pd_path$x -width 80
+        bind $id.f$x <KeyPress-Return> [concat path_ok $id]
+        pdtk_standardkeybindings $id.f$x
+        pack $id.f$x -side top
+    }
+
+    focus $id.f0
+}
+
+proc pd_set {var value} {
+        global $var
+        set $var $value
+}
+
+########## pdtk_startup_dialog -- dialog window for startup options #########
+
+proc startup_apply {id} {
+    global pd_nort pd_flags
+    global pd_startup0 pd_startup1 pd_startup2 pd_startup3 pd_startup4 
+    global pd_startup5 pd_startup6 pd_startup7 pd_startup8 pd_startup9 
+
+    pd [concat pd startup-dialog $pd_nort [pdtk_encodedialog $pd_flags] \
+    [pdtk_encodedialog $pd_startup0] [pdtk_encodedialog $pd_startup1] \
+    [pdtk_encodedialog $pd_startup2] [pdtk_encodedialog $pd_startup3] \
+    [pdtk_encodedialog $pd_startup4] [pdtk_encodedialog $pd_startup5] \
+    [pdtk_encodedialog $pd_startup6] [pdtk_encodedialog $pd_startup7] \
+    [pdtk_encodedialog $pd_startup8] [pdtk_encodedialog $pd_startup9] \;]
+
+}
+
+proc startup_cancel {id} {
+    pd [concat $id cancel \;]
+}
+
+proc startup_ok {id} {
+    startup_apply $id
+    startup_cancel $id
+}
+
+proc pdtk_startup_dialog {id nort flags} {
+    global pd_nort pd_nt pd_flags
+    global pd_startup0 pd_startup1 pd_startup2 pd_startup3 pd_startup4 
+    global pd_startup5 pd_startup6 pd_startup7 pd_startup8 pd_startup9 
+
+    set pd_nort $nort
+    set pd_flags $flags
+    toplevel $id
+    wm title $id {Pd binaries to load (on next startup)}
+    wm protocol $id WM_DELETE_WINDOW [concat startup_cancel $id]
+
+    frame $id.buttonframe
+    pack $id.buttonframe -side bottom -fill x -pady 2m
+    button $id.buttonframe.cancel -text {Cancel}\
+        -command "startup_cancel $id"
+    button $id.buttonframe.apply -text {Apply}\
+        -command "startup_apply $id"
+    button $id.buttonframe.ok -text {OK}\
+        -command "startup_ok $id"
+    pack $id.buttonframe.cancel -side left -expand 1
+    pack $id.buttonframe.apply -side left -expand 1
+    pack $id.buttonframe.ok -side left -expand 1
+    
+    frame $id.flags
+    pack $id.flags -side bottom
+    label $id.flags.entryname -text {startup flags}
+    entry $id.flags.entry -textvariable pd_flags -width 80
+    bind $id.flags.entry <KeyPress-Return> [concat startup_ok $id]
+    pdtk_standardkeybindings $id.flags.entry
+    pack $id.flags.entryname $id.flags.entry -side left
+
+    frame $id.nortframe
+    pack $id.nortframe -side bottom -fill x -pady 2m
+    if {$pd_nt != 1} {
+        checkbutton $id.nortframe.nort -text {defeat real-time scheduling} \
+            -variable pd_nort -anchor w
+    }
+    button $id.nortframe.save -text {Save all settings}\
+        -command "startup_apply $id \; pd pd save-preferences \\;"
+    if {$pd_nt != 1} {
+        pack $id.nortframe.nort $id.nortframe.save -side left -expand 1
+    } else {
+        pack $id.nortframe.save -side left -expand 1
+    }
+
+    for {set x 0} {$x < 10} {incr x} {
+        entry $id.f$x -textvariable pd_startup$x -width 80
+        bind $id.f$x <KeyPress-Return> [concat startup_ok $id]
+        pdtk_standardkeybindings $id.f$x
+        pack $id.f$x -side top
+    }
+
+    focus $id.f0
+}
+
diff --git a/src/x_qlist.c b/src/x_qlist.c
index 271259a30..c0be1d52f 100644
--- a/src/x_qlist.c
+++ b/src/x_qlist.c
@@ -100,7 +100,8 @@ static void qlist_donext(t_qlist *x, int drop, int automatic)
             if (ap->a_type != A_SYMBOL) continue;
             else if (!(target = ap->a_w.w_symbol->s_thing))
             {
-                error("qlist: %s: no such object", ap->a_w.w_symbol->s_name);
+                pd_error(x, "qlist: %s: no such object",
+                    ap->a_w.w_symbol->s_name);
                 continue;
             }
             ap++;
@@ -180,10 +181,10 @@ static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format)
     if (!strcmp(format->s_name, "cr"))
         cr = 1;
     else if (*format->s_name)
-        error("qlist_read: unknown flag: %s", format->s_name);
+        pd_error(x, "qlist_read: unknown flag: %s", format->s_name);
 
     if (binbuf_read_via_canvas(x->x_binbuf, filename->s_name, x->x_canvas, cr))
-            error("%s: read failed", filename->s_name);
+            pd_error(x, "%s: read failed", filename->s_name);
     x->x_onset = 0x7fffffff;
     x->x_reentered = 1;
 }
@@ -197,9 +198,9 @@ static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format)
     if (!strcmp(format->s_name, "cr"))
         cr = 1;
     else if (*format->s_name)
-        error("qlist_read: unknown flag: %s", format->s_name);
+        pd_error(x, "qlist_read: unknown flag: %s", format->s_name);
     if (binbuf_write(x->x_binbuf, buf, "", cr))
-            error("%s: write failed", filename->s_name);
+            pd_error(x, "%s: write failed", filename->s_name);
 }
 
 static void qlist_print(t_qlist *x)
-- 
GitLab