diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx
index faf696e44c4c47f0f22590ab3ceb4767290bff30..9f20843f780581724e1fb24f3236372e97b9da25 100644
--- a/fluid/fluid.cxx
+++ b/fluid/fluid.cxx
@@ -1948,10 +1948,9 @@ void load_history() {
   for (i = 0; i < max_files; i ++) {
     fluid_prefs.get( Fl_Preferences::Name("file%d", i), absolute_history[i], "", sizeof(absolute_history[i]));
     if (absolute_history[i][0]) {
-      // Make a relative version of the filename for the menu...
-      fl_filename_relative(relative_history[i], sizeof(relative_history[i]),
-                           absolute_history[i]);
-
+      // Make a shortened version of the filename for the menu...
+      Fl_String fn = fl_filename_shortened(absolute_history[i], 48);
+      strncpy(relative_history[i], fn.c_str(), sizeof(relative_history[i]));
       if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
       else history_item[i].flags = 0;
     } else break;
@@ -2002,9 +2001,8 @@ void update_history(const char *flname) {
 
   // Put the new file at the top...
   strlcpy(absolute_history[0], absolute, sizeof(absolute_history[0]));
-
-  fl_filename_relative(relative_history[0], sizeof(relative_history[0]),
-                       absolute_history[0]);
+  Fl_String fn = fl_filename_shortened(absolute_history[0], 48);
+  strncpy(relative_history[0], fn.c_str(), sizeof(relative_history[0]));
 
   // Update the menu items as needed...
   for (i = 0; i < max_files; i ++) {
diff --git a/fluid/fluid_filename.cxx b/fluid/fluid_filename.cxx
index dc323c2aa10df5b708a7b926626fd0d9b1fe9c47..99e1e068b220c9740ff7d6f299e3f9104885a98d 100644
--- a/fluid/fluid_filename.cxx
+++ b/fluid/fluid_filename.cxx
@@ -162,3 +162,60 @@ Fl_String fl_getcwd() {
   fl_getcwd(buffer, FL_PATH_MAX);
   return Fl_String(buffer);
 }
+
+/**
+ Return a shortened filename for limited display width.
+
+ Replace the start uf a path with "~" if it matches the home directory.
+ If the remaining filename has more than the give number of characters, it will
+ be shortened by replacing parts of the path with an ellipsis ("...").
+
+ The shortened name can no longer be used to open a file. This is purely to
+ make as much information visible while fitting into a give space.
+
+ \param[in] filename absolute path and name, UTF-8 aware
+ \param[in[ max_chars maximum number of characters in result, including ellipsis
+ \return shortened file path and name
+ */
+Fl_String fl_filename_shortened(const Fl_String &filename, int max_chars) {
+  // Insert this as the ellipsis
+  static const char *ell = "...";
+  static const int ell_bytes = 3;
+  // Replace the start of a path with "~" if it matches the home directory
+  static Fl_String tilde = "~/";
+  static Fl_String home;
+  static int home_chars = -1;
+  if (home_chars==-1) {
+    home = fl_filename_expand(tilde);
+    home_chars = fl_utf_nb_char((const uchar*)home.c_str(), home.size());
+  }
+  Fl_String homed_filename;
+#if defined(_WIN32) || defined(__APPLE__)
+  bool starts_with_home = fl_utf_strncasecmp(home.c_str(), filename.c_str(), home_chars)==0;
+#else
+  bool starts_with_home = ::strncmp(home.c_str(), filename.c_str(), home.size())==0;
+#endif
+  if (starts_with_home) {
+    homed_filename = tilde + filename.substr(home.size());
+  } else {
+    homed_filename = filename;
+  }
+  // C style pointer will stay valid until filename is modified.
+  const unsigned char *u8str = reinterpret_cast<const unsigned char *>(homed_filename.c_str());
+  // Count the number of UTF-8 characters in the name.
+  int num_chars = fl_utf_nb_char(u8str, homed_filename.size());
+  if (num_chars+ell_bytes-1 > max_chars) {
+    // Create a new string by replacing characters in the middle.
+    int remove_chars = num_chars - max_chars + ell_bytes;
+    int left_chars = (max_chars - ell_bytes)/2;
+    int right_chars = max_chars - left_chars - 3;
+    int right_start_char = num_chars - right_chars;
+    // Convert character counts into byte counts.
+    int left_bytes = fl_utf8strlen(homed_filename.c_str(), left_chars);
+    int right_start_byte = fl_utf8strlen(homed_filename.c_str()+left_bytes, remove_chars) + left_bytes;
+    return homed_filename.substr(0, left_bytes) + "..." + homed_filename.substr(right_start_byte);
+  } else {
+    // Nothing to change.
+    return homed_filename;
+  }
+}
diff --git a/fluid/fluid_filename.h b/fluid/fluid_filename.h
index afd2aed7eed726dad31d3ccc02e60f443a772e55..8a97f132ca42ba856fbebea1cde21455788a92d2 100644
--- a/fluid/fluid_filename.h
+++ b/fluid/fluid_filename.h
@@ -41,6 +41,7 @@
 
 class Fl_String;
 
+Fl_String fl_filename_shortened(const Fl_String &filename, int maxchars);
 Fl_String fl_filename_name(const Fl_String &filename);
 Fl_String fl_filename_path(const Fl_String &filename);
 Fl_String fl_filename_ext(const Fl_String &filename);