diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 64e80ab85453a7bca051f3509c3a068ff54e36fd..ed52ab0a6d4f56bea3e3fd466530d613219a63d1 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -287,6 +287,7 @@ function make_index() {
             finish_index();
         }
     }
+    pdsend("pd gui-busy 1");
     index_started = true;
     index_start_time = new Date().getTime() / 1000;
     var idx, manif;
@@ -329,6 +330,7 @@ function make_index() {
 	post("building help index in " + doc_path);
 	dive(doc_path, read_file, browser_path?make_index_cont:finish_index);
     }
+    pdsend("pd gui-busy 0");
 }
 
 // AG: This is called from dialog_search.html with a callback that expects to
@@ -1160,52 +1162,17 @@ function menu_saveas(name) {
 exports.menu_saveas = menu_saveas;
 
 function gui_canvas_print(name, initfile, initdir) {
-    // AG: This works mostly like gui_canvas_saveas above, except that we
-    // create a pdf file and use a different input element and callback.
-    var input, chooser,
-        span = patchwin[name].window.document.querySelector("#printDialogSpan");
-    if (!fs.existsSync(initdir)) {
-        initdir = pwd;
-    }
-    // If we don't have a ".pd" file extension (e.g., "Untitled-1", add one)
-    if (initfile.slice(-3) !== ".pd") {
-        initfile += ".pd";
-    }
-    // Adding an "f" now gives .pdf which is what we want.
-    initfile += "f";
-    input = build_file_dialog_string({
-        style: "display: none;",
-        type: "file",
-        id: "printDialog",
-        nwsaveas: path.join(initdir, initfile),
-        nwworkingdir: initdir,
-        accept: ".pdf"
-    });
-    span.innerHTML = input;
-    chooser = patchwin[name].window.document.querySelector("#printDialog");
-    chooser.onchange = function() {
-        print_callback(name, this.value);
-        // reset value so that we can open the same file twice
-        this.value = null;
-        console.log("tried to print something");
-    }
-    chooser.click();
+    // AG: The print dialog presents its own file picker anyway if PDF
+    // output is chosen, and just ignores the settings for pdf_path. So
+    // initfile and initdir are only used here to provide a useful default
+    // for the header and footer information -- otherwise the print() method
+    // uses some random internal document URL which isn't helpful.
+    pdsend("pd gui-busy 1");
+    patchwin[name].print({ autoprint: false, headerString: initfile, footerString: path.join(initdir, initfile) });
+    pdsend("pd gui-busy 0");
+    post("printed "+initfile);
 }
 
-function print_callback(cid, file) {
-    var filename = defunkify_windows_path(file);
-    // It probably isn't possible to arrive at the callback with an
-    // empty string.  But I've only tested on Debian so far...
-    if (filename === null) {
-        return;
-    }
-    // Let nw.js do the rest (requires nw.js 0.14.6+)
-    patchwin[cid].print({ pdf_path: filename, headerFooterEnabled: false });
-    post("printed to: " + filename);
-}
-
-exports.print_callback = print_callback;
-
 function menu_print(name) {
     pdsend(name + " menuprint");
 }
@@ -1398,7 +1365,9 @@ function gui_quit_dialog() {
 function menu_send(name) {
     var message,
         win = name ? patchwin[name] : pd_window;
+    pdsend("pd gui-busy 1");
     message = win.window.prompt("Type a message to send to Pd", name);
+    pdsend("pd gui-busy 0");
     if (message != undefined && message.length) {
         post("Sending message to Pd: " + message + ";");
         pdsend(message);
diff --git a/pd/src/m_glob.c b/pd/src/m_glob.c
index 2147047271868a021bb4f899b9aefdeecf56f6a2..6fca411ca59a08070c0c2b2fd9ee2a0da4f41eb7 100644
--- a/pd/src/m_glob.c
+++ b/pd/src/m_glob.c
@@ -107,6 +107,12 @@ static void glob_gui_properties(t_pd *dummy)
         sys_autopatch_yoffset);
 }
 
+int sys_gui_busy;
+static void glob_gui_busy(void *dummy, t_float f)
+{
+  sys_gui_busy = f != 0;
+}
+
 // ths one lives inside g_editor so that it can access the clipboard
 extern void glob_clipboard_text(t_pd *dummy, float f);
 
@@ -201,6 +207,8 @@ void glob_init(void)
         gensym("add-recent-file"), A_SYMBOL, 0);
     class_addmethod(glob_pdobject, (t_method)glob_clear_recent_files,
         gensym("clear-recent-files"), 0);
+    class_addmethod(glob_pdobject, (t_method)glob_gui_busy, gensym("gui-busy"),
+        A_DEFFLOAT, 0);
 #ifdef UNIX
     class_addmethod(glob_pdobject, (t_method)glob_watchdog,
         gensym("watchdog"), 0);
diff --git a/pd/src/m_sched.c b/pd/src/m_sched.c
index e51d64038efa9ce0fe460236ef44c80f1c45559c..50654791f6a49104d0e3b893110dba558d2f345c 100644
--- a/pd/src/m_sched.c
+++ b/pd/src/m_sched.c
@@ -312,11 +312,12 @@ static void sched_pollformeters( void)
 {
     int inclip, outclip, indb, outdb;
     static int sched_nextmeterpolltime, sched_nextpingtime;
+    extern int sys_gui_busy;
 
         /* if there's no GUI but we're running in "realtime", here is
         where we arrange to ping the watchdog every 2 seconds. */
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
-    if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
+    if ((sys_nogui||sys_gui_busy) && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
     {
         glob_watchdog(0);
             /* ping every 2 seconds */
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index f1e6cabbdf17e4419da05e942343a6026ea559f7..a712dba3a1d75e6927d7423e3dfbcdea4c5f9220 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -195,6 +195,7 @@ double sys_getrealtime(void)
 }
 
 extern int sys_nosleep;
+static int fdschanged;
 
 static int sys_domicrosleep(int microsec, int pollem)
 {
@@ -203,7 +204,7 @@ static int sys_domicrosleep(int microsec, int pollem)
     t_fdpoll *fp;
     timout.tv_sec = 0;
     timout.tv_usec = (sys_nosleep ? 0 : microsec);
-    if (pollem)
+    if (pollem && sys_nfdpoll)
     {
         fd_set readset, writeset, exceptset;
         FD_ZERO(&writeset);
@@ -216,8 +217,10 @@ static int sys_domicrosleep(int microsec, int pollem)
                 Sleep(microsec/1000);
         else
 #endif
-        select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
-        for (i = 0; i < sys_nfdpoll; i++)
+        if (select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout) < 0)
+          perror("microsleep select");
+        fdschanged = 0;
+        for (i = 0; i < sys_nfdpoll && !fdschanged; i++)
             if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
         {
 #ifdef THREAD_LOCKING
@@ -229,18 +232,23 @@ static int sys_domicrosleep(int microsec, int pollem)
 #endif
             didsomething = 1;
         }
-        return (didsomething);
+        if (didsomething) return (1);
     }
-    else
+    if (microsec)
     {
+#ifdef THREAD_LOCKING
+        sys_unlock();
+#endif
 #ifdef MSW
-        if (sys_maxfd == 0)
-              Sleep(microsec/1000);
-        else
+        Sleep(microsec/1000);
+#else
+        usleep(microsec);
+#endif
+#ifdef THREAD_LOCKING
+        sys_lock();
 #endif
-        select(0, 0, 0, 0, &timout);
-        return (0);
     }
+    return (0);
 }
 
 void sys_microsleep(int microsec)
@@ -438,6 +446,7 @@ void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
     fp->fdp_ptr = ptr;
     sys_nfdpoll = nfd + 1;
     if (fd >= sys_maxfd) sys_maxfd = fd + 1;
+    fdschanged = 1;
 }
 
 void sys_rmpollfn(int fd)
@@ -445,6 +454,7 @@ void sys_rmpollfn(int fd)
     int nfd = sys_nfdpoll;
     int i, size = nfd * sizeof(t_fdpoll);
     t_fdpoll *fp;
+    fdschanged = 1;
     for (i = nfd, fp = sys_fdpoll; i--; fp++)
     {
         if (fp->fdp_fd == fd)
@@ -624,6 +634,7 @@ void socketreceiver_read(t_socketreceiver *x, int fd)
 void sys_closesocket(int fd)
 {
 #ifdef HAVE_UNISTD_H
+    if (fd<0) return;
     close(fd);
 #endif
 #ifdef MSW