diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json
index e7a8510191e040baa874336b085caaf65711450b..6a0e72bae8428c1382893e88af7c75b79a5f123d 100644
--- a/pd/nw/locales/en/translation.json
+++ b/pd/nw/locales/en/translation.json
@@ -284,6 +284,10 @@
       "cancel": "Cancel",
       "cancel_tt": "Don't save any changes, and don't close the patch"
     },
+    "warning": {
+      "unsaved_tt": "There is an unsaved edited instance of this abstraction",
+      "multipleunsaved_tt": "There is another unsaved edited instance of this abstraction"
+    },
     "find": {
       "placeholder": "Search in Canvas",
       "search": "Search",
diff --git a/pd/nw/pd_canvas.html b/pd/nw/pd_canvas.html
index 7a104941a3695be2a1e7bfb781ee0a6b2f606767..110b1e4fa071ba7715d503c24efae970d2d88562 100644
--- a/pd/nw/pd_canvas.html
+++ b/pd/nw/pd_canvas.html
@@ -78,8 +78,8 @@
         </button>
       </div>
     </dialog>
-  <div id="dirtywarning" style="position: fixed; right: 2%; top: 2%; display: none;">
-      <strong style="color: rgb(255, 0, 0); font-size: medium; -webkit-user-select: none;">[MULTIPLE DIRTY INSTANCES]</strong>
+  <div style="position: fixed; right: 2%; top: 2%; ">
+      <strong id="canvas_warning" style="display: none; text-align: right; -webkit-user-select: none;">!</strong>
   </div>
 	<div id="hscroll" style="background-color: rgba(0, 0, 0, 0.267); position: fixed; left: 2px; bottom: 2px; border-radius: 0px; width: 10px; height: 5px; visibility: hidden;"></div>
 	<div id="vscroll" style="background-color: rgba(0, 0, 0, 0.267); position: fixed; right: 2px; top: 2px; border-radius: 0px; width: 5px; height: 10px; visibility: hidden;"></div>
diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js
index f15b358327598dd07338fa92b4af3c9b5036f3ea..0bbcf24e9f6fa8a71771c37dcb657283c6edf11f 100644
--- a/pd/nw/pd_canvas.js
+++ b/pd/nw/pd_canvas.js
@@ -1330,7 +1330,7 @@ function register_window_id(cid, attr_array) {
     // (which is the visual cue for "dirty")
 
     // Enable/disable the warning for multiple dirty instances
-    pdgui.gui_canvas_multipledirty(cid, attr_array.multipledirty);
+    pdgui.gui_canvas_warning(cid, attr_array.warid);
 
     // Two possibilities for handling this better:
     // have a representation of canvas attys in pdgui.js (editmode, dirty, etc.)
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 5aa5975c7d8e295908a4ae04c18a01e457f0ec97..9706f2072663858cb8c348b1a81279b9e48e1644 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -1607,7 +1607,7 @@ function create_window(cid, type, width, height, xpos, ypos, attr_array) {
 }
 
 // create a new canvas
-function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, dirty_flag, multipledirty, hide_scroll, hide_menu, has_toplevel_scalars, cargs) {
+function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, dirty_flag, warid, hide_scroll, hide_menu, has_toplevel_scalars, cargs) {
     // hack for buggy tcl popups... should go away for node-webkit
     //reset_ctrl_on_popup_window
     
@@ -1661,7 +1661,7 @@ function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir,
             name: name,
             dir: dir,
             dirty: dirty_flag,
-            multipledirty: multipledirty,
+            warid: warid,
             args: cargs,
             zoom: zoom,
             editmode: editmode,
@@ -2670,13 +2670,32 @@ function gui_gobj_dirty(cid, tag, state) {
     });
 }
 
-function gui_canvas_multipledirty(cid, state) {
-    var warning = get_item(cid, "dirtywarning");
-    if (state !== 0) warning.style.setProperty("display", "inline");
-    else warning.style.setProperty("display", "none");
+function gui_canvas_warning(cid, warid) {
+    var warning = get_item(cid, "canvas_warning");
+    switch(warid)
+    {
+        case 0:
+            warning.style.setProperty("display", "none");
+            break;
+        case 1:
+            warning.title = lang.get_local_string("canvas.warning.unsaved_tt");
+            warning.style.setProperty("color", "coral");
+            warning.style.setProperty("font-size", "x-large");
+            warning.style.setProperty("display", "inline");
+            break;
+        case 2:
+            warning.title = lang.get_local_string("canvas.warning.multipleunsaved_tt");
+            warning.style.setProperty("color", "red");
+            warning.style.setProperty("font-size", "xx-large");
+            warning.style.setProperty("display", "inline");
+            break;
+
+        default:
+            break;
+    }
 }
 
-exports.gui_canvas_multipledirty = gui_canvas_multipledirty;
+exports.gui_canvas_warning = gui_canvas_warning;
 
 function gui_canvas_emphasize(cid) {
     gui(cid).get_elem("patchsvg", function(e) {
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index b1e23fc8109365d03a6abe1b5d3a06da1612c407..c5ed8349a760a9b61e12bbe0981c09f7520ae0da 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -830,7 +830,9 @@ static void canvas_dirty_deliver_packed(t_canvas *x, t_dirty_broadcast_data *dat
     *data->res += (x->gl_dirty > 0);
     x->gl_dirties += data->mess;
     if(x->gl_havewindow)
-        canvas_multipledirty(x, (x->gl_dirties > 1));
+        canvas_warning(x, (x->gl_dirties > 1 ?
+                            (x->gl_dirty ? 2 : 1)
+                            : (x->gl_dirties ? !x->gl_dirty : 0)));
 }
 
 static int canvas_dirty_broadcast_packed(t_canvas *x, t_dirty_broadcast_data *data);
@@ -851,7 +853,9 @@ static int canvas_dirty_broadcast(t_canvas *x, t_symbol *name, t_symbol *dir, in
                 res += (z->gl_dirty > 0);
                 z->gl_dirties += mess;
                 if(z->gl_havewindow)
-                    canvas_multipledirty(z, (z->gl_dirties > 1));
+                    canvas_warning(z, (z->gl_dirties > 1 ?
+                            (z->gl_dirty ? 2 : 1)
+                            : (z->gl_dirties ? !z->gl_dirty : 0)));
             }
             else
                 res += canvas_dirty_broadcast((t_canvas *)g, name, dir, mess);
@@ -903,7 +907,9 @@ static void canvas_dirty_deliver_ab_packed(t_canvas *x, t_dirty_broadcast_ab_dat
     *data->res += (x->gl_dirty > 0);
     x->gl_dirties += data->mess;
     if(x->gl_havewindow)
-        canvas_multipledirty(x, (x->gl_dirties > 1));
+        canvas_warning(x, (x->gl_dirties > 1 ?
+                            (x->gl_dirty ? 2 : 1)
+                            : (x->gl_dirties ? !x->gl_dirty : 0)));
 }
 
 static int canvas_dirty_broadcast_ab_packed(t_canvas *x, t_dirty_broadcast_ab_data *data);
@@ -923,7 +929,9 @@ static int canvas_dirty_broadcast_ab(t_canvas *x, t_ab_definition *abdef, int me
                 res += (z->gl_dirty > 0);
                 z->gl_dirties += mess;
                 if(z->gl_havewindow)
-                    canvas_multipledirty(z, (z->gl_dirties > 1));
+                    canvas_warning(z, (z->gl_dirties > 1 ?
+                            (z->gl_dirty ? 2 : 1)
+                            : (z->gl_dirties ? !z->gl_dirty : 0)));
             }
             else
                 res += canvas_dirty_broadcast_ab((t_canvas *)g, abdef, mess);
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
index 2be170b3d4969c39eec49d399d41489f4354d985..e28506cb4173a5796b512b95e5a721f858ed763c 100644
--- a/pd/src/g_canvas.h
+++ b/pd/src/g_canvas.h
@@ -602,7 +602,7 @@ EXTERN t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos,
     int *x1p, int *y1p, int *x2p, int *y2p);
 EXTERN int canvas_setdeleting(t_canvas *x, int flag);
 EXTERN int canvas_hasarray(t_canvas *x);
-EXTERN void canvas_multipledirty(t_canvas *x, int on);
+EXTERN void canvas_warning(t_canvas *x, int warid);
 
 #define LB_LOAD 0       /* "loadbang" actions - 0 for original meaning */
 #define LB_INIT 1       /* loaded but not yet connected to parent patch */
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index 53cadb650b9f208d719c74c67c674bd34d05fe71..d120fa44d303ffb0cf11d816c519b243058ca6a1 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -2620,7 +2620,9 @@ void canvas_vis(t_canvas *x, t_floatarg f)
                 x->gl_name->s_name,
                 canvas_getdir(x)->s_name,
                 x->gl_dirty,
-                (x->gl_dirty && x->gl_dirties > 1),
+                (x->gl_dirties > 1 ?
+                    (x->gl_dirty ? 2 : 1)
+                    : (x->gl_dirties ? !x->gl_dirty : 0)),
                 x->gl_noscroll,
                 x->gl_nomenu,
                 canvas_hasarray(x),
@@ -5976,11 +5978,11 @@ void gobj_dirty(t_gobj *x, t_glist *g, int state)
     gui_vmess("gui_gobj_dirty", "xsi", g, rtext_gettag(y), state);
 }
 
-    /* tell the gui to display a warning about the existence of
-        multiple dirty instances of the same abstraction */
-void canvas_multipledirty(t_canvas *x, int on)
+    /* tell the gui to display a specific message in the
+        top right corner */
+void canvas_warning(t_canvas *x, int warid)
 {
-    gui_vmess("gui_canvas_multipledirty", "xi", x, (on > 0));
+    gui_vmess("gui_canvas_warning", "xi", x, warid);
 }
 
 static int glist_dofinderror(t_glist *gl, void *error_object)