FLTK logo

[master] 179771a - Fixing FLUID file corruption from issue #653 (#662)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 179771a - Fixing FLUID file corruption from issue #653 (#662) "Matthias Melcher" Jan 26, 2023  
 
commit 179771acd25ee5ff8e36a5fd192682d4d55c52af
Author:     Matthias Melcher <github@matthiasm.com>
AuthorDate: Thu Jan 26 15:23:43 2023 +0100
Commit:     GitHub <noreply@github.com>
CommitDate: Thu Jan 26 15:23:43 2023 +0100

    Fixing FLUID file corruption from issue #653 (#662)
    
    Removing all globals in file writer (#653 )
    Fix some static analyser complaints
    Valgrind: handle width==0 in GfxDrivers on Wayland and X11
    Don't use `Fl_Input_::static_value`, it accesses previous
    buffer that may be deleted
    Project file write encapsulated, removing globals
    Encapsulating project file reader, removing states in glbals
    Project i/o increased source code readability

 fluid/Fl_Function_Type.cxx                         | 386 ++++-----
 fluid/Fl_Function_Type.h                           |  62 +-
 fluid/Fl_Group_Type.cxx                            | 102 +--
 fluid/Fl_Group_Type.h                              |  10 +-
 fluid/Fl_Menu_Type.cxx                             | 195 +++--
 fluid/Fl_Menu_Type.h                               |  12 +-
 fluid/Fl_Type.cxx                                  | 171 ++--
 fluid/Fl_Type.h                                    |  25 +-
 fluid/Fl_Widget_Type.cxx                           | 550 ++++++------
 fluid/Fl_Widget_Type.h                             |  18 +-
 fluid/Fl_Window_Type.cxx                           | 184 ++--
 fluid/Fl_Window_Type.h                             |  16 +-
 fluid/Fluid_Image.cxx                              | 265 +++---
 fluid/Fluid_Image.h                                |  18 +-
 fluid/about_panel.cxx                              |   1 +
 fluid/code.cxx                                     | 460 +++++-----
 fluid/code.h                                       |  69 +-
 fluid/file.cxx                                     | 940 +++++++++++----------
 fluid/file.h                                       |  61 +-
 fluid/fluid.cxx                                    |  19 +-
 fluid/function_panel.cxx                           |   2 +-
 fluid/function_panel.fl                            |   6 +-
 fluid/function_panel.h                             |   2 +-
 fluid/print_panel.cxx                              |   9 +-
 fluid/print_panel.fl                               |  16 +-
 fluid/template_panel.cxx                           |   4 +-
 fluid/widget_browser.cxx                           |   2 +-
 fluid/widget_panel.fl                              |   4 +-
 src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx     |   1 +
 .../Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx      |   1 +
 test/boxtype.cxx                                   |   5 +-
 test/valuators.fl                                  |   4 +-
 32 files changed, 1911 insertions(+), 1709 deletions(-)

diff --git fluid/Fl_Function_Type.cxx fluid/Fl_Function_Type.cxx
index 9affddb..c19077b 100644
--- fluid/Fl_Function_Type.cxx
+++ fluid/Fl_Function_Type.cxx
@@ -209,16 +209,16 @@ Fl_Type *Fl_Function_Type::make(Strategy strategy) {
   - "C" is written if we want a C signature instead of C++
   - "return_type" is followed by the return type of the function
  */
-void Fl_Function_Type::write_properties() {
-  Fl_Type::write_properties();
+void Fl_Function_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
   switch (public_) {
-    case 0: write_string("private"); break;
-    case 2: write_string("protected"); break;
+    case 0: f.write_string("private"); break;
+    case 2: f.write_string("protected"); break;
   }
-  if (cdecl_) write_string("C");
+  if (cdecl_) f.write_string("C");
   if (return_type) {
-    write_string("return_type");
-    write_word(return_type);
+    f.write_string("return_type");
+    f.write_word(return_type);
   }
 }
 
@@ -226,7 +226,7 @@ void Fl_Function_Type::write_properties() {
  Read function specific properties fron an .fl file.
  \param[in] c read from this string
  */
-void Fl_Function_Type::read_property(const char *c) {
+void Fl_Function_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"private")) {
     public_ = 0;
   } else if (!strcmp(c,"protected")) {
@@ -234,9 +234,9 @@ void Fl_Function_Type::read_property(const char *c) {
   } else if (!strcmp(c,"C")) {
     cdecl_ = 1;
   } else if (!strcmp(c,"return_type")) {
-    storestring(read_word(),return_type);
+    storestring(f.read_word(),return_type);
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -245,8 +245,8 @@ void Fl_Function_Type::read_property(const char *c) {
  */
 void Fl_Function_Type::open() {
   if (!function_panel) make_function_panel();
-  f_return_type_input->static_value(return_type);
-  f_name_input->static_value(name());
+  f_return_type_input->value(return_type);
+  f_name_input->value(name());
   if (is_in_class()) {
     f_public_member_choice->value(public_);
     f_public_member_choice->show();
@@ -328,9 +328,9 @@ int Fl_Function_Type::is_public() const {
 /**
  Write the code for the source and the header file.
  This writes the code that goes \b before all children of this class.
- \see write_code2()
+ \see write_code2(Fd_Code_Writer& f)
  */
-void Fl_Function_Type::write_code1() {
+void Fl_Function_Type::write_code1(Fd_Code_Writer& f) {
   constructor=0;
   havewidgets = 0;
   Fl_Type *child;
@@ -346,10 +346,10 @@ void Fl_Function_Type::write_code1() {
     }
   }
   if (havechildren)
-    write_c("\n");
+    f.write_c("\n");
   if (ismain()) {
     if (havechildren)
-      write_c("int main(int argc, char **argv) {\n");
+      f.write_c("int main(int argc, char **argv) {\n");
   } else {
     const char* rtype = return_type;
     const char* star = "";
@@ -375,24 +375,24 @@ void Fl_Function_Type::write_code1() {
     const char* k = class_name(0);
     if (k) {
       if (havechildren)
-        write_comment_c();
-      write_public(public_);
+        write_comment_c(f);
+      f.write_public(public_);
       if (name()[0] == '~')
         constructor = 1;
       else {
         size_t n = strlen(k);
         if (!strncmp(name(), k, n) && name()[n] == '(') constructor = 1;
       }
-      write_h("%s", indent(1));
-      if (is_static) write_h("static ");
-      if (is_virtual) write_h("virtual ");
+      f.write_h("%s", f.indent(1));
+      if (is_static) f.write_h("static ");
+      if (is_virtual) f.write_h("virtual ");
       if (!constructor) {
-        write_h("%s%s ", rtype, star);
+        f.write_h("%s%s ", rtype, star);
         if (havechildren)
-          write_c("%s%s ", rtype, star);
+          f.write_c("%s%s ", rtype, star);
       }
 
-      // if this is a subclass, only write_h() the part before the ':'
+      // if this is a subclass, only f.write_h() the part before the ':'
       char s[1024], *sptr = s;
       char *nptr = (char *)name();
 
@@ -407,9 +407,9 @@ void Fl_Function_Type::write_code1() {
       *sptr = '\0';
 
       if (s[strlen(s)-1] == '}') {  // special case for inlined functions
-        write_h("%s\n", s);
+        f.write_h("%s\n", s);
       } else {
-        write_h("%s;\n", s);
+        f.write_h("%s;\n", s);
       }
       // skip all function default param. init in body:
       int skips=0,skipc=0;
@@ -437,20 +437,20 @@ void Fl_Function_Type::write_code1() {
       *sptr = '\0';
 
       if (havechildren)
-        write_c("%s::%s {\n", k, s);
+        f.write_c("%s::%s {\n", k, s);
     } else {
       if (havechildren)
-        write_comment_c();
+        write_comment_c(f);
       if (public_==1) {
         if (cdecl_)
-          write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
+          f.write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
         else
-          write_h("%s%s %s;\n", rtype, star, name());
+          f.write_h("%s%s %s;\n", rtype, star, name());
       } else if (public_==2) {
         // write neither the prototype nor static, the function may be declared elsewhere
       } else {
         if (havechildren)
-          write_c("static ");
+          f.write_c("static ");
       }
 
       // write everything but the default parameters (if any)
@@ -481,21 +481,21 @@ void Fl_Function_Type::write_code1() {
       *sptr = '\0';
 
       if (havechildren)
-        write_c("%s%s %s {\n", rtype, star, s);
+        f.write_c("%s%s %s {\n", rtype, star, s);
     }
   }
 
   if (havewidgets && child && !child->name())
-    write_c("%s%s* w;\n", indent(1), subclassname(child));
-  indentation++;
+    f.write_c("%s%s* w;\n", f.indent(1), subclassname(child));
+  f.indentation++;
 }
 
 /**
  Write the code for the source and the header file.
  This writes the code that goes \b after all children of this class.
- \see write_code1()
+ \see write_code1(Fd_Code_Writer& f)
  */
-void Fl_Function_Type::write_code2() {
+void Fl_Function_Type::write_code2(Fd_Code_Writer& f) {
   Fl_Type *child;
   const char *var = "w";
   char havechildren = 0;
@@ -506,15 +506,15 @@ void Fl_Function_Type::write_code2() {
 
   if (ismain()) {
     if (havewidgets)
-      write_c("%s%s->show(argc, argv);\n", indent(1), var);
+      f.write_c("%s%s->show(argc, argv);\n", f.indent(1), var);
     if (havechildren)
-      write_c("%sreturn Fl::run();\n", indent(1));
+      f.write_c("%sreturn Fl::run();\n", f.indent(1));
   } else if (havewidgets && !constructor && !return_type) {
-    write_c("%sreturn %s;\n", indent(1), var);
+    f.write_c("%sreturn %s;\n", f.indent(1), var);
   }
   if (havechildren)
-    write_c("}\n");
-  indentation = 0;
+    f.write_c("}\n");
+  f.indentation = 0;
 }
 
 /**
@@ -619,24 +619,24 @@ BREAK2:
 /**
  Grab changes from an external editor and write this node.
  */
-void Fl_Code_Type::write() {
+void Fl_Code_Type::write(Fd_Project_Writer &f) {
   // External editor changes? If so, load changes into ram, update mtime/size
   if ( handle_editor_changes() == 1 ) {
     main_window->redraw();    // tell fluid to redraw; edits may affect tree's contents
   }
-  Fl_Type::write();
+  Fl_Type::write(f);
 }
 
 /**
  Write the code block with the correct indentation.
  */
-void Fl_Code_Type::write_code1() {
+void Fl_Code_Type::write_code1(Fd_Code_Writer& f) {
   // External editor changes? If so, load changes into ram, update mtime/size
   if ( handle_editor_changes() == 1 ) {
     main_window->redraw();    // tell fluid to redraw; edits may affect tree's contents
   }
 
-  write_c_indented(name(), 0, '\n');
+  f.write_c_indented(name(), 0, '\n');
 }
 
 /**
@@ -737,22 +737,22 @@ Fl_Type *Fl_CodeBlock_Type::make(Strategy strategy) {
   - "after" is followed by the code that comes after the children
  The "before" code is stored in the name() field.
  */
-void Fl_CodeBlock_Type::write_properties() {
-  Fl_Type::write_properties();
+void Fl_CodeBlock_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
   if (after) {
-    write_string("after");
-    write_word(after);
+    f.write_string("after");
+    f.write_word(after);
   }
 }
 
 /**
  Read the node specifc properties.
  */
-void Fl_CodeBlock_Type::read_property(const char *c) {
+void Fl_CodeBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"after")) {
-    storestring(read_word(),after);
+    storestring(f.read_word(),after);
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -761,8 +761,8 @@ void Fl_CodeBlock_Type::read_property(const char *c) {
  */
 void Fl_CodeBlock_Type::open() {
   if (!codeblock_panel) make_codeblock_panel();
-  code_before_input->static_value(name());
-  code_after_input->static_value(after);
+  code_before_input->value(name());
+  code_after_input->value(after);
   codeblock_panel->show();
   const char* message = 0;
   for (;;) { // repeat as long as there are errors
@@ -788,19 +788,19 @@ BREAK2:
 /**
  Write the "before" code.
  */
-void Fl_CodeBlock_Type::write_code1() {
+void Fl_CodeBlock_Type::write_code1(Fd_Code_Writer& f) {
   const char* c = name();
-  write_c("%s%s {\n", indent(), c ? c : "");
-  indentation++;
+  f.write_c("%s%s {\n", f.indent(), c ? c : "");
+  f.indentation++;
 }
 
 /**
  Write the "after" code.
  */
-void Fl_CodeBlock_Type::write_code2() {
-  indentation--;
-  if (after) write_c("%s} %s\n", indent(), after);
-  else write_c("%s}\n", indent());
+void Fl_CodeBlock_Type::write_code2(Fd_Code_Writer& f) {
+  f.indentation--;
+  if (after) f.write_c("%s} %s\n", f.indent(), after);
+  else f.write_c("%s}\n", f.indent());
 }
 
 // ---- Fl_Decl_Type declaration
@@ -861,23 +861,23 @@ Fl_Type *Fl_Decl_Type::make(Strategy strategy) {
   - "private"/"public"/"protected"
   - "local"/"global" if this is static or not
  */
-void Fl_Decl_Type::write_properties() {
-  Fl_Type::write_properties();
+void Fl_Decl_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
   switch (public_) {
-    case 0: write_string("private"); break;
-    case 1: write_string("public"); break;
-    case 2: write_string("protected"); break;
+    case 0: f.write_string("private"); break;
+    case 1: f.write_string("public"); break;
+    case 2: f.write_string("protected"); break;
   }
   if (static_)
-    write_string("local");
+    f.write_string("local");
   else
-    write_string("global");
+    f.write_string("global");
 }
 
 /**
  Read the specific properties.
  */
-void Fl_Decl_Type::read_property(const char *c) {
+void Fl_Decl_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"public")) {
     public_ = 1;
   } else if (!strcmp(c,"private")) {
@@ -889,7 +889,7 @@ void Fl_Decl_Type::read_property(const char *c) {
   } else if (!strcmp(c,"global")) {
     static_ = 0;
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -898,7 +898,7 @@ void Fl_Decl_Type::read_property(const char *c) {
  */
 void Fl_Decl_Type::open() {
   if (!decl_panel) make_decl_panel();
-  decl_input->static_value(name());
+  decl_input->value(name());
   if (is_in_class()) {
     decl_class_choice->value(public_);
     decl_class_choice->show();
@@ -960,7 +960,7 @@ BREAK2:
  \todo There are a lot of side effect in this node depending on the given text
     and the parent node. They need to be understood and documented.
  */
-void Fl_Decl_Type::write_code1() {
+void Fl_Decl_Type::write_code1(Fd_Code_Writer& f) {
   const char* c = name();
   if (!c) return;
   // handle a few keywords differently if inside a class
@@ -969,9 +969,9 @@ void Fl_Decl_Type::write_code1() {
                         || (!strncmp(c,"FL_EXPORT",9) && isspace(c[9]))
                         || (!strncmp(c,"struct",6) && isspace(c[6]))
                         ) ) {
-    write_public(public_);
-    write_comment_h(indent(1));
-    write_h("%s%s\n", indent(1), c);
+    f.write_public(public_);
+    write_comment_h(f, f.indent(1));
+    f.write_h("%s%s\n", f.indent(1), c);
     return;
   }
   // handle putting #include, extern, using or typedef into decl:
@@ -984,11 +984,11 @@ void Fl_Decl_Type::write_code1() {
       //    || !strncmp(c,"struct",6) && isspace(c[6])
       ) {
     if (public_) {
-      write_comment_h();
-      write_h("%s\n", c);
+      write_comment_h(f);
+      f.write_h("%s\n", c);
     } else {
-      write_comment_c();
-      write_c("%s\n", c);
+      write_comment_c(f);
+      f.write_c("%s\n", c);
     }
     return;
   }
@@ -999,26 +999,26 @@ void Fl_Decl_Type::write_code1() {
   // lose spaces between text and comment, if any
   while (e>c && e[-1]==' ') e--;
   if (class_name(1)) {
-    write_public(public_);
-    write_comment_h(indent(1));
-    write_hc(indent(1), int(e-c), c, csc);
+    f.write_public(public_);
+    write_comment_h(f, f.indent(1));
+    f.write_hc(f.indent(1), int(e-c), c, csc);
   } else {
     if (public_) {
       if (static_)
-        write_h("extern ");
+        f.write_h("extern ");
       else
-        write_comment_h();
-      write_hc("", int(e-c), c, csc);
+        write_comment_h(f);
+      f.write_hc("", int(e-c), c, csc);
 
       if (static_) {
-        write_comment_c();
-        write_cc("", int(e-c), c, csc);
+        write_comment_c(f);
+        f.write_cc("", int(e-c), c, csc);
       }
     } else {
-      write_comment_c();
+      write_comment_c(f);
       if (static_)
-        write_c("static ");
-      write_cc("", int(e-c), c, csc);
+        f.write_c("static ");
+      f.write_cc("", int(e-c), c, csc);
     }
   }
 }
@@ -1076,27 +1076,27 @@ Fl_Type *Fl_Data_Type::make(Strategy strategy) {
   - "filename" followed by the filename of the file to inline
   - "textmode" if data is written in ASCII vs. binary
  */
-void Fl_Data_Type::write_properties() {
-  Fl_Decl_Type::write_properties();
+void Fl_Data_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Decl_Type::write_properties(f);
   if (filename_) {
-    write_string("filename");
-    write_word(filename_);
+    f.write_string("filename");
+    f.write_word(filename_);
   }
   if (text_mode_) {
-    write_string("textmode");
+    f.write_string("textmode");
   }
 }
 
 /**
  Read specific properties.
  */
-void Fl_Data_Type::read_property(const char *c) {
+void Fl_Data_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"filename")) {
-    storestring(read_word(), filename_, 1);
+    storestring(f.read_word(), filename_, 1);
   } else if (!strcmp(c,"textmode")) {
     text_mode_ = 1;
   } else {
-    Fl_Decl_Type::read_property(c);
+    Fl_Decl_Type::read_property(f, c);
   }
 }
 
@@ -1105,7 +1105,7 @@ void Fl_Data_Type::read_property(const char *c) {
  */
 void Fl_Data_Type::open() {
   if (!data_panel) make_data_panel();
-  data_input->static_value(name());
+  data_input->value(name());
   if (is_in_class()) {
     data_class_choice->value(public_);
     data_class_choice->show();
@@ -1208,7 +1208,7 @@ BREAK2:
 /**
  Write the content of the external file inline into the source code.
  */
-void Fl_Data_Type::write_code1() {
+void Fl_Data_Type::write_code1(Fd_Code_Writer& f) {
   const char *message = 0;
   const char *c = name();
   if (!c) return;
@@ -1216,7 +1216,7 @@ void Fl_Data_Type::write_code1() {
   char *data = 0;
   int nData = -1;
   // path should be set correctly already
-  if (filename_ && !write_sourceview) {
+  if (filename_ && !f.write_sourceview) {
     enter_project_dir();
     FILE *f = fl_fopen(filename_, "rb");
     leave_project_dir();
@@ -1236,71 +1236,71 @@ void Fl_Data_Type::write_code1() {
     fn = filename_ ? filename_ : "<no filename>";
   }
   if (is_in_class()) {
-    write_public(public_);
+    f.write_public(public_);
     if (text_mode_) {
-      write_h("%sstatic const char *%s;\n", indent(1), c);
-      write_c("\n");
-      write_comment_c();
-      write_c("const char *%s::%s = /* text inlined from %s */\n", class_name(1), c, fn);
-      if (message) write_c("#error %s %s\n", message, fn);
-      write_cstring(data, nData);
+      f.write_h("%sstatic const char *%s;\n", f.indent(1), c);
+      f.write_c("\n");
+      write_comment_c(f);
+      f.write_c("const char *%s::%s = /* text inlined from %s */\n", class_name(1), c, fn);
+      if (message) f.write_c("#error %s %s\n", message, fn);
+      f.write_cstring(data, nData);
     } else {
-      write_h("%sstatic unsigned char %s[%d];\n", indent(1), c, nData);
-      write_c("\n");
-      write_comment_c();
-      write_c("unsigned char %s::%s[%d] = /* data inlined from %s */\n", class_name(1), c, nData, fn);
-      if (message) write_c("#error %s %s\n", message, fn);
-      write_cdata(data, nData);
+      f.write_h("%sstatic unsigned char %s[%d];\n", f.indent(1), c, nData);
+      f.write_c("\n");
+      write_comment_c(f);
+      f.write_c("unsigned char %s::%s[%d] = /* data inlined from %s */\n", class_name(1), c, nData, fn);
+      if (message) f.write_c("#error %s %s\n", message, fn);
+      f.write_cdata(data, nData);
     }
-    write_c(";\n");
+    f.write_c(";\n");
   } else {
     // the "header only" option does not apply here!
     if (public_) {
       if (static_) {
         if (text_mode_) {
-          write_h("extern const char *%s;\n", c);
-          write_c("\n");
-          write_comment_c();
-          write_c("const char *%s = /* text inlined from %s */\n", c, fn);
-          if (message) write_c("#error %s %s\n", message, fn);
-          write_cstring(data, nData);
+          f.write_h("extern const char *%s;\n", c);
+          f.write_c("\n");
+          write_comment_c(f);
+          f.write_c("const char *%s = /* text inlined from %s */\n", c, fn);
+          if (message) f.write_c("#error %s %s\n", message, fn);
+          f.write_cstring(data, nData);
         } else {
-          write_h("extern unsigned char %s[%d];\n", c, nData);
-          write_c("\n");
-          write_comment_c();
-          write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
-          if (message) write_c("#error %s %s\n", message, fn);
-          write_cdata(data, nData);
+          f.write_h("extern unsigned char %s[%d];\n", c, nData);
+          f.write_c("\n");
+          write_comment_c(f);
+          f.write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
+          if (message) f.write_c("#error %s %s\n", message, fn);
+          f.write_cdata(data, nData);
         }
-        write_c(";\n");
+        f.write_c(";\n");
       } else {
-        write_comment_h();
-        write_h("#error Unsupported declaration loading inline data %s\n", fn);
+        write_comment_h(f);
+        f.write_h("#error Unsupported declaration loading inline data %s\n", fn);
         if (text_mode_)
-          write_h("const char *%s = \"abc...\";\n", c);
+          f.write_h("const char *%s = \"abc...\";\n", c);
         else
-          write_h("unsigned char %s[3] = { 1, 2, 3 };\n", c);
+          f.write_h("unsigned char %s[3] = { 1, 2, 3 };\n", c);
       }
     } else {
-      write_c("\n");
-      write_comment_c();
+      f.write_c("\n");
+      write_comment_c(f);
       if (static_)
-        write_c("static ");
+        f.write_c("static ");
       if (text_mode_) {
-        write_c("const char *%s = /* text inlined from %s */\n", c, fn);
-        if (message) write_c("#error %s %s\n", message, fn);
-        write_cstring(data, nData);
+        f.write_c("const char *%s = /* text inlined from %s */\n", c, fn);
+        if (message) f.write_c("#error %s %s\n", message, fn);
+        f.write_cstring(data, nData);
       } else {
-        write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
-        if (message) write_c("#error %s %s\n", message, fn);
-        write_cdata(data, nData);
+        f.write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
+        if (message) f.write_c("#error %s %s\n", message, fn);
+        f.write_cdata(data, nData);
       }
-      write_c(";\n");
+      f.write_c(";\n");
     }
   }
   // if we are in interactive mode, we pop up a warning dialog
   // giving the error: (batch_mode && !write_sourceview) ???
-  if (message && !write_sourceview) {
+  if (message && !f.write_sourceview) {
     if (batch_mode)
       fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn);
     else
@@ -1365,28 +1365,28 @@ Fl_Type *Fl_DeclBlock_Type::make(Strategy strategy) {
   - "public"/"protected"
   - "after" followed by the second code block.
  */
-void Fl_DeclBlock_Type::write_properties() {
-  Fl_Type::write_properties();
+void Fl_DeclBlock_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
   switch (public_) {
-    case 1: write_string("public"); break;
-    case 2: write_string("protected"); break;
+    case 1: f.write_string("public"); break;
+    case 2: f.write_string("protected"); break;
   }
-  write_string("after");
-  write_word(after);
+  f.write_string("after");
+  f.write_word(after);
 }
 
 /**
  Read the specific properties.
  */
-void Fl_DeclBlock_Type::read_property(const char *c) {
+void Fl_DeclBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if(!strcmp(c,"public")) {
     public_ = 1;
   } else if(!strcmp(c,"protected")) {
     public_ = 2;
   } else  if (!strcmp(c,"after")) {
-    storestring(read_word(),after);
+    storestring(f.read_word(),after);
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -1395,9 +1395,9 @@ void Fl_DeclBlock_Type::read_property(const char *c) {
  */
 void Fl_DeclBlock_Type::open() {
   if (!declblock_panel) make_declblock_panel();
-  decl_before_input->static_value(name());
+  decl_before_input->value(name());
   declblock_public_choice->value((public_>0));
-  decl_after_input->static_value(after);
+  decl_after_input->value(after);
   declblock_panel->show();
   const char* message = 0;
   for (;;) { // repeat as long as there are errors
@@ -1433,21 +1433,21 @@ BREAK2:
  Write the \b before code to the source file, and to the header file if declared public.
  The before code is stored in the name() field.
  */
-void Fl_DeclBlock_Type::write_code1() {
+void Fl_DeclBlock_Type::write_code1(Fd_Code_Writer& f) {
   const char* c = name();
   if (public_)
-    write_h("%s\n", c);
-  write_c("%s\n", c);
+    f.write_h("%s\n", c);
+  f.write_c("%s\n", c);
 }
 
 /**
  Write the \b after code to the source file, and to the header file if declared public.
  */
-void Fl_DeclBlock_Type::write_code2() {
+void Fl_DeclBlock_Type::write_code2(Fd_Code_Writer& f) {
   const char* c = after;
   if (public_)
-    write_h("%s\n", c);
-  write_c("%s\n", c);
+    f.write_h("%s\n", c);
+  f.write_c("%s\n", c);
 }
 
 // ---- Fl_Comment_Type declaration
@@ -1496,16 +1496,16 @@ Fl_Type *Fl_Comment_Type::make(Strategy strategy) {
   - "in_source"/"not_in_source" if the comment will be written to the source code
   - "in_header"/"not_in_header" if the comment will be written to the header file
  */
-void Fl_Comment_Type::write_properties() {
-  Fl_Type::write_properties();
-  if (in_c_) write_string("in_source"); else write_string("not_in_source");
-  if (in_h_) write_string("in_header"); else write_string("not_in_header");
+void Fl_Comment_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
+  if (in_c_) f.write_string("in_source"); else f.write_string("not_in_source");
+  if (in_h_) f.write_string("in_header"); else f.write_string("not_in_header");
 }
 
 /**
  Read extra properties.
  */
-void Fl_Comment_Type::read_property(const char *c) {
+void Fl_Comment_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"in_source")) {
     in_c_ = 1;
   } else if (!strcmp(c,"not_in_source")) {
@@ -1515,7 +1515,7 @@ void Fl_Comment_Type::read_property(const char *c) {
   } else if (!strcmp(c,"not_in_header")) {
     in_h_ = 0;
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -1688,7 +1688,7 @@ const char *Fl_Comment_Type::title() {
 /**
  Write the comment to the files.
  */
-void Fl_Comment_Type::write_code1() {
+void Fl_Comment_Type::write_code1(Fd_Code_Writer& f) {
   const char* c = name();
   if (!c) return;
   if (!in_c_ && !in_h_) return;
@@ -1698,8 +1698,8 @@ void Fl_Comment_Type::write_code1() {
   // if this seems to be a C style comment, copy the block as is
   // (it's up to the user to correctly close the comment)
   if (s[0]=='/' && s[1]=='*') {
-    if (in_h_) write_h("%s\n", c);
-    if (in_c_) write_c("%s\n", c);
+    if (in_h_) f.write_h("%s\n", c);
+    if (in_c_) f.write_c("%s\n", c);
     return;
   }
   // copy the comment line by line, add the double slash if needed
@@ -1715,12 +1715,12 @@ void Fl_Comment_Type::write_code1() {
     while (isspace(*s)) s++;
     if (s!=e && ( s[0]!='/' || s[1]!='/') ) {
       // if no comment marker was found, we add one ourselves
-      if (in_h_) write_h("// ");
-      if (in_c_) write_c("// ");
+      if (in_h_) f.write_h("// ");
+      if (in_c_) f.write_c("// ");
     }
     // now copy the rest of the line
-    if (in_h_) write_h("%s\n", b);
-    if (in_c_) write_c("%s\n", b);
+    if (in_h_) f.write_h("%s\n", b);
+    if (in_c_) f.write_c("%s\n", b);
     if (eol==0) break;
     *e++ = eol;
     b = e;
@@ -1795,30 +1795,30 @@ Fl_Type *Fl_Class_Type::make(Strategy strategy) {
   - ":" followed by the super class
   - "private"/"protected"
  */
-void Fl_Class_Type::write_properties() {
-  Fl_Type::write_properties();
+void Fl_Class_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
   if (subclass_of) {
-    write_string(":");
-    write_word(subclass_of);
+    f.write_string(":");
+    f.write_word(subclass_of);
   }
   switch (public_) {
-    case 0: write_string("private"); break;
-    case 2: write_string("protected"); break;
+    case 0: f.write_string("private"); break;
+    case 2: f.write_string("protected"); break;
   }
 }
 
 /**
  Read additional properties.
  */
-void Fl_Class_Type::read_property(const char *c) {
+void Fl_Class_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"private")) {
     public_ = 0;
   } else if (!strcmp(c,"protected")) {
     public_ = 2;
   } else if (!strcmp(c,":")) {
-    storestring(read_word(), subclass_of);
+    storestring(f.read_word(), subclass_of);
   } else {
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
@@ -1832,8 +1832,8 @@ void Fl_Class_Type::open() {
     sprintf(fullname,"%s %s",prefix(),name());
   else
     strcpy(fullname, name());
-  c_name_input->static_value(fullname);
-  c_subclass_input->static_value(subclass_of);
+  c_name_input->value(fullname);
+  c_subclass_input->value(subclass_of);
   c_public_button->value(public_);
   const char *c = comment();
   c_comment_input->buffer()->text(c?c:"");
@@ -1898,25 +1898,25 @@ BREAK2:
 /**
  Write the header code that declares this class.
  */
-void Fl_Class_Type::write_code1() {
+void Fl_Class_Type::write_code1(Fd_Code_Writer& f) {
   parent_class = current_class;
   current_class = this;
   write_public_state = 0;
-  write_h("\n");
-  write_comment_h();
+  f.write_h("\n");
+  write_comment_h(f);
   if (prefix() && strlen(prefix()))
-    write_h("class %s %s ", prefix(), name());
+    f.write_h("class %s %s ", prefix(), name());
   else
-    write_h("class %s ", name());
-  if (subclass_of) write_h(": %s ", subclass_of);
-  write_h("{\n");
+    f.write_h("class %s ", name());
+  if (subclass_of) f.write_h(": %s ", subclass_of);
+  f.write_h("{\n");
 }
 
 /**
  Write the header code that ends the declaration of this class.
  */
-void Fl_Class_Type::write_code2() {
-  write_h("};\n");
+void Fl_Class_Type::write_code2(Fd_Code_Writer& f) {
+  f.write_h("};\n");
   current_class = parent_class;
 }
 
diff --git fluid/Fl_Function_Type.h fluid/Fl_Function_Type.h
index 638458d..c53223f 100644
--- fluid/Fl_Function_Type.h
+++ fluid/Fl_Function_Type.h
@@ -50,8 +50,8 @@ public:
   Fl_Function_Type();
   ~Fl_Function_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void open() FL_OVERRIDE;
   int ismain() {return name_ == 0;}
   const char *type_name() FL_OVERRIDE {return "Function";}
@@ -62,8 +62,8 @@ public:
   int is_code_block() const FL_OVERRIDE {return 1;}
   int is_public() const FL_OVERRIDE;
   int pixmapID() FL_OVERRIDE { return 7; }
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int has_signature(const char *, const char*) const;
 };
 
@@ -78,9 +78,9 @@ class Fl_Code_Type : public Fl_Type {
 public:
   Fl_Code_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write() FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE { }
+  void write(Fd_Project_Writer &f) FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE { }
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "code";}
   int is_code_block() const FL_OVERRIDE {return 0;}
@@ -101,16 +101,16 @@ public:
   Fl_CodeBlock_Type();
   ~Fl_CodeBlock_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "codeblock";}
   int is_code_block() const FL_OVERRIDE {return 1;}
   int is_parent() const FL_OVERRIDE {return 1;}
   int is_public() const FL_OVERRIDE { return -1; }
   int pixmapID() FL_OVERRIDE { return 9; }
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
 };
 
 // ---- Fl_Decl_Type declaration
@@ -124,12 +124,12 @@ protected:
 public:
   Fl_Decl_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE { }
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE { }
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "decl";}
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int is_public() const FL_OVERRIDE;
   int pixmapID() FL_OVERRIDE { return 10; }
 };
@@ -144,12 +144,12 @@ public:
   Fl_Data_Type();
   ~Fl_Data_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE {}
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE {}
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "data";}
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int pixmapID() FL_OVERRIDE { return 49; }
 };
 
@@ -163,12 +163,12 @@ public:
   Fl_DeclBlock_Type();
   ~Fl_DeclBlock_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "declblock";}
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int is_parent() const FL_OVERRIDE {return 1;}
   int is_decl_block() const FL_OVERRIDE {return 1;}
   int is_public() const FL_OVERRIDE;
@@ -184,13 +184,13 @@ class Fl_Comment_Type : public Fl_Type {
 public:
   Fl_Comment_Type();
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE { }
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE { }
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "comment";}
   const char *title() FL_OVERRIDE; // string for browser
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int is_public() const FL_OVERRIDE { return 1; }
   int is_comment() const FL_OVERRIDE { return 1; }
   int pixmapID() FL_OVERRIDE { return 46; }
@@ -211,8 +211,8 @@ public:
   Fl_Class_Type* parent_class; // save class if nested
 //
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void open() FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "class";}
   int is_parent() const FL_OVERRIDE {return 1;}
@@ -220,8 +220,8 @@ public:
   int is_class() const FL_OVERRIDE {return 1;}
   int is_public() const FL_OVERRIDE;
   int pixmapID() FL_OVERRIDE { return 12; }
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
 
   // class prefix attribute access
   void prefix(const char* p);
diff --git fluid/Fl_Group_Type.cxx fluid/Fl_Group_Type.cxx
index 8db3076..38c1544d 100644
--- fluid/Fl_Group_Type.cxx
+++ fluid/Fl_Group_Type.cxx
@@ -131,18 +131,18 @@ void ungroup_cb(Fl_Widget *, void *) {
   set_modflag(1);
 }
 
-void Fl_Group_Type::write_code1() {
-  Fl_Widget_Type::write_code1();
+void Fl_Group_Type::write_code1(Fd_Code_Writer& f) {
+  Fl_Widget_Type::write_code1(f);
 }
 
-void Fl_Group_Type::write_code2() {
+void Fl_Group_Type::write_code2(Fd_Code_Writer& f) {
   const char *var = name() ? name() : "o";
-  write_extra_code();
-  write_c("%s%s->end();\n", indent(), var);
+  write_extra_code(f);
+  f.write_c("%s%s->end();\n", f.indent(), var);
   if (resizable()) {
-    write_c("%sFl_Group::current()->resizable(%s);\n", indent(), var);
+    f.write_c("%sFl_Group::current()->resizable(%s);\n", f.indent(), var);
   }
-  write_block_close();
+  write_block_close(f);
 }
 
 // This is called when o is created.  If it is in the tab group make
@@ -247,95 +247,95 @@ void Fl_Flex_Type::copy_properties()
   d->gap( s->gap() );
 }
 
-void Fl_Flex_Type::write_properties()
+void Fl_Flex_Type::write_properties(Fd_Project_Writer &f)
 {
-  Fl_Group_Type::write_properties();
-  Fl_Flex* f = (Fl_Flex*)o;
+  Fl_Group_Type::write_properties(f);
+  Fl_Flex* flex = (Fl_Flex*)o;
   int lm, tm, rm, bm;
-  f->margin(&lm, &tm, &rm, &bm);
+  flex->margin(&lm, &tm, &rm, &bm);
   if (lm!=0 || tm!=0 || rm!=0 || bm!=0)
-    write_string("margin {%d %d %d %d}", lm, tm, rm, bm);
-  if (f->gap())
-    write_string("gap %d", f->gap());
+    f.write_string("margin {%d %d %d %d}", lm, tm, rm, bm);
+  if (flex->gap())
+    f.write_string("gap %d", flex->gap());
   int nSet = 0;
-  for (int i=0; i<f->children(); i++)
-    if (f->fixed(f->child(i)))
+  for (int i=0; i<flex->children(); i++)
+    if (flex->fixed(flex->child(i)))
       nSet++;
   if (nSet) {
-    write_string("fixed_size_tuples {%d", nSet);
-    for (int i=0; i<f->children(); i++) {
-      Fl_Widget *ci = f->child(i);
-      if (f->fixed(ci))
-        write_string(" %d %d", i, f->horizontal() ? ci->w() : ci->h());
+    f.write_string("fixed_size_tuples {%d", nSet);
+    for (int i=0; i<flex->children(); i++) {
+      Fl_Widget *ci = flex->child(i);
+      if (flex->fixed(ci))
+        f.write_string(" %d %d", i, flex->horizontal() ? ci->w() : ci->h());
     }
-    write_string("}");
+    f.write_string("}");
   }
 }
 
-void Fl_Flex_Type::read_property(const char *c)
+void Fl_Flex_Type::read_property(Fd_Project_Reader &f, const char *c)
 {
-  Fl_Flex* f = (Fl_Flex*)o;
+  Fl_Flex* flex = (Fl_Flex*)o;
   suspend_auto_layout = 1;
   if (!strcmp(c,"margin")) {
     int lm, tm, rm, bm;
-    if (sscanf(read_word(),"%d %d %d %d",&lm,&tm,&rm,&bm) == 4)
-      f->margin(lm, tm, rm, bm);
+    if (sscanf(f.read_word(),"%d %d %d %d",&lm,&tm,&rm,&bm) == 4)
+      flex->margin(lm, tm, rm, bm);
   } else if (!strcmp(c,"gap")) {
     int g;
-    if (sscanf(read_word(),"%d",&g))
-      f->gap(g);
+    if (sscanf(f.read_word(),"%d",&g))
+      flex->gap(g);
   } else if (!strcmp(c,"fixed_size_tuples")) {
-    read_word(1); // must be '{'
-    const char *nStr = read_word(1); // number of indices in table
+    f.read_word(1); // must be '{'
+    const char *nStr = f.read_word(1); // number of indices in table
     fixedSizeTupleSize = atoi(nStr);
     fixedSizeTuple = new int[fixedSizeTupleSize*2];
     for (int i=0; i<fixedSizeTupleSize; i++) {
-      const char *ix = read_word(1); // child at that index is fixed in size
+      const char *ix = f.read_word(1); // child at that index is fixed in size
       fixedSizeTuple[i*2] = atoi(ix);
-      const char *size = read_word(1); // fixed size of that child
+      const char *size = f.read_word(1); // fixed size of that child
       fixedSizeTuple[i*2+1] = atoi(size);
     }
-    read_word(1); // must be '}'
+    f.read_word(1); // must be '}'
   } else {
-    Fl_Group_Type::read_property(c);
+    Fl_Group_Type::read_property(f, c);
   }
 }
 
 void Fl_Flex_Type::postprocess_read()
 {
   if (fixedSizeTupleSize==0) return;
-  Fl_Flex* f = (Fl_Flex*)o;
+  Fl_Flex* flex = (Fl_Flex*)o;
   for (int i=0; i<fixedSizeTupleSize; i++) {
     int ix = fixedSizeTuple[2*i];
     int size = fixedSizeTuple[2*i+1];
-    if (ix>=0 && ix<f->children()) {
-      Fl_Widget *ci = f->child(ix);
-      f->fixed(ci, size);
+    if (ix>=0 && ix<flex->children()) {
+      Fl_Widget *ci = flex->child(ix);
+      flex->fixed(ci, size);
     }
   }
   fixedSizeTupleSize = 0;
   delete[] fixedSizeTuple;
   fixedSizeTuple = NULL;
-  f->layout();
+  flex->layout();
   suspend_auto_layout = 0;
 }
 
-void Fl_Flex_Type::write_code2() {
+void Fl_Flex_Type::write_code2(Fd_Code_Writer& f) {
   const char *var = name() ? name() : "o";
-  Fl_Flex* f = (Fl_Flex*)o;
+  Fl_Flex* flex = (Fl_Flex*)o;
   int lm, tm, rm, bm;
-  f->margin(&lm, &tm, &rm, &bm);
+  flex->margin(&lm, &tm, &rm, &bm);
   if (lm!=0 || tm!=0 || rm!=0 || bm!=0)
-    write_c("%s%s->margin(%d, %d, %d, %d);\n", indent(), var, lm, tm, rm, bm);
-  if (f->gap())
-    write_c("%s%s->gap(%d);\n", indent(), var, f->gap());
-  for (int i=0; i<f->children(); ++i) {
-    Fl_Widget *ci = f->child(i);
-    if (f->fixed(ci))
-      write_c("%s%s->fixed(%s->child(%d), %d);\n", indent(), var, var, i,
-              f->horizontal() ? ci->w() : ci->h());
+    f.write_c("%s%s->margin(%d, %d, %d, %d);\n", f.indent(), var, lm, tm, rm, bm);
+  if (flex->gap())
+    f.write_c("%s%s->gap(%d);\n", f.indent(), var, flex->gap());
+  for (int i=0; i<flex->children(); ++i) {
+    Fl_Widget *ci = flex->child(i);
+    if (flex->fixed(ci))
+      f.write_c("%s%s->fixed(%s->child(%d), %d);\n", f.indent(), var, var, i,
+                flex->horizontal() ? ci->w() : ci->h());
   }
-  Fl_Group_Type::write_code2();
+  Fl_Group_Type::write_code2(f);
 }
 
 void Fl_Flex_Type::add_child(Fl_Type* a, Fl_Type* b) {
diff --git fluid/Fl_Group_Type.h fluid/Fl_Group_Type.h
index ec4e139..e8c8791 100644
--- fluid/Fl_Group_Type.h
+++ fluid/Fl_Group_Type.h
@@ -44,8 +44,8 @@ public:
     igroup *g = new igroup(X,Y,W,H); Fl_Group::current(0); return g;}
   Fl_Widget_Type *_make() FL_OVERRIDE {return new Fl_Group_Type();}
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE;
   void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE;
   void remove_child(Fl_Type*) FL_OVERRIDE;
@@ -91,12 +91,12 @@ public:
   Fl_Widget *widget(int X,int Y,int W,int H) FL_OVERRIDE {
     Fl_Flex *g = new Fl_Flex(X,Y,W,H); Fl_Group::current(0); return g;}
   int pixmapID() FL_OVERRIDE { return 56; }
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE;
   void copy_properties() FL_OVERRIDE;
   void postprocess_read() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE;
   void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE;
   void remove_child(Fl_Type*) FL_OVERRIDE;
diff --git fluid/Fl_Menu_Type.cxx fluid/Fl_Menu_Type.cxx
index f0a7b6a..371f7ab 100644
--- fluid/Fl_Menu_Type.cxx
+++ fluid/Fl_Menu_Type.cxx
@@ -227,7 +227,7 @@ int isdeclare(const char *c);
 // Search backwards to find the parent menu button and return it's name.
 // Also put in i the index into the button's menu item array belonging
 // to this menu item.
-const char* Fl_Menu_Item_Type::menu_name(int& i) {
+const char* Fl_Menu_Item_Type::menu_name(Fd_Code_Writer& f, int& i) {
   i = 0;
   Fl_Type* t = prev;
   while (t && t->is_menu_item()) {
@@ -238,20 +238,21 @@ const char* Fl_Menu_Item_Type::menu_name(int& i) {
     t = t->prev;
     i++;
   }
-  return unique_id(t, "menu", t->name(), t->label());
+  if (!t) return "\n#error Fl_Menu_Item_Type::menu_name, invalid f\n";
+  return f.unique_id(t, "menu", t->name(), t->label());
 }
 
-void Fl_Menu_Item_Type::write_static() {
+void Fl_Menu_Item_Type::write_static(Fd_Code_Writer& f) {
   if (image && label() && label()[0]) {
-    write_declare("#include <FL/Fl.H>");
-    write_declare("#include <FL/Fl_Multi_Label.H>");
+    f.write_h_once("#include <FL/Fl.H>");
+    f.write_h_once("#include <FL/Fl_Multi_Label.H>");
   }
   if (callback() && is_name(callback()) && !user_defined(callback()))
-    write_declare("extern void %s(Fl_Menu_*, %s);", callback(),
+    f.write_h_once("extern void %s(Fl_Menu_*, %s);", callback(),
                   user_data_type() ? user_data_type() : "void*");
   for (int n=0; n < NUM_EXTRA_CODE; n++) {
     if (extra_code(n) && isdeclare(extra_code(n)))
-      write_declare("%s", extra_code(n));
+      f.write_h_once("%s", extra_code(n));
   }
   if (callback() && !is_name(callback())) {
     // see if 'o' or 'v' used, to prevent unused argument warnings:
@@ -264,48 +265,46 @@ void Fl_Menu_Item_Type::write_static() {
       do d++; while (is_id(*d));
       while (*d && !is_id(*d)) d++;
     }
-    const char* cn = callback_name();
+    const char* cn = callback_name(f);
     const char* k = class_name(1);
     if (k) {
-      write_c("\nvoid %s::%s_i(Fl_Menu_*", k, cn);
+      f.write_c("\nvoid %s::%s_i(Fl_Menu_*", k, cn);
     } else {
-      write_c("\nstatic void %s(Fl_Menu_*", cn);
+      f.write_c("\nstatic void %s(Fl_Menu_*", cn);
     }
-    if (use_o) write_c(" o");
+    if (use_o) f.write_c(" o");
     const char* ut = user_data_type() ? user_data_type() : "void*";
-    write_c(", %s", ut);
-    if (use_v) write_c(" v");
-    write_c(") {\n");
-    write_c_indented(callback(), 1, 0);
+    f.write_c(", %s", ut);
+    if (use_v) f.write_c(" v");
+    f.write_c(") {\n");
+    f.write_c_indented(callback(), 1, 0);
     if (*(d-1) != ';' && *(d-1) != '}') {
       const char *p = strrchr(callback(), '\n');
       if (p) p ++;
       else p = callback();
       // Only add trailing semicolon if the last line is not a preprocessor
       // statement...
-      if (*p != '#' && *p) write_c(";");
+      if (*p != '#' && *p) f.write_c(";");
     }
-    write_c("\n}\n");
+    f.write_c("\n}\n");
     if (k) {
-      write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut);
-      write_c("%s((%s*)(o", indent(1), k);
+      f.write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut);
+      f.write_c("%s((%s*)(o", f.indent(1), k);
       Fl_Type* t = parent; while (t->is_menu_item()) t = t->parent;
       Fl_Type *q = 0;
       // Go up one more level for Fl_Input_Choice, as these are groups themselves
       if (t && !strcmp(t->type_name(), "Fl_Input_Choice"))
-        write_c("->parent()");
+        f.write_c("->parent()");
       for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent)
-        write_c("->parent()");
+        f.write_c("->parent()");
       if (!q || strcmp(q->type_name(), "widget_class"))
-        write_c("->user_data()");
-      write_c("))->%s_i(o,v);\n}\n", cn);
+        f.write_c("->user_data()");
+      f.write_c("))->%s_i(o,v);\n}\n", cn);
     }
   }
   if (image) {
-    if (image->written != write_number) {
-      image->write_static(compress_image_);
-      image->written = write_number;
-    }
+    if (!f.c_contains(image))
+      image->write_static(f, compress_image_);
   }
   if (next && next->is_menu_item()) return;
   // okay, when we hit last item in the menu we have to write the
@@ -313,20 +312,20 @@ void Fl_Menu_Item_Type::write_static() {
   const char* k = class_name(1);
   if (k) {
     int i;
-    write_c("\nFl_Menu_Item %s::%s[] = {\n", k, menu_name(i));
+    f.write_c("\nFl_Menu_Item %s::%s[] = {\n", k, menu_name(f, i));
   } else {
     int i;
-    write_c("\nFl_Menu_Item %s[] = {\n", menu_name(i));
+    f.write_c("\nFl_Menu_Item %s[] = {\n", menu_name(f, i));
   }
   Fl_Type* t = prev; while (t && t->is_menu_item()) t = t->prev;
   for (Fl_Type* q = t->next; q && q->is_menu_item(); q = q->next) {
-    ((Fl_Menu_Item_Type*)q)->write_item();
+    ((Fl_Menu_Item_Type*)q)->write_item(f);
     int thislevel = q->level; if (q->is_parent()) thislevel++;
     int nextlevel =
       (q->next && q->next->is_menu_item()) ? q->next->level : t->level+1;
-    while (thislevel > nextlevel) {write_c(" {0,0,0,0,0,0,0,0,0},\n"); thislevel--;}
+    while (thislevel > nextlevel) {f.write_c(" {0,0,0,0,0,0,0,0,0},\n"); thislevel--;}
   }
-  write_c(" {0,0,0,0,0,0,0,0,0}\n};\n");
+  f.write_c(" {0,0,0,0,0,0,0,0,0}\n};\n");
 
   if (k) {
     // Write menu item variables...
@@ -338,12 +337,12 @@ void Fl_Menu_Item_Type::write_static() {
         if (c==m->name()) {
           // assign a menu item address directly to a variable
           int i;
-          const char* n = ((Fl_Menu_Item_Type *)q)->menu_name(i);
-          write_c("Fl_Menu_Item* %s::%s = %s::%s + %d;\n", k, c, k, n, i);
+          const char* n = ((Fl_Menu_Item_Type *)q)->menu_name(f, i);
+          f.write_c("Fl_Menu_Item* %s::%s = %s::%s + %d;\n", k, c, k, n, i);
         } else {
           // if the name is an array, only define the array.
-          // The actual assignment is in write_code1()
-          write_c("Fl_Menu_Item* %s::%s;\n", k, c);
+          // The actual assignment is in write_code1(Fd_Code_Writer& f)
+          f.write_c("Fl_Menu_Item* %s::%s;\n", k, c);
         }
       }
     }
@@ -363,7 +362,7 @@ int Fl_Menu_Item_Type::flags() {
   return i;
 }
 
-void Fl_Menu_Item_Type::write_item() {
+void Fl_Menu_Item_Type::write_item(Fd_Code_Writer& f) {
   static const char * const labeltypes[] = {
     "FL_NORMAL_LABEL",
     "FL_NO_LABEL",
@@ -375,120 +374,120 @@ void Fl_Menu_Item_Type::write_item() {
     "FL_IMAGE_LABEL"
   };
 
-  write_comment_inline_c(" ");
-  write_c(" {");
+  write_comment_inline_c(f, " ");
+  f.write_c(" {");
   if (label() && label()[0])
     switch (g_project.i18n_type) {
       case 1:
         // we will call i18n when the menu is instantiated for the first time
-        write_c("%s(", g_project.i18n_static_function.value());
-        write_cstring(label());
-        write_c(")");
+        f.write_c("%s(", g_project.i18n_static_function.value());
+        f.write_cstring(label());
+        f.write_c(")");
         break;
       case 2:
         // fall through: strings can't be translated before a catalog is choosen
       default:
-        write_cstring(label());
+        f.write_cstring(label());
     }
   else
-    write_c("\"\"");
+    f.write_c("\"\"");
   if (((Fl_Button*)o)->shortcut()) {
                 int s = ((Fl_Button*)o)->shortcut();
                 if (g_project.use_FL_COMMAND && (s & (FL_CTRL|FL_META))) {
-                        write_c(", FL_COMMAND|0x%x, ", s & ~(FL_CTRL|FL_META));
+                        f.write_c(", FL_COMMAND|0x%x, ", s & ~(FL_CTRL|FL_META));
                 } else {
-                        write_c(", 0x%x, ", s);
+                        f.write_c(", 0x%x, ", s);
                 }
   } else
-    write_c(", 0, ");
+    f.write_c(", 0, ");
   if (callback()) {
     const char* k = is_name(callback()) ? 0 : class_name(1);
     if (k) {
-      write_c(" (Fl_Callback*)%s::%s,", k, callback_name());
+      f.write_c(" (Fl_Callback*)%s::%s,", k, callback_name(f));
     } else {
-      write_c(" (Fl_Callback*)%s,", callback_name());
+      f.write_c(" (Fl_Callback*)%s,", callback_name(f));
     }
   } else
-    write_c(" 0,");
+    f.write_c(" 0,");
   if (user_data())
-    write_c(" (void*)(%s),", user_data());
+    f.write_c(" (void*)(%s),", user_data());
   else
-    write_c(" 0,");
-  write_c(" %d, (uchar)%s, %d, %d, %d", flags(),
+    f.write_c(" 0,");
+  f.write_c(" %d, (uchar)%s, %d, %d, %d", flags(),
           labeltypes[o->labeltype()], o->labelfont(), o->labelsize(), o->labelcolor());
-  write_c("},\n");
+  f.write_c("},\n");
 }
 
-void start_menu_initialiser(int &initialized, const char *name, int index) {
+void start_menu_initialiser(Fd_Code_Writer& f, int &initialized, const char *name, int index) {
   if (!initialized) {
     initialized = 1;
-    write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", indent(), name, index);
-    indentation++;
+    f.write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", f.indent(), name, index);
+    f.indentation++;
   }
 }
 
-void Fl_Menu_Item_Type::write_code1() {
-  int i; const char* mname = menu_name(i);
+void Fl_Menu_Item_Type::write_code1(Fd_Code_Writer& f) {
+  int i; const char* mname = menu_name(f, i);
 
   if (!prev->is_menu_item()) {
     // for first menu item, declare the array
     if (class_name(1)) {
-      write_h("%sstatic Fl_Menu_Item %s[];\n", indent(1), mname);
+      f.write_h("%sstatic Fl_Menu_Item %s[];\n", f.indent(1), mname);
     } else {
-      write_h("extern Fl_Menu_Item %s[];\n", mname);
+      f.write_h("extern Fl_Menu_Item %s[];\n", mname);
     }
   }
 
   const char *c = array_name(this);
   if (c) {
     if (class_name(1)) {
-      write_public(public_);
-      write_h("%sstatic Fl_Menu_Item *%s;\n", indent(1), c);
+      f.write_public(public_);
+      f.write_h("%sstatic Fl_Menu_Item *%s;\n", f.indent(1), c);
     } else {
       if (c==name())
-        write_h("#define %s (%s+%d)\n", c, mname, i);
+        f.write_h("#define %s (%s+%d)\n", c, mname, i);
       else
-        write_h("extern Fl_Menu_Item *%s;\n", c);
+        f.write_h("extern Fl_Menu_Item *%s;\n", c);
     }
   }
 
   if (callback()) {
     if (!is_name(callback()) && class_name(1)) {
-      const char* cn = callback_name();
+      const char* cn = callback_name(f);
       const char* ut = user_data_type() ? user_data_type() : "void*";
-      write_public(0);
-      write_h("%sinline void %s_i(Fl_Menu_*, %s);\n", indent(1), cn, ut);
-      write_h("%sstatic void %s(Fl_Menu_*, %s);\n", indent(1), cn, ut);
+      f.write_public(0);
+      f.write_h("%sinline void %s_i(Fl_Menu_*, %s);\n", f.indent(1), cn, ut);
+      f.write_h("%sstatic void %s(Fl_Menu_*, %s);\n", f.indent(1), cn, ut);
     }
   }
 
   int menuItemInitialized = 0;
   // if the name is an array variable, assign the value here
   if (name() && strchr(name(), '[')) {
-    write_c("%s%s = &%s[%d];\n", indent_plus(1), name(), mname, i);
+    f.write_c("%s%s = &%s[%d];\n", f.indent_plus(1), name(), mname, i);
   }
   if (image) {
-    start_menu_initialiser(menuItemInitialized, mname, i);
+    start_menu_initialiser(f, menuItemInitialized, mname, i);
     if (label() && label()[0]) {
-      write_c("%sFl_Multi_Label *ml = new Fl_Multi_Label;\n", indent());
-      write_c("%sml->labela = (char*)", indent());
-      image->write_inline();
-      write_c(";\n");
+      f.write_c("%sFl_Multi_Label *ml = new Fl_Multi_Label;\n", f.indent());
+      f.write_c("%sml->labela = (char*)", f.indent());
+      image->write_inline(f);
+      f.write_c(";\n");
       if (g_project.i18n_type==0) {
-        write_c("%sml->labelb = o->label();\n", indent());
+        f.write_c("%sml->labelb = o->label();\n", f.indent());
       } else if (g_project.i18n_type==1) {
-        write_c("%sml->labelb = %s(o->label());\n",
-                indent(), g_project.i18n_function.value());
+        f.write_c("%sml->labelb = %s(o->label());\n",
+                f.indent(), g_project.i18n_function.value());
       } else if (g_project.i18n_type==2) {
-        write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n",
-                indent(), g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
+        f.write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n",
+                f.indent(), g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
                 g_project.i18n_set.value(), msgnum());
       }
-      write_c("%sml->typea = FL_IMAGE_LABEL;\n", indent());
-      write_c("%sml->typeb = FL_NORMAL_LABEL;\n", indent());
-      write_c("%sml->label(o);\n", indent());
+      f.write_c("%sml->typea = FL_IMAGE_LABEL;\n", f.indent());
+      f.write_c("%sml->typeb = FL_NORMAL_LABEL;\n", f.indent());
+      f.write_c("%sml->label(o);\n", f.indent());
     } else {
-      image->write_code(0, "o");
+      image->write_code(f, 0, "o");
     }
   }
   if (g_project.i18n_type && label() && label()[0]) {
@@ -497,30 +496,30 @@ void Fl_Menu_Item_Type::write_code1() {
       // label was already copied a few lines up
     } else if (   t==FL_NORMAL_LABEL   || t==FL_SHADOW_LABEL
                || t==FL_ENGRAVED_LABEL || t==FL_EMBOSSED_LABEL) {
-      start_menu_initialiser(menuItemInitialized, mname, i);
+      start_menu_initialiser(f, menuItemInitialized, mname, i);
       if (g_project.i18n_type==1) {
-        write_c("%so->label(%s(o->label()));\n",
-                indent(), g_project.i18n_function.value());
+        f.write_c("%so->label(%s(o->label()));\n",
+                f.indent(), g_project.i18n_function.value());
       } else if (g_project.i18n_type==2) {
-        write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n",
-                indent(), g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
+        f.write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n",
+                f.indent(), g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
                 g_project.i18n_set.value(), msgnum());
       }
     }
   }
   for (int n=0; n < NUM_EXTRA_CODE; n++) {
     if (extra_code(n) && !isdeclare(extra_code(n))) {
-      start_menu_initialiser(menuItemInitialized, mname, i);
-      write_c("%s%s\n", indent(), extra_code(n));
+      start_menu_initialiser(f, menuItemInitialized, mname, i);
+      f.write_c("%s%s\n", f.indent(), extra_code(n));
     }
   }
   if (menuItemInitialized) {
-    indentation--;
-    write_c("%s}\n",indent());
+    f.indentation--;
+    f.write_c("%s}\n",f.indent());
   }
 }
 
-void Fl_Menu_Item_Type::write_code2() {}
+void Fl_Menu_Item_Type::write_code2(Fd_Code_Writer&) {}
 
 ////////////////////////////////////////////////////////////////
 // This is the base class for widgets that contain a menu (ie
@@ -612,12 +611,12 @@ Fl_Type* Fl_Menu_Type::click_test(int, int) {
   return this;
 }
 
-void Fl_Menu_Type::write_code2() {
+void Fl_Menu_Type::write_code2(Fd_Code_Writer& f) {
   if (next && next->is_menu_item()) {
-    write_c("%s%s->menu(%s);\n", indent(), name() ? name() : "o",
-            unique_id(this, "menu", name(), label()));
+    f.write_c("%s%s->menu(%s);\n", f.indent(), name() ? name() : "o",
+            f.unique_id(this, "menu", name(), label()));
   }
-  Fl_Widget_Type::write_code2();
+  Fl_Widget_Type::write_code2(f);
 }
 
 void Fl_Menu_Type::copy_properties() {
diff --git fluid/Fl_Menu_Type.h fluid/Fl_Menu_Type.h
index 6b8da25..5aca716 100644
--- fluid/Fl_Menu_Type.h
+++ fluid/Fl_Menu_Type.h
@@ -41,12 +41,12 @@ public:
   int is_button() const FL_OVERRIDE {return 1;} // this gets shortcut to work
   Fl_Widget* widget(int,int,int,int) FL_OVERRIDE {return 0;}
   Fl_Widget_Type* _make() FL_OVERRIDE {return 0;}
-  virtual const char* menu_name(int& i);
+  virtual const char* menu_name(Fd_Code_Writer& f, int& i);
   int flags();
-  void write_static() FL_OVERRIDE;
-  void write_item();
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_static(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_item(Fd_Code_Writer& f);
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   int pixmapID() FL_OVERRIDE { return 16; }
 };
 
@@ -105,7 +105,7 @@ public:
   void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE {build_menu();}
   void remove_child(Fl_Type*) FL_OVERRIDE {build_menu();}
   Fl_Type* click_test(int x, int y) FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   void copy_properties() FL_OVERRIDE;
 };
 
diff --git fluid/Fl_Type.cxx fluid/Fl_Type.cxx
index 2db91d5..a662dbb 100644
--- fluid/Fl_Type.cxx
+++ fluid/Fl_Type.cxx
@@ -160,9 +160,14 @@ void later_cb(Fl_Widget*,void*) {
   widget_browser->rebuild();
 }
 
+/** \brief Delete all children of a Type.
+ */
 static void delete_children(Fl_Type *p) {
   Fl_Type *f;
+  // find all types following p that are higher in level, effectively finding
+  // the last child of the last child
   for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/}
+  // now loop back up to p, deleting all children on the way
   for (; f != p; ) {
     Fl_Type *g = f->prev;
     delete f;
@@ -178,7 +183,9 @@ void delete_all(int selected_only) {
       Fl_Type *g = f->next;
       delete f;
       f = g;
-    } else f = f->next;
+    } else {
+      f = f->next;
+    }
   }
   if(!selected_only) {
     // reset the setting for the external shell command
@@ -281,11 +288,11 @@ Fl_Type::Fl_Type() {
  */
 Fl_Type::~Fl_Type() {
   // warning: destructor only works for widgets that have been add()ed.
-  if (prev) prev->next = next; else first = next;
-  if (next) next->prev = prev; else last = prev;
-  if (Fl_Type::last==this) Fl_Type::last = prev;
-  if (Fl_Type::first==this) Fl_Type::first = next;
-  if (current == this) current = 0;
+  if (prev) prev->next = next; // else first = next; // don't do that! The Type may not be part of the main list
+  if (next) next->prev = prev; // else last = prev;
+  if (Fl_Type::last == this) Fl_Type::last = prev;
+  if (Fl_Type::first == this) Fl_Type::first = next;
+  if (current == this) current = NULL;
   if (parent) parent->remove_child(this);
   if (name_) free((void*)name_);
   if (label_) free((void*)label_);
@@ -576,76 +583,76 @@ void Fl_Type::move_before(Fl_Type* g) {
 
 
 // write a widget and all its children:
-void Fl_Type::write() {
-    write_indent(level);
-    write_word(type_name());
-
-    if (is_class()) {
-      const char * p =  ((Fl_Class_Type*)this)->prefix();
-      if (p &&  strlen(p))
-        write_word(p);
-    }
+void Fl_Type::write(Fd_Project_Writer &f) {
+  f.write_indent(level);
+  f.write_word(type_name());
+
+  if (is_class()) {
+    const char * p =  ((Fl_Class_Type*)this)->prefix();
+    if (p &&  strlen(p))
+      f.write_word(p);
+  }
 
-    write_word(name());
-    write_open(level);
-    write_properties();
-    write_close(level);
-    if (!is_parent()) return;
-    // now do children:
-    write_open(level);
-    Fl_Type *child;
-    for (child = next; child && child->level > level; child = child->next)
-        if (child->level == level+1) child->write();
-    write_close(level);
+  f.write_word(name());
+  f.write_open(level);
+  write_properties(f);
+  f.write_close(level);
+  if (!is_parent()) return;
+  // now do children:
+  f.write_open(level);
+  Fl_Type *child;
+  for (child = next; child && child->level > level; child = child->next)
+    if (child->level == level+1) child->write(f);
+  f.write_close(level);
 }
 
-void Fl_Type::write_properties() {
+void Fl_Type::write_properties(Fd_Project_Writer &f) {
   // repeat this for each attribute:
   if (label()) {
-    write_indent(level+1);
-    write_word("label");
-    write_word(label());
+    f.write_indent(level+1);
+    f.write_word("label");
+    f.write_word(label());
   }
   if (user_data()) {
-    write_indent(level+1);
-    write_word("user_data");
-    write_word(user_data());
+    f.write_indent(level+1);
+    f.write_word("user_data");
+    f.write_word(user_data());
   }
   if (user_data_type()) {
-    write_word("user_data_type");
-    write_word(user_data_type());
+    f.write_word("user_data_type");
+    f.write_word(user_data_type());
   }
   if (callback()) {
-    write_indent(level+1);
-    write_word("callback");
-    write_word(callback());
+    f.write_indent(level+1);
+    f.write_word("callback");
+    f.write_word(callback());
   }
   if (comment()) {
-    write_indent(level+1);
-    write_word("comment");
-    write_word(comment());
+    f.write_indent(level+1);
+    f.write_word("comment");
+    f.write_word(comment());
   }
-  if (is_parent() && open_) write_word("open");
-  if (selected) write_word("selected");
+  if (is_parent() && open_) f.write_word("open");
+  if (selected) f.write_word("selected");
 }
 
-void Fl_Type::read_property(const char *c) {
+void Fl_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"label"))
-    label(read_word());
+    label(f.read_word());
   else if (!strcmp(c,"user_data"))
-    user_data(read_word());
+    user_data(f.read_word());
   else if (!strcmp(c,"user_data_type"))
-    user_data_type(read_word());
+    user_data_type(f.read_word());
   else if (!strcmp(c,"callback"))
-    callback(read_word());
+    callback(f.read_word());
   else if (!strcmp(c,"comment"))
-    comment(read_word());
+    comment(f.read_word());
   else if (!strcmp(c,"open"))
     open_ = 1;
   else if (!strcmp(c,"selected"))
     select(this,1);
   else
-    read_error("Unknown property \"%s\"", c);
+    f.read_error("Unknown property \"%s\"", c);
 }
 
 int Fl_Type::read_fdesign(const char*, const char*) {return 0;}
@@ -654,86 +661,86 @@ int Fl_Type::read_fdesign(const char*, const char*) {return 0;}
  Write a comment into the header file.
  \param[in] pre indent the comment by this string
 */
-void Fl_Type::write_comment_h(const char *pre)
+void Fl_Type::write_comment_h(Fd_Code_Writer& f, const char *pre)
 {
   if (comment() && *comment()) {
-    write_h("%s/**\n", pre);
+    f.write_h("%s/**\n", pre);
     const char *s = comment();
-    write_h("%s ", pre);
+    f.write_h("%s ", pre);
     while(*s) {
       if (*s=='\n') {
         if (s[1]) {
-          write_h("\n%s ", pre);
+          f.write_h("\n%s ", pre);
         }
       } else {
-        write_h("%c", *s); // FIXME this is much too slow!
+        f.write_h("%c", *s); // FIXME this is much too slow!
       }
       s++;
     }
-    write_h("\n%s*/\n", pre);
+    f.write_h("\n%s*/\n", pre);
   }
 }
 
 /**
   Write a comment into the source file.
 */
-void Fl_Type::write_comment_c(const char *pre)
+void Fl_Type::write_comment_c(Fd_Code_Writer& f, const char *pre)
 {
   if (comment() && *comment()) {
-    write_c("%s/**\n", pre);
+    f.write_c("%s/**\n", pre);
     const char *s = comment();
-    write_c("%s ", pre);
+    f.write_c("%s ", pre);
     while(*s) {
       if (*s=='\n') {
         if (s[1]) {
-          write_c("\n%s ", pre);
+          f.write_c("\n%s ", pre);
         }
       } else {
-        write_c("%c", *s); // FIXME this is much too slow!
+        f.write_c("%c", *s); // FIXME this is much too slow!
       }
       s++;
     }
-    write_c("\n%s*/\n", pre);
+    f.write_c("\n%s*/\n", pre);
   }
 }
 
 /**
   Write a comment into the source file.
 */
-void Fl_Type::write_comment_inline_c(const char *pre)
+void Fl_Type::write_comment_inline_c(Fd_Code_Writer& f, const char *pre)
 {
   if (comment() && *comment()) {
     const char *s = comment();
     if (strchr(s, '\n')==0L) {
       // single line comment
-      if (pre) write_c("%s", pre);
-      write_c("// %s\n", s);
-      if (!pre) write_c("%s", indent_plus(1));
+      if (pre) f.write_c("%s", pre);
+      f.write_c("// %s\n", s);
+      if (!pre) f.write_c("%s", f.indent_plus(1));
     } else {
-      write_c("%s/*\n", pre?pre:"");
+      f.write_c("%s/*\n", pre?pre:"");
       if (pre)
-        write_c("%s ", pre);
+        f.write_c("%s ", pre);
       else
-        write_c("%s ", indent_plus(1));
+        f.write_c("%s ", f.indent_plus(1));
       while(*s) {
         if (*s=='\n') {
           if (s[1]) {
             if (pre)
-              write_c("\n%s ", pre);
+              f.write_c("\n%s ", pre);
             else
-              write_c("\n%s ", indent_plus(1));
+              f.write_c("\n%s ", f.indent_plus(1));
           }
         } else {
-          write_c("%c", *s); // FIXME this is much too slow!
+          f.write_c("%c", *s); // FIXME this is much too slow!
         }
         s++;
       }
       if (pre)
-        write_c("\n%s */\n", pre);
+        f.write_c("\n%s */\n", pre);
       else
-        write_c("\n%s */\n", indent_plus(1));
+        f.write_c("\n%s */\n", f.indent_plus(1));
       if (!pre)
-        write_c("%s", indent_plus(1));
+        f.write_c("%s", f.indent_plus(1));
     }
   }
 }
@@ -777,9 +784,9 @@ int Fl_Type::user_defined(const char* cbname) const {
   return 0;
 }
 
-const char *Fl_Type::callback_name() {
+const char *Fl_Type::callback_name(Fd_Code_Writer& f) {
   if (is_name(callback())) return callback();
-  return unique_id(this, "cb", name(), label());
+  return f.unique_id(this, "cb", name(), label());
 }
 
 const char* Fl_Type::class_name(const int need_nest) const {
@@ -818,15 +825,15 @@ const Fl_Class_Type *Fl_Type::is_in_class() const {
   return 0;
 }
 
-void Fl_Type::write_static() {
+void Fl_Type::write_static(Fd_Code_Writer&) {
 }
 
-void Fl_Type::write_code1() {
-  write_h("// Header for %s\n", title());
-  write_c("// Code for %s\n", title());
+void Fl_Type::write_code1(Fd_Code_Writer& f) {
+  f.write_h("// Header for %s\n", title());
+  f.write_c("// Code for %s\n", title());
 }
 
-void Fl_Type::write_code2() {
+void Fl_Type::write_code2(Fd_Code_Writer&) {
 }
 
 /// \}
diff --git fluid/Fl_Type.h fluid/Fl_Type.h
index 86bfdb8..d52ffa5 100644
--- fluid/Fl_Type.h
+++ fluid/Fl_Type.h
@@ -20,10 +20,15 @@
 #include <FL/Fl_Widget.H>
 #include <FL/fl_draw.H>
 
+#include "code.h"
+
 class Fl_Type;
 class Fl_Group_Type;
 class Fl_Window_Type;
 
+class Fd_Project_Reader;
+class Fd_Project_Writer;
+
 typedef enum {
   kAddAsLastChild = 0,
   kAddAfterCurrent
@@ -72,7 +77,7 @@ public: // things that should not be public:
   Fl_Type *first_child();
 
   Fl_Type *factory;
-  const char *callback_name();
+  const char *callback_name(Fd_Code_Writer& f);
 
   int code_position, header_position;
   int code_position_end, header_position_end;
@@ -121,19 +126,19 @@ public:
   virtual void open();  // what happens when you double-click
 
   // read and write data to a saved file:
-  virtual void write();
-  virtual void write_properties();
-  virtual void read_property(const char *);
+  virtual void write(Fd_Project_Writer &f);
+  virtual void write_properties(Fd_Project_Writer &f);
+  virtual void read_property(Fd_Project_Reader &f, const char *);
   virtual int read_fdesign(const char*, const char*);
   virtual void postprocess_read() { }
 
   // write code, these are called in order:
-  virtual void write_static(); // write static stuff to .c file
-  virtual void write_code1(); // code and .h before children
-  virtual void write_code2(); // code and .h after children
-  void write_comment_h(const char *ind=""); // write the commentary text into the header file
-  void write_comment_c(const char *ind=""); // write the commentary text into the source file
-  void write_comment_inline_c(const char *ind=0L); // write the commentary text
+  virtual void write_static(Fd_Code_Writer& f); // write static stuff to .c file
+  virtual void write_code1(Fd_Code_Writer& f); // code and .h before children
+  virtual void write_code2(Fd_Code_Writer& f); // code and .h after children
+  void write_comment_h(Fd_Code_Writer& f, const char *ind=""); // write the commentary text into the header file
+  void write_comment_c(Fd_Code_Writer& f, const char *ind=""); // write the commentary text into the source file
+  void write_comment_inline_c(Fd_Code_Writer& f, const char *ind=0L); // write the commentary text
 
   // live mode
   virtual Fl_Widget *enter_live_mode(int top=0); // build wdgets needed for live mode
diff --git fluid/Fl_Widget_Type.cxx fluid/Fl_Widget_Type.cxx
index 32705b4..76cc31b 100644
--- fluid/Fl_Widget_Type.cxx
+++ fluid/Fl_Widget_Type.cxx
@@ -286,7 +286,7 @@ Fl_Type *sort(Fl_Type *parent) {
     if (!f->selected || (!f->is_widget() || f->is_menu_item())) continue;
     Fl_Widget* fw = ((Fl_Widget_Type*)f)->o;
     Fl_Type *g; // we will insert before this
-    for (g = parent->next; g != f; g = g->next) {
+    for (g = parent ? parent->next : Fl_Type::first; g != f; g = g->next) {
       if (!g->selected || g->level > f->level) continue;
       Fl_Widget* gw = ((Fl_Widget_Type*)g)->o;
       if (gw->y() > fw->y()) break;
@@ -320,7 +320,7 @@ void name_cb(Fl_Input* o, void *v) {
       snprintf(buf, sizeof(buf), "Widget Properties (%d widgets)", numselected);
       o->hide();
     } else {
-      o->static_value(current_widget->name());
+      o->value(current_widget->name());
       o->show();
       snprintf(buf, sizeof(buf), "%s Properties", current_widget->title());
     }
@@ -384,7 +384,7 @@ void name_public_cb(Fl_Choice* i, void* v) {
 /* Treating UNDO for text widget.
 
  Goal: we want to continiously update the UI while the user is typing text
- (changing the label, in this case). Source View does deferred uodates, and
+ (changing the label, in this case). Source View does deferred updates, and
  the widget browser and widget panel update on every keystroke. At the same
  time, we want to limit undo actions to few and logical units.
 
@@ -397,7 +397,7 @@ void name_public_cb(Fl_Choice* i, void* v) {
  The edit process has these main states:
 
  1: starting to edit [first_change==1 && !unfocus]; we must create a single undo checkpoint before anything changes
- 2: continue editing [first_change==0 && !unfocus] ; we must suspend any undo checkpoints
+ 2: continue editing [first_change==0 && !unfocus]; we must suspend any undo checkpoints
  3: done editing, unfocus [first_change==0 && unfocus]; we must make sure that undo checkpoints are enabled again
  4: losing focus without editing [first_change==1 && unfocus]; don't create and checkpoints
 
@@ -409,7 +409,7 @@ void name_public_cb(Fl_Choice* i, void* v) {
 void label_cb(Fl_Input* i, void *v) {
   static int first_change = 1;
   if (v == LOAD) {
-    i->static_value(current_widget->label());
+    i->value(current_widget->label());
     first_change = 1;
   } else {
     if (i->changed()) {
@@ -444,7 +444,7 @@ void image_cb(Fl_Input* i, void *v) {
     image_input = i;
     if (current_widget->is_widget() && !current_widget->is_window()) {
       i->activate();
-      i->static_value(((Fl_Widget_Type*)current_widget)->image_name());
+      i->value(((Fl_Widget_Type*)current_widget)->image_name());
     } else i->deactivate();
   } else {
     int mod = 0;
@@ -526,7 +526,7 @@ void inactive_cb(Fl_Input* i, void *v) {
     inactive_input = i;
     if (current_widget->is_widget() && !current_widget->is_window()) {
       i->activate();
-      i->static_value(((Fl_Widget_Type*)current_widget)->inactive_name());
+      i->value(((Fl_Widget_Type*)current_widget)->inactive_name());
     } else i->deactivate();
   } else {
     int mod = 0;
@@ -605,7 +605,7 @@ void tooltip_cb(Fl_Input* i, void *v) {
   if (v == LOAD) {
     if (current_widget->is_widget()) {
       i->activate();
-      i->static_value(((Fl_Widget_Type*)current_widget)->tooltip());
+      i->value(((Fl_Widget_Type*)current_widget)->tooltip());
     } else i->deactivate();
   } else {
     int mod = 0;
@@ -1736,7 +1736,7 @@ void comment_cb(Fl_Text_Editor* i, void *v) {
 
 void user_data_cb(Fl_Input *i, void *v) {
   if (v == LOAD) {
-    i->static_value(current_widget->user_data());
+    i->value(current_widget->user_data());
   } else {
     int mod = 0;
     const char *c = i->value();
@@ -1784,7 +1784,7 @@ void user_data_type_cb(Fl_Input_Choice *i, void *v) {
 void v_input_cb(Fl_Input* i, void* v) {
   int n = fl_int(i->user_data());
   if (v == LOAD) {
-    i->static_value(current_widget->extra_code(n));
+    i->value(current_widget->extra_code(n));
   } else {
     int mod = 0;
     const char *c = i->value();
@@ -1804,7 +1804,7 @@ void v_input_cb(Fl_Input* i, void* v) {
 void subclass_cb(Fl_Input* i, void* v) {
   if (v == LOAD) {
     if (current_widget->is_menu_item()) {i->deactivate(); return;} else i->activate();
-    i->static_value(current_widget->subclass());
+    i->value(current_widget->subclass());
   } else {
     int mod = 0;
     const char *c = i->value();
@@ -2735,15 +2735,15 @@ int isdeclare(const char *c) {
   return 0;
 }
 
-void Fl_Widget_Type::write_static() {
+void Fl_Widget_Type::write_static(Fd_Code_Writer& f) {
   const char* t = subclassname(this);
   if (!subclass() || (is_class() && !strncmp(t, "Fl_", 3))) {
-    write_declare("#include <FL/Fl.H>");
-    write_declare("#include <FL/%s.H>", t);
+    f.write_h_once("#include <FL/Fl.H>");
+    f.write_h_once("#include <FL/%s.H>", t);
   }
   for (int n=0; n < NUM_EXTRA_CODE; n++) {
     if (extra_code(n) && isdeclare(extra_code(n)))
-      write_declare("%s", extra_code(n));
+      f.write_h_once("%s", extra_code(n));
   }
   if (callback() && is_name(callback())) {
     int write_extern_declaration = 1;
@@ -2757,17 +2757,17 @@ void Fl_Widget_Type::write_static() {
         write_extern_declaration = 0;
     }
     if (write_extern_declaration)
-      write_declare("extern void %s(%s*, %s);", callback(), t,
+      f.write_h_once("extern void %s(%s*, %s);", callback(), t,
                     user_data_type() ? user_data_type() : "void*");
   }
   const char* k = class_name(1);
   const char* c = array_name(this);
   if (c && !k && !is_class()) {
-    write_c("\n");
-    if (!public_) write_c("static ");
-    else write_h("extern %s *%s;\n", t, c);
-    if (strchr(c, '[') == NULL) write_c("%s *%s=(%s *)0;\n", t, c, t);
-    else write_c("%s *%s={(%s *)0};\n", t, c, t);
+    f.write_c("\n");
+    if (!public_) f.write_c("static ");
+    else f.write_h("extern %s *%s;\n", t, c);
+    if (strchr(c, '[') == NULL) f.write_c("%s *%s=(%s *)0;\n", t, c, t);
+    else f.write_c("%s *%s={(%s *)0};\n", t, c, t);
   }
   if (callback() && !is_name(callback())) {
     // see if 'o' or 'v' used, to prevent unused argument warnings:
@@ -2780,157 +2780,167 @@ void Fl_Widget_Type::write_static() {
       do d++; while (is_id(*d));
       while (*d && !is_id(*d)) d++;
     }
-    const char* cn = callback_name();
+    const char* cn = callback_name(f);
     if (k) {
-      write_c("\nvoid %s::%s_i(%s*", k, cn, t);
+      f.write_c("\nvoid %s::%s_i(%s*", k, cn, t);
     } else {
-      write_c("\nstatic void %s(%s*", cn, t);
+      f.write_c("\nstatic void %s(%s*", cn, t);
     }
-    if (use_o) write_c(" o");
+    if (use_o) f.write_c(" o");
     const char* ut = user_data_type() ? user_data_type() : "void*";
-    write_c(", %s", ut);
-    if (use_v) write_c(" v");
-    write_c(") {\n");
-    write_c_indented(callback(), 1, 0);
+    f.write_c(", %s", ut);
+    if (use_v) f.write_c(" v");
+    f.write_c(") {\n");
+    f.write_c_indented(callback(), 1, 0);
     if (*(d-1) != ';' && *(d-1) != '}') {
       const char *p = strrchr(callback(), '\n');
       if (p) p ++;
       else p = callback();
       // Only add trailing semicolon if the last line is not a preprocessor
       // statement...
-      if (*p != '#' && *p) write_c(";");
+      if (*p != '#' && *p) f.write_c(";");
     }
-    write_c("\n}\n");
+    f.write_c("\n}\n");
     if (k) {
-      write_c("void %s::%s(%s* o, %s v) {\n", k, cn, t, ut);
-      write_c("%s((%s*)(o", indent(1), k);
+      f.write_c("void %s::%s(%s* o, %s v) {\n", k, cn, t, ut);
+      f.write_c("%s((%s*)(o", f.indent(1), k);
       Fl_Type *q = 0;
       for (Fl_Type* p = parent; p && p->is_widget(); q = p, p = p->parent)
-        write_c("->parent()");
+        f.write_c("->parent()");
       if (!q || strcmp(q->type_name(), "widget_class"))
-        write_c("->user_data()");
-      write_c("))->%s_i(o,v);\n}\n", cn);
+        f.write_c("->user_data()");
+      f.write_c("))->%s_i(o,v);\n}\n", cn);
     }
   }
   if (image) {
-    if (image->written != write_number) {
-      image->write_static(compress_image_);
-      image->written = write_number;
-    }
+    if (!f.c_contains(image))
+      image->write_static(f, compress_image_);
   }
   if (inactive) {
-    if (inactive->written != write_number) {
-      inactive->write_static(compress_deimage_);
-      inactive->written = write_number;
-    }
+    if (!f.c_contains(inactive))
+      inactive->write_static(f, compress_deimage_);
   }
 }
 
-extern int varused_test, varused;
-
-void Fl_Widget_Type::write_code1() {
+void Fl_Widget_Type::write_code1(Fd_Code_Writer& f) {
   const char* t = subclassname(this);
   const char *c = array_name(this);
   if (c) {
     if (class_name(1)) {
-      write_public(public_);
-      write_h("%s%s *%s;\n", indent(1), t, c);
+      f.write_public(public_);
+      f.write_h("%s%s *%s;\n", f.indent(1), t, c);
     }
   }
   if (class_name(1) && callback() && !is_name(callback())) {
-    const char* cn = callback_name();
+    const char* cn = callback_name(f);
     const char* ut = user_data_type() ? user_data_type() : "void*";
-    write_public(0);
-    write_h("%sinline void %s_i(%s*, %s);\n", indent(1), cn, t, ut);
-    write_h("%sstatic void %s(%s*, %s);\n", indent(1), cn, t, ut);
+    f.write_public(0);
+    f.write_h("%sinline void %s_i(%s*, %s);\n", f.indent(1), cn, t, ut);
+    f.write_h("%sstatic void %s(%s*, %s);\n", f.indent(1), cn, t, ut);
   }
   // figure out if local variable will be used (prevent compiler warnings):
   int wused = !name() && is_window();
   const char *ptr;
 
-  varused = wused;
+  f.varused = wused;
 
-  if (!name() && !varused) {
-    varused |= is_parent();
+  if (!name() && !f.varused) {
+    f.varused |= is_parent();
 
-    if (!varused) {
-      varused_test = 1;
-      write_widget_code();
-      varused_test = 0;
+    if (!f.varused) {
+      f.varused_test = 1;
+      write_widget_code(f);
+      f.varused_test = 0;
     }
   }
 
-  if (!varused) {
+  if (!f.varused) {
     for (int n=0; n < NUM_EXTRA_CODE; n++)
       if (extra_code(n) && !isdeclare(extra_code(n)))
       {
         int instring = 0;
         int inname = 0;
+        int incomment = 0;
+        int incppcomment = 0;
         for (ptr = extra_code(n); *ptr; ptr ++) {
           if (instring) {
             if (*ptr == '\\') ptr++;
             else if (*ptr == '\"') instring = 0;
-          } else if (inname && !isalnum(*ptr & 255)) inname = 0;
-          else if (*ptr == '\"') instring = 1;
-          else if (isalnum(*ptr & 255) || *ptr == '_') {
+          } else if (inname && !isalnum(*ptr & 255)) {
+            inname = 0;
+          } else if (*ptr == '/' && ptr[1]=='*') {
+            incomment = 1; ptr++;
+          } else if (incomment) {
+            if (*ptr == '*' && ptr[1]=='/') {
+              incomment = 0; ptr++;
+            }
+          } else if (*ptr == '/' && ptr[1]=='/') {
+            incppcomment = 1; ptr++;
+          } else if (incppcomment) {
+            if (*ptr == '\n')
+              incppcomment = 0;
+          } else if (*ptr == '\"') {
+            instring = 1;
+          } else if (isalnum(*ptr & 255) || *ptr == '_') {
             size_t len = strspn(ptr, "0123456789_"
                                      "abcdefghijklmnopqrstuvwxyz"
                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-
             if (!strncmp(ptr, "o", len)) {
-              varused = 1;
+              f.varused = 1;
               break;
-            } else ptr += len - 1;
+            } else {
+              ptr += len - 1;
+            }
           }
         }
       }
   }
 
-  write_c("%s{ ", indent());
-  write_comment_inline_c();
-  if (varused) write_c("%s* o = ", t);
-  if (name()) write_c("%s = ", name());
+  f.write_c("%s{ ", f.indent());
+  write_comment_inline_c(f);
+  if (f.varused) f.write_c("%s* o = ", t);
+  if (name()) f.write_c("%s = ", name());
   if (is_window()) {
     // Handle special case where user is faking a Fl_Group type as a window,
     // there is no 2-argument constructor in that case:
     if (!strstr(t, "Window"))
-      write_c("new %s(0, 0, %d, %d", t, o->w(), o->h());
+      f.write_c("new %s(0, 0, %d, %d", t, o->w(), o->h());
     else
-      write_c("new %s(%d, %d", t, o->w(), o->h());
+      f.write_c("new %s(%d, %d", t, o->w(), o->h());
   } else {
-    write_c("new %s(%d, %d, %d, %d", t, o->x(), o->y(), o->w(), o->h());
+    f.write_c("new %s(%d, %d, %d, %d", t, o->x(), o->y(), o->w(), o->h());
   }
   if (label() && *label()) {
-    write_c(", ");
+    f.write_c(", ");
     switch (g_project.i18n_type) {
     case 0 : /* None */
-        write_cstring(label());
+        f.write_cstring(label());
         break;
     case 1 : /* GNU gettext */
-        write_c("%s(", g_project.i18n_function.value());
-        write_cstring(label());
-        write_c(")");
+        f.write_c("%s(", g_project.i18n_function.value());
+        f.write_cstring(label());
+        f.write_c(")");
         break;
     case 2 : /* POSIX catgets */
-        write_c("catgets(%s,%s,%d,", g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
+        f.write_c("catgets(%s,%s,%d,", g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
                 g_project.i18n_set.value(), msgnum());
-        write_cstring(label());
-        write_c(")");
+        f.write_cstring(label());
+        f.write_c(")");
         break;
     }
   }
-  write_c(");\n");
+  f.write_c(");\n");
 
-  indentation++;
+  f.indentation++;
 
   // Avoid compiler warning for unused variable.
   // Also avoid quality control warnings about incorrect allocation error handling.
-  if (wused) write_c("%sw = o; (void)w;\n", indent());
+  if (wused) f.write_c("%sw = o; (void)w;\n", f.indent());
 
-  write_widget_code();
+  write_widget_code(f);
 }
 
-void Fl_Widget_Type::write_color(const char* field, Fl_Color color) {
+void Fl_Widget_Type::write_color(Fd_Code_Writer& f, const char* field, Fl_Color color) {
   const char* color_name = 0;
   switch (color) {
   case FL_FOREGROUND_COLOR:     color_name = "FL_FOREGROUND_COLOR";     break;
@@ -2962,44 +2972,44 @@ void Fl_Widget_Type::write_color(const char* field, Fl_Color color) {
   }
   const char *var = is_class() ? "this" : name() ? name() : "o";
   if (color_name) {
-    write_c("%s%s->%s(%s);\n", indent(), var, field, color_name);
+    f.write_c("%s%s->%s(%s);\n", f.indent(), var, field, color_name);
   } else {
-    write_c("%s%s->%s((Fl_Color)%d);\n", indent(), var, field, color);
+    f.write_c("%s%s->%s((Fl_Color)%d);\n", f.indent(), var, field, color);
   }
 }
 
-// this is split from write_code1() for Fl_Window_Type:
-void Fl_Widget_Type::write_widget_code() {
+// this is split from write_code1(Fd_Code_Writer& f) for Fl_Window_Type:
+void Fl_Widget_Type::write_widget_code(Fd_Code_Writer& f) {
   Fl_Widget* tplate = ((Fl_Widget_Type*)factory)->o;
   const char *var = is_class() ? "this" : name() ? name() : "o";
 
   if (tooltip() && *tooltip()) {
-    write_c("%s%s->tooltip(",indent(), var);
+    f.write_c("%s%s->tooltip(",f.indent(), var);
     switch (g_project.i18n_type) {
     case 0 : /* None */
-        write_cstring(tooltip());
+        f.write_cstring(tooltip());
         break;
     case 1 : /* GNU gettext */
-        write_c("%s(", g_project.i18n_function.value());
-        write_cstring(tooltip());
-        write_c(")");
+        f.write_c("%s(", g_project.i18n_function.value());
+        f.write_cstring(tooltip());
+        f.write_c(")");
         break;
     case 2 : /* POSIX catgets */
-        write_c("catgets(%s,%s,%d,", g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
+        f.write_c("catgets(%s,%s,%d,", g_project.i18n_file[0] ? g_project.i18n_file.value() : "_catalog",
                 g_project.i18n_set.value(), msgnum() + 1);
-        write_cstring(tooltip());
-        write_c(")");
+        f.write_cstring(tooltip());
+        f.write_c(")");
         break;
     }
-    write_c(");\n");
+    f.write_c(");\n");
   }
 
   if (is_spinner() && ((Fl_Spinner*)o)->type() != ((Fl_Spinner*)tplate)->type())
-    write_c("%s%s->type(%d);\n", indent(), var, ((Fl_Spinner*)o)->type());
+    f.write_c("%s%s->type(%d);\n", f.indent(), var, ((Fl_Spinner*)o)->type());
   else if (o->type() != tplate->type() && !is_window())
-    write_c("%s%s->type(%d);\n", indent(), var, o->type());
+    f.write_c("%s%s->type(%d);\n", f.indent(), var, o->type());
   if (o->box() != tplate->box() || subclass())
-    write_c("%s%s->box(FL_%s);\n", indent(), var, boxname(o->box()));
+    f.write_c("%s%s->box(FL_%s);\n", f.indent(), var, boxname(o->box()));
 
   // write shortcut command if needed
   int shortcut = 0;
@@ -3009,284 +3019,284 @@ void Fl_Widget_Type::write_widget_code() {
   else if (is_text_display()) shortcut = ((Fl_Text_Display*)o)->shortcut();
   if (shortcut) {
     if (g_project.use_FL_COMMAND && (shortcut & (FL_CTRL|FL_META))) {
-      write_c("%s%s->shortcut(FL_COMMAND|0x%x);\n", indent(), var, shortcut & ~(FL_CTRL|FL_META));
+      f.write_c("%s%s->shortcut(FL_COMMAND|0x%x);\n", f.indent(), var, shortcut & ~(FL_CTRL|FL_META));
     } else {
-      write_c("%s%s->shortcut(0x%x);\n", indent(), var, shortcut);
+      f.write_c("%s%s->shortcut(0x%x);\n", f.indent(), var, shortcut);
     }
   }
 
   if (is_button()) {
     Fl_Button* b = (Fl_Button*)o;
-    if (b->down_box()) write_c("%s%s->down_box(FL_%s);\n", indent(), var,
+    if (b->down_box()) f.write_c("%s%s->down_box(FL_%s);\n", f.indent(), var,
                                boxname(b->down_box()));
-    if (b->value()) write_c("%s%s->value(1);\n", indent(), var);
+    if (b->value()) f.write_c("%s%s->value(1);\n", f.indent(), var);
   } else if (!strcmp(type_name(), "Fl_Input_Choice")) {
     Fl_Input_Choice* b = (Fl_Input_Choice*)o;
-    if (b->down_box()) write_c("%s%s->down_box(FL_%s);\n", indent(), var,
+    if (b->down_box()) f.write_c("%s%s->down_box(FL_%s);\n", f.indent(), var,
                                boxname(b->down_box()));
   } else if (is_menu_button()) {
     Fl_Menu_* b = (Fl_Menu_*)o;
-    if (b->down_box()) write_c("%s%s->down_box(FL_%s);\n", indent(), var,
+    if (b->down_box()) f.write_c("%s%s->down_box(FL_%s);\n", f.indent(), var,
                                boxname(b->down_box()));
   }
   if (o->color() != tplate->color() || subclass())
-    write_color("color", o->color());
+    write_color(f, "color", o->color());
   if (o->selection_color() != tplate->selection_color() || subclass())
-    write_color("selection_color", o->selection_color());
-  if (image) image->write_code(bind_image_, var);
-  if (inactive) inactive->write_code(bind_deimage_, var, 1);
+    write_color(f, "selection_color", o->selection_color());
+  if (image) image->write_code(f, bind_image_, var);
+  if (inactive) inactive->write_code(f, bind_deimage_, var, 1);
   if (o->labeltype() != tplate->labeltype() || subclass())
-    write_c("%s%s->labeltype(FL_%s);\n", indent(), var,
+    f.write_c("%s%s->labeltype(FL_%s);\n", f.indent(), var,
             item_name(labeltypemenu, o->labeltype()));
   if (o->labelfont() != tplate->labelfont() || subclass())
-    write_c("%s%s->labelfont(%d);\n", indent(), var, o->labelfont());
+    f.write_c("%s%s->labelfont(%d);\n", f.indent(), var, o->labelfont());
   if (o->labelsize() != tplate->labelsize() || subclass())
-    write_c("%s%s->labelsize(%d);\n", indent(), var, o->labelsize());
+    f.write_c("%s%s->labelsize(%d);\n", f.indent(), var, o->labelsize());
   if (o->labelcolor() != tplate->labelcolor() || subclass())
-    write_color("labelcolor", o->labelcolor());
+    write_color(f, "labelcolor", o->labelcolor());
   if (is_valuator()) {
     Fl_Valuator* v = (Fl_Valuator*)o;
-    Fl_Valuator* f = (Fl_Valuator*)(tplate);
-    if (v->minimum()!=f->minimum())
-      write_c("%s%s->minimum(%g);\n", indent(), var, v->minimum());
-    if (v->maximum()!=f->maximum())
-      write_c("%s%s->maximum(%g);\n", indent(), var, v->maximum());
-    if (v->step()!=f->step())
-      write_c("%s%s->step(%g);\n", indent(), var, v->step());
+    Fl_Valuator* t = (Fl_Valuator*)(tplate);
+    if (v->minimum()!=t->minimum())
+      f.write_c("%s%s->minimum(%g);\n", f.indent(), var, v->minimum());
+    if (v->maximum()!=t->maximum())
+      f.write_c("%s%s->maximum(%g);\n", f.indent(), var, v->maximum());
+    if (v->step()!=t->step())
+      f.write_c("%s%s->step(%g);\n", f.indent(), var, v->step());
     if (v->value()) {
       if (is_valuator()==3) { // Fl_Scrollbar::value(double) is nott available
-        write_c("%s%s->Fl_Slider::value(%g);\n", indent(), var, v->value());
+        f.write_c("%s%s->Fl_Slider::value(%g);\n", f.indent(), var, v->value());
       } else {
-        write_c("%s%s->value(%g);\n", indent(), var, v->value());
+        f.write_c("%s%s->value(%g);\n", f.indent(), var, v->value());
       }
     }
     if (is_valuator()>=2) {
       double x = ((Fl_Slider*)v)->slider_size();
-      double y = ((Fl_Slider*)f)->slider_size();
-      if (x != y) write_c("%s%s->slider_size(%g);\n", indent(), var, x);
+      double y = ((Fl_Slider*)t)->slider_size();
+      if (x != y) f.write_c("%s%s->slider_size(%g);\n", f.indent(), var, x);
     }
   }
   if (is_spinner()) {
     Fl_Spinner* v = (Fl_Spinner*)o;
-    Fl_Spinner* f = (Fl_Spinner*)(tplate);
-    if (v->minimum()!=f->minimum())
-      write_c("%s%s->minimum(%g);\n", indent(), var, v->minimum());
-    if (v->maximum()!=f->maximum())
-      write_c("%s%s->maximum(%g);\n", indent(), var, v->maximum());
-    if (v->step()!=f->step())
-      write_c("%s%s->step(%g);\n", indent(), var, v->step());
+    Fl_Spinner* t = (Fl_Spinner*)(tplate);
+    if (v->minimum()!=t->minimum())
+      f.write_c("%s%s->minimum(%g);\n", f.indent(), var, v->minimum());
+    if (v->maximum()!=t->maximum())
+      f.write_c("%s%s->maximum(%g);\n", f.indent(), var, v->maximum());
+    if (v->step()!=t->step())
+      f.write_c("%s%s->step(%g);\n", f.indent(), var, v->step());
     if (v->value()!=1.0f)
-      write_c("%s%s->value(%g);\n", indent(), var, v->value());
+      f.write_c("%s%s->value(%g);\n", f.indent(), var, v->value());
   }
 
   {Fl_Font ff; int fs; Fl_Color fc; if (textstuff(4,ff,fs,fc)) {
-    Fl_Font f; int s; Fl_Color c; textstuff(0,f,s,c);
-    if (f != ff) write_c("%s%s->textfont(%d);\n", indent(), var, f);
-    if (s != fs) write_c("%s%s->textsize(%d);\n", indent(), var, s);
-    if (c != fc) write_color("textcolor", c);
+    Fl_Font g; int s; Fl_Color c; textstuff(0,g,s,c);
+    if (g != ff) f.write_c("%s%s->textfont(%d);\n", f.indent(), var, g);
+    if (s != fs) f.write_c("%s%s->textsize(%d);\n", f.indent(), var, s);
+    if (c != fc) write_color(f, "textcolor", c);
   }}
   const char* ud = user_data();
   if (class_name(1) && !parent->is_widget()) ud = "this";
   if (callback()) {
-    write_c("%s%s->callback((Fl_Callback*)%s", indent(), var, callback_name());
+    f.write_c("%s%s->callback((Fl_Callback*)%s", f.indent(), var, callback_name(f));
     if (ud)
-      write_c(", (void*)(%s));\n", ud);
+      f.write_c(", (void*)(%s));\n", ud);
     else
-      write_c(");\n");
+      f.write_c(");\n");
   } else if (ud) {
-    write_c("%s%s->user_data((void*)(%s));\n", indent(), var, ud);
+    f.write_c("%s%s->user_data((void*)(%s));\n", f.indent(), var, ud);
   }
   if (o->align() != tplate->align() || subclass()) {
     int i = o->align();
-    write_c("%s%s->align(Fl_Align(%s", indent(), var,
+    f.write_c("%s%s->align(Fl_Align(%s", f.indent(), var,
             item_name(alignmenu, i & ~FL_ALIGN_INSIDE));
-    if (i & FL_ALIGN_INSIDE) write_c("|FL_ALIGN_INSIDE");
-    write_c("));\n");
+    if (i & FL_ALIGN_INSIDE) f.write_c("|FL_ALIGN_INSIDE");
+    f.write_c("));\n");
   }
   Fl_When ww = o->when();
   if (ww==FL_WHEN_NOT_CHANGED)
     ww = FL_WHEN_NEVER;
   if (ww != tplate->when() || subclass())
-    write_c("%s%s->when(%s);\n", indent(), var, when_symbol_name(ww));
+    f.write_c("%s%s->when(%s);\n", f.indent(), var, when_symbol_name(ww));
   if (!o->visible() && o->parent())
-    write_c("%s%s->hide();\n", indent(), var);
+    f.write_c("%s%s->hide();\n", f.indent(), var);
   if (!o->active())
-    write_c("%s%s->deactivate();\n", indent(), var);
+    f.write_c("%s%s->deactivate();\n", f.indent(), var);
   if (!is_group() && resizable())
-    write_c("%sFl_Group::current()->resizable(%s);\n", indent(), var);
+    f.write_c("%sFl_Group::current()->resizable(%s);\n", f.indent(), var);
   if (hotspot()) {
     if (is_class())
-      write_c("%shotspot(%s);\n", indent(), var);
+      f.write_c("%shotspot(%s);\n", f.indent(), var);
     else if (is_window())
-      write_c("%s%s->hotspot(%s);\n", indent(), var, var);
+      f.write_c("%s%s->hotspot(%s);\n", f.indent(), var, var);
     else
-      write_c("%s%s->window()->hotspot(%s);\n", indent(), var, var);
+      f.write_c("%s%s->window()->hotspot(%s);\n", f.indent(), var, var);
   }
 }
 
-void Fl_Widget_Type::write_extra_code() {
+void Fl_Widget_Type::write_extra_code(Fd_Code_Writer& f) {
   for (int n=0; n < NUM_EXTRA_CODE; n++)
     if (extra_code(n) && !isdeclare(extra_code(n)))
-      write_c("%s%s\n", indent(), extra_code(n));
+      f.write_c("%s%s\n", f.indent(), extra_code(n));
 }
 
-void Fl_Widget_Type::write_block_close() {
-  indentation--;
-  write_c("%s} // %s* %s\n", indent(), subclassname(this),
+void Fl_Widget_Type::write_block_close(Fd_Code_Writer& f) {
+  f.indentation--;
+  f.write_c("%s} // %s* %s\n", f.indent(), subclassname(this),
           name() ? name() : "o");
 }
 
-void Fl_Widget_Type::write_code2() {
-  write_extra_code();
-  write_block_close();
+void Fl_Widget_Type::write_code2(Fd_Code_Writer& f) {
+  write_extra_code(f);
+  write_block_close(f);
 }
 
 ////////////////////////////////////////////////////////////////
 
-void Fl_Widget_Type::write_properties() {
-  Fl_Type::write_properties();
-  write_indent(level+1);
+void Fl_Widget_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Type::write_properties(f);
+  f.write_indent(level+1);
   switch (public_) {
-    case 0: write_string("private"); break;
+    case 0: f.write_string("private"); break;
     case 1: break;
-    case 2: write_string("protected"); break;
+    case 2: f.write_string("protected"); break;
   }
   if (tooltip() && *tooltip()) {
-    write_string("tooltip");
-    write_word(tooltip());
+    f.write_string("tooltip");
+    f.write_word(tooltip());
   }
   if (image_name() && *image_name()) {
-    write_string("image");
-    write_word(image_name());
-    write_string("compress_image %d", compress_image_);
+    f.write_string("image");
+    f.write_word(image_name());
+    f.write_string("compress_image %d", compress_image_);
   }
-  if (bind_image_) write_string("bind_image 1");
+  if (bind_image_) f.write_string("bind_image 1");
   if (inactive_name() && *inactive_name()) {
-    write_string("deimage");
-    write_word(inactive_name());
-    write_string("compress_deimage %d", compress_deimage_);
+    f.write_string("deimage");
+    f.write_word(inactive_name());
+    f.write_string("compress_deimage %d", compress_deimage_);
   }
-  if (bind_deimage_) write_string("bind_deimage 1");
-  write_string("xywh {%d %d %d %d}", o->x(), o->y(), o->w(), o->h());
+  if (bind_deimage_) f.write_string("bind_deimage 1");
+  f.write_string("xywh {%d %d %d %d}", o->x(), o->y(), o->w(), o->h());
   Fl_Widget* tplate = ((Fl_Widget_Type*)factory)->o;
   if (is_spinner() && ((Fl_Spinner*)o)->type() != ((Fl_Spinner*)tplate)->type()) {
-    write_string("type");
-    write_word(item_name(subtypes(), ((Fl_Spinner*)o)->type()));
+    f.write_string("type");
+    f.write_word(item_name(subtypes(), ((Fl_Spinner*)o)->type()));
   } else if (subtypes() && (o->type() != tplate->type() || is_window())) {
-    write_string("type");
-    write_word(item_name(subtypes(), o->type()));
+    f.write_string("type");
+    f.write_word(item_name(subtypes(), o->type()));
   }
   if (o->box() != tplate->box()) {
-    write_string("box"); write_word(boxname(o->box()));}
+    f.write_string("box"); f.write_word(boxname(o->box()));}
   if (is_input()) {
     Fl_Input_* b = (Fl_Input_*)o;
-    if (b->shortcut()) write_string("shortcut 0x%x", b->shortcut());
+    if (b->shortcut()) f.write_string("shortcut 0x%x", b->shortcut());
   }
   if (is_value_input()) {
     Fl_Value_Input* b = (Fl_Value_Input*)o;
-    if (b->shortcut()) write_string("shortcut 0x%x", b->shortcut());
+    if (b->shortcut()) f.write_string("shortcut 0x%x", b->shortcut());
   }
   if (is_text_display()) {
     Fl_Text_Display* b = (Fl_Text_Display*)o;
-    if (b->shortcut()) write_string("shortcut 0x%x", b->shortcut());
+    if (b->shortcut()) f.write_string("shortcut 0x%x", b->shortcut());
   }
   if (is_button()) {
     Fl_Button* b = (Fl_Button*)o;
     if (b->down_box()) {
-      write_string("down_box"); write_word(boxname(b->down_box()));}
-    if (b->shortcut()) write_string("shortcut 0x%x", b->shortcut());
-    if (b->value()) write_string("value 1");
+      f.write_string("down_box"); f.write_word(boxname(b->down_box()));}
+    if (b->shortcut()) f.write_string("shortcut 0x%x", b->shortcut());
+    if (b->value()) f.write_string("value 1");
   } else if (!strcmp(type_name(), "Fl_Input_Choice")) {
     Fl_Input_Choice* b = (Fl_Input_Choice*)o;
     if (b->down_box()) {
-      write_string("down_box"); write_word(boxname(b->down_box()));}
+      f.write_string("down_box"); f.write_word(boxname(b->down_box()));}
   } else if (is_menu_button()) {
     Fl_Menu_* b = (Fl_Menu_*)o;
     if (b->down_box()) {
-      write_string("down_box"); write_word(boxname(b->down_box()));}
+      f.write_string("down_box"); f.write_word(boxname(b->down_box()));}
   }
   if (o->color()!=tplate->color())
-    write_string("color %d", o->color());
+    f.write_string("color %d", o->color());
   if (o->selection_color()!=tplate->selection_color())
-    write_string("selection_color %d", o->selection_color());
+    f.write_string("selection_color %d", o->selection_color());
   if (o->labeltype()!=tplate->labeltype()) {
-    write_string("labeltype");
-    write_word(item_name(labeltypemenu, o->labeltype()));
+    f.write_string("labeltype");
+    f.write_word(item_name(labeltypemenu, o->labeltype()));
   }
   if (o->labelfont()!=tplate->labelfont())
-    write_string("labelfont %d", o->labelfont());
+    f.write_string("labelfont %d", o->labelfont());
   if (o->labelsize()!=tplate->labelsize())
-    write_string("labelsize %d", o->labelsize());
+    f.write_string("labelsize %d", o->labelsize());
   if (o->labelcolor()!=tplate->labelcolor())
-    write_string("labelcolor %d", o->labelcolor());
+    f.write_string("labelcolor %d", o->labelcolor());
   if (o->align()!=tplate->align())
-    write_string("align %d", o->align());
+    f.write_string("align %d", o->align());
   if (o->when() != tplate->when())
-    write_string("when %d", o->when());
+    f.write_string("when %d", o->when());
   if (is_valuator()) {
     Fl_Valuator* v = (Fl_Valuator*)o;
-    Fl_Valuator* f = (Fl_Valuator*)(tplate);
-    if (v->minimum()!=f->minimum()) write_string("minimum %g",v->minimum());
-    if (v->maximum()!=f->maximum()) write_string("maximum %g",v->maximum());
-    if (v->step()!=f->step()) write_string("step %g",v->step());
-    if (v->value()!=0.0) write_string("value %g",v->value());
+    Fl_Valuator* t = (Fl_Valuator*)(tplate);
+    if (v->minimum()!=t->minimum()) f.write_string("minimum %g",v->minimum());
+    if (v->maximum()!=t->maximum()) f.write_string("maximum %g",v->maximum());
+    if (v->step()!=t->step()) f.write_string("step %g",v->step());
+    if (v->value()!=0.0) f.write_string("value %g",v->value());
     if (is_valuator()>=2) {
       double x = ((Fl_Slider*)v)->slider_size();
-      double y = ((Fl_Slider*)f)->slider_size();
-      if (x != y) write_string("slider_size %g", x);
+      double y = ((Fl_Slider*)t)->slider_size();
+      if (x != y) f.write_string("slider_size %g", x);
     }
   }
   if (is_spinner()) {
     Fl_Spinner* v = (Fl_Spinner*)o;
-    Fl_Spinner* f = (Fl_Spinner*)(tplate);
-    if (v->minimum()!=f->minimum()) write_string("minimum %g",v->minimum());
-    if (v->maximum()!=f->maximum()) write_string("maximum %g",v->maximum());
-    if (v->step()!=f->step()) write_string("step %g",v->step());
-    if (v->value()!=1.0) write_string("value %g",v->value());
+    Fl_Spinner* t = (Fl_Spinner*)(tplate);
+    if (v->minimum()!=t->minimum()) f.write_string("minimum %g",v->minimum());
+    if (v->maximum()!=t->maximum()) f.write_string("maximum %g",v->maximum());
+    if (v->step()!=t->step()) f.write_string("step %g",v->step());
+    if (v->value()!=1.0) f.write_string("value %g",v->value());
   }
   {Fl_Font ff; int fs; Fl_Color fc; if (textstuff(4,ff,fs,fc)) {
-    Fl_Font f; int s; Fl_Color c; textstuff(0,f,s,c);
-    if (f != ff) write_string("textfont %d", f);
-    if (s != fs) write_string("textsize %d", s);
-    if (c != fc) write_string("textcolor %d", c);
+    Fl_Font ft; int s; Fl_Color c; textstuff(0,ft,s,c);
+    if (ft != ff) f.write_string("textfont %d", ft);
+    if (s != fs) f.write_string("textsize %d", s);
+    if (c != fc) f.write_string("textcolor %d", c);
   }}
-  if (!o->visible()) write_string("hide");
-  if (!o->active()) write_string("deactivate");
-  if (resizable()) write_string("resizable");
-  if (hotspot()) write_string(is_menu_item() ? "divider" : "hotspot");
+  if (!o->visible()) f.write_string("hide");
+  if (!o->active()) f.write_string("deactivate");
+  if (resizable()) f.write_string("resizable");
+  if (hotspot()) f.write_string(is_menu_item() ? "divider" : "hotspot");
   for (int n=0; n < NUM_EXTRA_CODE; n++) if (extra_code(n)) {
-    write_indent(level+1);
-    write_string("code%d",n);
-    write_word(extra_code(n));
+    f.write_indent(level+1);
+    f.write_string("code%d",n);
+    f.write_word(extra_code(n));
   }
   if (subclass()) {
-    write_indent(level+1);
-    write_string("class");
-    write_word(subclass());
+    f.write_indent(level+1);
+    f.write_string("class");
+    f.write_word(subclass());
   }
 }
 
-void Fl_Widget_Type::read_property(const char *c) {
-  int x,y,w,h; Fl_Font f; int s; Fl_Color cc;
+void Fl_Widget_Type::read_property(Fd_Project_Reader &f, const char *c) {
+  int x,y,w,h; Fl_Font ft; int s; Fl_Color cc;
   if (!strcmp(c,"private")) {
     public_ = 0;
   } else if (!strcmp(c,"protected")) {
     public_ = 2;
   } else if (!strcmp(c,"xywh")) {
-    if (sscanf(read_word(),"%d %d %d %d",&x,&y,&w,&h) == 4) {
+    if (sscanf(f.read_word(),"%d %d %d %d",&x,&y,&w,&h) == 4) {
       x += pasteoffset;
       y += pasteoffset;
       // FIXME temporary change!
-      if (read_version>=2.0 && o->parent() && o->parent()!=o->window()) {
+      if (f.read_version>=2.0 && o->parent() && o->parent()!=o->window()) {
         x += o->parent()->x();
         y += o->parent()->y();
       }
       o->resize(x,y,w,h);
     }
   } else if (!strcmp(c,"tooltip")) {
-    tooltip(read_word());
+    tooltip(f.read_word());
   } else if (!strcmp(c,"image")) {
-    image_name(read_word());
+    image_name(f.read_word());
     // starting in 2023, `image` is always followed by `compress_image`
     // the code below is for compatibility with older .fl files
     const char *ext = fl_filename_ext(image_name_);
@@ -3295,11 +3305,11 @@ void Fl_Widget_Type::read_property(const char *c) {
         && strcmp(ext, ".svgz"))
       compress_image_ = 0; // if it is neither of those, default to uncompressed
   } else if (!strcmp(c,"bind_image")) {
-    bind_image_ = (int)atol(read_word());
+    bind_image_ = (int)atol(f.read_word());
   } else if (!strcmp(c,"compress_image")) {
-    compress_image_ = (int)atol(read_word());
+    compress_image_ = (int)atol(f.read_word());
   } else if (!strcmp(c,"deimage")) {
-    inactive_name(read_word());
+    inactive_name(f.read_word());
     // starting in 2023, `deimage` is always followed by `compress_deimage`
     // the code below is for compatibility with older .fl files
     const char *ext = fl_filename_ext(inactive_name_);
@@ -3308,43 +3318,43 @@ void Fl_Widget_Type::read_property(const char *c) {
         && strcmp(ext, ".svgz"))
       compress_deimage_ = 0; // if it is neither of those, default to uncompressed
   } else if (!strcmp(c,"bind_deimage")) {
-    bind_deimage_ = (int)atol(read_word());
+    bind_deimage_ = (int)atol(f.read_word());
   } else if (!strcmp(c,"compress_deimage")) {
-    compress_deimage_ = (int)atol(read_word());
+    compress_deimage_ = (int)atol(f.read_word());
   } else if (!strcmp(c,"type")) {
     if (is_spinner())
-      ((Fl_Spinner*)o)->type(item_number(subtypes(), read_word()));
+      ((Fl_Spinner*)o)->type(item_number(subtypes(), f.read_word()));
     else
-      o->type(item_number(subtypes(), read_word()));
+      o->type(item_number(subtypes(), f.read_word()));
   } else if (!strcmp(c,"box")) {
-    const char* value = read_word();
+    const char* value = f.read_word();
     if ((x = boxnumber(value))) {
       if (x == ZERO_ENTRY) x = 0;
       o->box((Fl_Boxtype)x);
     } else if (sscanf(value,"%d",&x) == 1) o->box((Fl_Boxtype)x);
   } else if (is_button() && !strcmp(c,"down_box")) {
-    const char* value = read_word();
+    const char* value = f.read_word();
     if ((x = boxnumber(value))) {
       if (x == ZERO_ENTRY) x = 0;
       ((Fl_Button*)o)->down_box((Fl_Boxtype)x);
     }
   } else if (!strcmp(type_name(), "Fl_Input_Choice") && !strcmp(c,"down_box")) {
-    const char* value = read_word();
+    const char* value = f.read_word();
     if ((x = boxnumber(value))) {
       if (x == ZERO_ENTRY) x = 0;
       ((Fl_Input_Choice*)o)->down_box((Fl_Boxtype)x);
     }
   } else if (is_menu_button() && !strcmp(c,"down_box")) {
-    const char* value = read_word();
+    const char* value = f.read_word();
     if ((x = boxnumber(value))) {
       if (x == ZERO_ENTRY) x = 0;
       ((Fl_Menu_*)o)->down_box((Fl_Boxtype)x);
     }
   } else if (is_button() && !strcmp(c,"value")) {
-    const char* value = read_word();
+    const char* value = f.read_word();
     ((Fl_Button*)o)->value(atoi(value));
   } else if (!strcmp(c,"color")) {
-    const char *cw = read_word();
+    const char *cw = f.read_word();
     if (cw[0]=='0' && cw[1]=='x') {
       sscanf(cw,"0x%x",&x);
       o->color(x);
@@ -3358,12 +3368,12 @@ void Fl_Widget_Type::read_property(const char *c) {
       }
     }
   } else if (!strcmp(c,"selection_color")) {
-    if (sscanf(read_word(),"%d",&x)) o->selection_color(x);
+    if (sscanf(f.read_word(),"%d",&x)) o->selection_color(x);
   } else if (!strcmp(c,"labeltype")) {
-    c = read_word();
+    c = f.read_word();
     if (!strcmp(c,"image")) {
       Fluid_Image *i = Fluid_Image::find(label());
-      if (!i) read_error("Image file '%s' not found", label());
+      if (!i) f.read_error("Image file '%s' not found", label());
       else setimage(i);
       image_name(label());
       label("");
@@ -3371,35 +3381,35 @@ void Fl_Widget_Type::read_property(const char *c) {
       o->labeltype((Fl_Labeltype)item_number(labeltypemenu,c));
     }
   } else if (!strcmp(c,"labelfont")) {
-    if (sscanf(read_word(),"%d",&x) == 1) o->labelfont(x);
+    if (sscanf(f.read_word(),"%d",&x) == 1) o->labelfont(x);
   } else if (!strcmp(c,"labelsize")) {
-    if (sscanf(read_word(),"%d",&x) == 1) o->labelsize(x);
+    if (sscanf(f.read_word(),"%d",&x) == 1) o->labelsize(x);
   } else if (!strcmp(c,"labelcolor")) {
-    if (sscanf(read_word(),"%d",&x) == 1) o->labelcolor(x);
+    if (sscanf(f.read_word(),"%d",&x) == 1) o->labelcolor(x);
   } else if (!strcmp(c,"align")) {
-    if (sscanf(read_word(),"%d",&x) == 1) o->align(x);
+    if (sscanf(f.read_word(),"%d",&x) == 1) o->align(x);
   } else if (!strcmp(c,"when")) {
-    if (sscanf(read_word(),"%d",&x) == 1) o->when(x);
+    if (sscanf(f.read_word(),"%d",&x) == 1) o->when(x);
   } else if (!strcmp(c,"minimum")) {
-    if (is_valuator()) ((Fl_Valuator*)o)->minimum(strtod(read_word(),0));
-    if (is_spinner()) ((Fl_Spinner*)o)->minimum(strtod(read_word(),0));
+    if (is_valuator()) ((Fl_Valuator*)o)->minimum(strtod(f.read_word(),0));
+    if (is_spinner()) ((Fl_Spinner*)o)->minimum(strtod(f.read_word(),0));
   } else if (!strcmp(c,"maximum")) {
-    if (is_valuator()) ((Fl_Valuator*)o)->maximum(strtod(read_word(),0));
-    if (is_spinner()) ((Fl_Spinner*)o)->maximum(strtod(read_word(),0));
+    if (is_valuator()) ((Fl_Valuator*)o)->maximum(strtod(f.read_word(),0));
+    if (is_spinner()) ((Fl_Spinner*)o)->maximum(strtod(f.read_word(),0));
   } else if (!strcmp(c,"step")) {
-    if (is_valuator()) ((Fl_Valuator*)o)->step(strtod(read_word(),0));
-    if (is_spinner()) ((Fl_Spinner*)o)->step(strtod(read_word(),0));
+    if (is_valuator()) ((Fl_Valuator*)o)->step(strtod(f.read_word(),0));
+    if (is_spinner()) ((Fl_Spinner*)o)->step(strtod(f.read_word(),0));
   } else if (!strcmp(c,"value")) {
-    if (is_valuator()) ((Fl_Valuator*)o)->value(strtod(read_word(),0));
-    if (is_spinner()) ((Fl_Spinner*)o)->value(strtod(read_word(),0));
+    if (is_valuator()) ((Fl_Valuator*)o)->value(strtod(f.read_word(),0));
+    if (is_spinner()) ((Fl_Spinner*)o)->value(strtod(f.read_word(),0));
   } else if ((!strcmp(c,"slider_size")||!strcmp(c,"size"))&&is_valuator()==2) {
-    ((Fl_Slider*)o)->slider_size(strtod(read_word(),0));
+    ((Fl_Slider*)o)->slider_size(strtod(f.read_word(),0));
   } else if (!strcmp(c,"textfont")) {
-    if (sscanf(read_word(),"%d",&x) == 1) {f=(Fl_Font)x; textstuff(1,f,s,cc);}
+    if (sscanf(f.read_word(),"%d",&x) == 1) {ft=(Fl_Font)x; textstuff(1,ft,s,cc);}
   } else if (!strcmp(c,"textsize")) {
-    if (sscanf(read_word(),"%d",&x) == 1) {s=x; textstuff(2,f,s,cc);}
+    if (sscanf(f.read_word(),"%d",&x) == 1) {s=x; textstuff(2,ft,s,cc);}
   } else if (!strcmp(c,"textcolor")) {
-    if (sscanf(read_word(),"%d",&x) == 1) {cc=(Fl_Color)x;textstuff(3,f,s,cc);}
+    if (sscanf(f.read_word(),"%d",&x) == 1) {cc=(Fl_Color)x;textstuff(3,ft,s,cc);}
   } else if (!strcmp(c,"hide")) {
     o->hide();
   } else if (!strcmp(c,"deactivate")) {
@@ -3409,9 +3419,9 @@ void Fl_Widget_Type::read_property(const char *c) {
   } else if (!strcmp(c,"hotspot") || !strcmp(c, "divider")) {
     hotspot(1);
   } else if (!strcmp(c,"class")) {
-    subclass(read_word());
+    subclass(f.read_word());
   } else if (!strcmp(c,"shortcut")) {
-    int shortcut = (int)strtol(read_word(),0,0);
+    int shortcut = (int)strtol(f.read_word(),0,0);
     if (is_button()) ((Fl_Button*)o)->shortcut(shortcut);
     else if (is_input()) ((Fl_Input_*)o)->shortcut(shortcut);
     else if (is_value_input()) ((Fl_Value_Input*)o)->shortcut(shortcut);
@@ -3420,14 +3430,14 @@ void Fl_Widget_Type::read_property(const char *c) {
     if (!strncmp(c,"code",4)) {
       int n = atoi(c+4);
       if (n >= 0 && n <= NUM_EXTRA_CODE) {
-        extra_code(n,read_word());
+        extra_code(n,f.read_word());
         return;
       }
     } else if (!strcmp(c,"extra_code")) {
-      extra_code(0,read_word());
+      extra_code(0,f.read_word());
       return;
     }
-    Fl_Type::read_property(c);
+    Fl_Type::read_property(f, c);
   }
 }
 
diff --git fluid/Fl_Widget_Type.h fluid/Fl_Widget_Type.h
index 23d4ae2..a7bc0f7 100644
--- fluid/Fl_Widget_Type.h
+++ fluid/Fl_Widget_Type.h
@@ -51,13 +51,13 @@ class Fl_Widget_Type : public Fl_Type {
 
 protected:
 
-  void write_static() FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_widget_code();
-  void write_extra_code();
-  void write_block_close();
-  void write_code2() FL_OVERRIDE;
-  void write_color(const char*, Fl_Color);
+  void write_static(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_widget_code(Fd_Code_Writer& f);
+  void write_extra_code(Fd_Code_Writer& f);
+  void write_block_close(Fd_Code_Writer& f);
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_color(Fd_Code_Writer& f, const char*, Fl_Color);
   Fl_Widget *live_widget;
 
 public:
@@ -101,8 +101,8 @@ public:
   int is_widget() const FL_OVERRIDE;
   int is_public() const FL_OVERRIDE;
 
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int read_fdesign(const char*, const char*) FL_OVERRIDE;
 
   Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE;
diff --git fluid/Fl_Window_Type.cxx fluid/Fl_Window_Type.cxx
index 3aa4bce..90a5732 100644
--- fluid/Fl_Window_Type.cxx
+++ fluid/Fl_Window_Type.cxx
@@ -941,7 +941,7 @@ void Fl_Window_Type::draw_overlay() {
     }
 
     // Check spacing and alignment between individual widgets
-    if (drag && selection->is_widget()) {
+    if (drag && selection && selection->is_widget()) {
       for (Fl_Type *q=next; q && q->level>level; q = q->next)
         if (q != selection && q->is_widget()) {
           Fl_Widget_Type *qw = (Fl_Widget_Type*)q;
@@ -1354,7 +1354,7 @@ int Fl_Window_Type::handle(int event) {
       // or in the same group, add after selection. Otherwise, just add
       // at the end of the selected group.
       if (   Fl_Type::current_dnd->group()
-          && selection->group()
+          && selection && selection->group()
           && Fl_Type::current_dnd->group()==selection->group())
       {
         Fl_Type *cc = Fl_Type::current;
@@ -1460,7 +1460,7 @@ int Fl_Window_Type::handle(int event) {
         for (Fl_Widget *o1 = myo->o; o1; o1 = o1->parent())
           if (!o1->visible()) goto CONTINUE;
         if (Fl::event_inside(myo->o)) selection = myo;
-        if (myo->o->x()>=x1 && myo->o->y()>y1 &&
+        if (myo && myo->o && myo->o->x()>=x1 && myo->o->y()>y1 &&
             myo->o->x()+myo->o->w()<mx && myo->o->y()+myo->o->h()<my) {
           n++;
           select(myo, toggle ? !myo->selected : 1);
@@ -1468,7 +1468,7 @@ int Fl_Window_Type::handle(int event) {
       CONTINUE:;
       }
       // if nothing in box, select what was clicked on:
-      if (!n) {
+      if (selection && !n) {
         select(selection, toggle ? !selection->selected : 1);
       }
     }
@@ -1538,47 +1538,47 @@ int Fl_Window_Type::handle(int event) {
 
 ////////////////////////////////////////////////////////////////
 
-void Fl_Window_Type::write_code1() {
-  Fl_Widget_Type::write_code1();
+void Fl_Window_Type::write_code1(Fd_Code_Writer& f) {
+  Fl_Widget_Type::write_code1(f);
 }
 
-void Fl_Window_Type::write_code2() {
+void Fl_Window_Type::write_code2(Fd_Code_Writer& f) {
   const char *var = is_class() ? "this" : name() ? name() : "o";
-  write_extra_code();
-  if (modal) write_c("%s%s->set_modal();\n", indent(), var);
-  else if (non_modal) write_c("%s%s->set_non_modal();\n", indent(), var);
+  write_extra_code(f);
+  if (modal) f.write_c("%s%s->set_modal();\n", f.indent(), var);
+  else if (non_modal) f.write_c("%s%s->set_non_modal();\n", f.indent(), var);
   if (!((Fl_Window*)o)->border()) {
-    write_c("%s%s->clear_border();\n", indent(), var);
+    f.write_c("%s%s->clear_border();\n", f.indent(), var);
   }
   if (xclass) {
-    write_c("%s%s->xclass(", indent(), var);
-    write_cstring(xclass);
-    write_c(");\n");
+    f.write_c("%s%s->xclass(", f.indent(), var);
+    f.write_cstring(xclass);
+    f.write_c(");\n");
   }
   if (sr_max_w || sr_max_h) {
-    write_c("%s%s->size_range(%d, %d, %d, %d);\n", indent(), var,
+    f.write_c("%s%s->size_range(%d, %d, %d, %d);\n", f.indent(), var,
             sr_min_w, sr_min_h, sr_max_w, sr_max_h);
   } else if (sr_min_w || sr_min_h) {
-    write_c("%s%s->size_range(%d, %d);\n", indent(), var, sr_min_w, sr_min_h);
+    f.write_c("%s%s->size_range(%d, %d);\n", f.indent(), var, sr_min_w, sr_min_h);
   }
-  write_c("%s%s->end();\n", indent(), var);
+  f.write_c("%s%s->end();\n", f.indent(), var);
   if (((Fl_Window*)o)->resizable() == o)
-    write_c("%s%s->resizable(%s);\n", indent(), var, var);
-  write_block_close();
+    f.write_c("%s%s->resizable(%s);\n", f.indent(), var, var);
+  write_block_close(f);
 }
 
-void Fl_Window_Type::write_properties() {
-  Fl_Widget_Type::write_properties();
-  if (modal) write_string("modal");
-  else if (non_modal) write_string("non_modal");
-  if (!((Fl_Window*)o)->border()) write_string("noborder");
-  if (xclass) {write_string("xclass"); write_word(xclass);}
+void Fl_Window_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Widget_Type::write_properties(f);
+  if (modal) f.write_string("modal");
+  else if (non_modal) f.write_string("non_modal");
+  if (!((Fl_Window*)o)->border()) f.write_string("noborder");
+  if (xclass) {f.write_string("xclass"); f.write_word(xclass);}
   if (sr_min_w || sr_min_h || sr_max_w || sr_max_h)
-    write_string("size_range {%d %d %d %d}", sr_min_w, sr_min_h, sr_max_w, sr_max_h);
-  if (o->visible()) write_string("visible");
+    f.write_string("size_range {%d %d %d %d}", sr_min_w, sr_min_h, sr_max_w, sr_max_h);
+  if (o->visible()) f.write_string("visible");
 }
 
-void Fl_Window_Type::read_property(const char *c) {
+void Fl_Window_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"modal")) {
     modal = 1;
   } else if (!strcmp(c,"non_modal")) {
@@ -1588,18 +1588,18 @@ void Fl_Window_Type::read_property(const char *c) {
   } else if (!strcmp(c,"noborder")) {
     ((Fl_Window*)o)->border(0);
   } else if (!strcmp(c,"xclass")) {
-    storestring(read_word(),xclass);
+    storestring(f.read_word(),xclass);
     ((Fl_Window*)o)->xclass(xclass);
   } else if (!strcmp(c,"size_range")) {
     int mw, mh, MW, MH;
-    if (sscanf(read_word(),"%d %d %d %d",&mw,&mh,&MW,&MH) == 4) {
+    if (sscanf(f.read_word(),"%d %d %d %d",&mw,&mh,&MW,&MH) == 4) {
       sr_min_w = mw; sr_min_h = mh; sr_max_w = MW; sr_max_h = MH;
     }
   } else if (!strcmp(c,"xywh")) {
-    Fl_Widget_Type::read_property(c);
+    Fl_Widget_Type::read_property(f, c);
     pasteoffset = 0; // make it not apply to contents
   } else {
-    Fl_Widget_Type::read_property(c);
+    Fl_Widget_Type::read_property(f, c);
   }
 }
 
@@ -1659,21 +1659,21 @@ Fl_Type *Fl_Widget_Class_Type::make(Strategy strategy) {
   return myo;
 }
 
-void Fl_Widget_Class_Type::write_properties() {
-  Fl_Window_Type::write_properties();
+void Fl_Widget_Class_Type::write_properties(Fd_Project_Writer &f) {
+  Fl_Window_Type::write_properties(f);
   if (wc_relative==1)
-    write_string("position_relative");
+    f.write_string("position_relative");
   else if (wc_relative==2)
-    write_string("position_relative_rescale");
+    f.write_string("position_relative_rescale");
 }
 
-void Fl_Widget_Class_Type::read_property(const char *c) {
+void Fl_Widget_Class_Type::read_property(Fd_Project_Reader &f, const char *c) {
   if (!strcmp(c,"position_relative")) {
     wc_relative = 1;
   } else if (!strcmp(c,"position_relative_rescale")) {
       wc_relative = 2;
   } else {
-    Fl_Window_Type::read_property(c);
+    Fl_Window_Type::read_property(f, c);
   }
 }
 
@@ -1690,9 +1690,9 @@ static const char *trimclassname(const char *n) {
 }
 
 
-void Fl_Widget_Class_Type::write_code1() {
+void Fl_Widget_Class_Type::write_code1(Fd_Code_Writer& f) {
 #if 0
-  Fl_Widget_Type::write_code1();
+  Fl_Widget_Type::write_code1(Fd_Code_Writer& f);
 #endif // 0
 
   current_widget_class = this;
@@ -1701,80 +1701,80 @@ void Fl_Widget_Class_Type::write_code1() {
   const char *c = subclass();
   if (!c) c = "Fl_Group";
 
-  write_c("\n");
-  write_comment_h();
-  write_h("\nclass %s : public %s {\n", name(), c);
+  f.write_c("\n");
+  write_comment_h(f);
+  f.write_h("\nclass %s : public %s {\n", name(), c);
   if (strstr(c, "Window")) {
-    write_h("%svoid _%s();\n", indent(1), trimclassname(name()));
-    write_h("public:\n");
-    write_h("%s%s(int X, int Y, int W, int H, const char *L = 0);\n", indent(1), trimclassname(name()));
-    write_h("%s%s(int W, int H, const char *L = 0);\n", indent(1), trimclassname(name()));
-    write_h("%s%s();\n", indent(1), trimclassname(name()));
+    f.write_h("%svoid _%s();\n", f.indent(1), trimclassname(name()));
+    f.write_h("public:\n");
+    f.write_h("%s%s(int X, int Y, int W, int H, const char *L = 0);\n", f.indent(1), trimclassname(name()));
+    f.write_h("%s%s(int W, int H, const char *L = 0);\n", f.indent(1), trimclassname(name()));
+    f.write_h("%s%s();\n", f.indent(1), trimclassname(name()));
 
     // a constructor with all four dimensions plus label
-    write_c("%s::%s(int X, int Y, int W, int H, const char *L) :\n", name(), trimclassname(name()));
-    write_c("%s%s(X, Y, W, H, L)\n{\n", indent(1), c);
-    write_c("%s_%s();\n", indent(1), trimclassname(name()));
-    write_c("}\n\n");
+    f.write_c("%s::%s(int X, int Y, int W, int H, const char *L) :\n", name(), trimclassname(name()));
+    f.write_c("%s%s(X, Y, W, H, L)\n{\n", f.indent(1), c);
+    f.write_c("%s_%s();\n", f.indent(1), trimclassname(name()));
+    f.write_c("}\n\n");
 
     // a constructor with just the size and label. The window manager will position the window
-    write_c("%s::%s(int W, int H, const char *L) :\n", name(), trimclassname(name()));
-    write_c("%s%s(0, 0, W, H, L)\n{\n", indent(1), c);
-    write_c("%sclear_flag(16);\n", indent(1));
-    write_c("%s_%s();\n", indent(1), trimclassname(name()));
-    write_c("}\n\n");
+    f.write_c("%s::%s(int W, int H, const char *L) :\n", name(), trimclassname(name()));
+    f.write_c("%s%s(0, 0, W, H, L)\n{\n", f.indent(1), c);
+    f.write_c("%sclear_flag(16);\n", f.indent(1));
+    f.write_c("%s_%s();\n", f.indent(1), trimclassname(name()));
+    f.write_c("}\n\n");
 
     // a constructor that takes size and label from the Fluid database
-    write_c("%s::%s() :\n", name(), trimclassname(name()));
-    write_c("%s%s(0, 0, %d, %d, ", indent(1), c, o->w(), o->h());
+    f.write_c("%s::%s() :\n", name(), trimclassname(name()));
+    f.write_c("%s%s(0, 0, %d, %d, ", f.indent(1), c, o->w(), o->h());
     const char *cstr = label();
-    if (cstr) write_cstring(cstr);
-    else write_c("0");
-    write_c(")\n{\n");
-    write_c("%sclear_flag(16);\n", indent(1));
-    write_c("%s_%s();\n", indent(1), trimclassname(name()));
-    write_c("}\n\n");
-
-    write_c("void %s::_%s() {\n", name(), trimclassname(name()));
-//    write_c("%s%s *w = this;\n", indent(1), name());
+    if (cstr) f.write_cstring(cstr);
+    else f.write_c("0");
+    f.write_c(")\n{\n");
+    f.write_c("%sclear_flag(16);\n", f.indent(1));
+    f.write_c("%s_%s();\n", f.indent(1), trimclassname(name()));
+    f.write_c("}\n\n");
+
+    f.write_c("void %s::_%s() {\n", name(), trimclassname(name()));
+//    f.write_c("%s%s *w = this;\n", f.indent(1), name());
   } else {
-    write_h("public:\n");
-    write_h("%s%s(int X, int Y, int W, int H, const char *L = 0);\n",
-            indent(1), trimclassname(name()));
-    write_c("%s::%s(int X, int Y, int W, int H, const char *L) :\n", name(), trimclassname(name()));
+    f.write_h("public:\n");
+    f.write_h("%s%s(int X, int Y, int W, int H, const char *L = 0);\n",
+            f.indent(1), trimclassname(name()));
+    f.write_c("%s::%s(int X, int Y, int W, int H, const char *L) :\n", name(), trimclassname(name()));
     if (wc_relative==1)
-      write_c("%s%s(0, 0, W, H, L)\n{\n", indent(1), c);
+      f.write_c("%s%s(0, 0, W, H, L)\n{\n", f.indent(1), c);
     else if (wc_relative==2)
-      write_c("%s%s(0, 0, %d, %d, L)\n{\n", indent(1), c, o->w(), o->h());
+      f.write_c("%s%s(0, 0, %d, %d, L)\n{\n", f.indent(1), c, o->w(), o->h());
     else
-      write_c("%s%s(X, Y, W, H, L)\n{\n", indent(1), c);
+      f.write_c("%s%s(X, Y, W, H, L)\n{\n", f.indent(1), c);
   }
 
-//  write_c("%s%s *o = this;\n", indent(1), name());
+//  f.write_c("%s%s *o = this;\n", f.indent(1), name());
 
-  indentation++;
-  write_widget_code();
+  f.indentation++;
+  write_widget_code(f);
 }
 
-void Fl_Widget_Class_Type::write_code2() {
-  write_extra_code();
+void Fl_Widget_Class_Type::write_code2(Fd_Code_Writer& f) {
+  write_extra_code(f);
   if (wc_relative==1)
-    write_c("%sposition(X, Y);\n", indent());
+    f.write_c("%sposition(X, Y);\n", f.indent());
   else if (wc_relative==2)
-    write_c("%sresize(X, Y, W, H);\n", indent());
-  if (modal) write_c("%sset_modal();\n", indent());
-  else if (non_modal) write_c("%sset_non_modal();\n", indent());
-  if (!((Fl_Window*)o)->border()) write_c("%sclear_border();\n", indent());
+    f.write_c("%sresize(X, Y, W, H);\n", f.indent());
+  if (modal) f.write_c("%sset_modal();\n", f.indent());
+  else if (non_modal) f.write_c("%sset_non_modal();\n", f.indent());
+  if (!((Fl_Window*)o)->border()) f.write_c("%sclear_border();\n", f.indent());
   if (xclass) {
-    write_c("%sxclass(", indent());
-    write_cstring(xclass);
-    write_c(");\n");
+    f.write_c("%sxclass(", f.indent());
+    f.write_cstring(xclass);
+    f.write_c(");\n");
   }
-  write_c("%send();\n", indent());
+  f.write_c("%send();\n", f.indent());
   if (((Fl_Window*)o)->resizable() == o)
-    write_c("%sresizable(this);\n", indent());
-  indentation--;
-  write_c("}\n");
+    f.write_c("%sresizable(this);\n", f.indent());
+  f.indentation--;
+  f.write_c("}\n");
 }
 
 ////////////////////////////////////////////////////////////////
diff --git fluid/Fl_Window_Type.h fluid/Fl_Window_Type.h
index 4e4ac8a..519af34 100644
--- fluid/Fl_Window_Type.h
+++ fluid/Fl_Window_Type.h
@@ -51,8 +51,8 @@ protected:
   void newposition(Fl_Widget_Type *,int &x,int &y,int &w,int &h);
   int handle(int);
   void setlabel(const char *) FL_OVERRIDE;
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   Fl_Widget_Type *_make() FL_OVERRIDE {return 0;} // we don't call this
   Fl_Widget *widget(int,int,int,int) FL_OVERRIDE {return 0;}
   int recalc;           // set by fix_overlay()
@@ -84,8 +84,8 @@ public:
   void fix_overlay();                   // Update the bounding box, etc
   uchar *read_image(int &ww, int &hh);  // Read an image of the window
 
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
   int read_fdesign(const char*, const char*) FL_OVERRIDE;
 
   void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE;
@@ -118,11 +118,11 @@ public:
   char write_public_state; // true when public: has been printed
   char wc_relative; // if 1, reposition all children, if 2, reposition and resize
 
-  void write_properties() FL_OVERRIDE;
-  void read_property(const char *) FL_OVERRIDE;
+  void write_properties(Fd_Project_Writer &f) FL_OVERRIDE;
+  void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE;
 
-  void write_code1() FL_OVERRIDE;
-  void write_code2() FL_OVERRIDE;
+  void write_code1(Fd_Code_Writer& f) FL_OVERRIDE;
+  void write_code2(Fd_Code_Writer& f) FL_OVERRIDE;
   Fl_Type *make(Strategy strategy) FL_OVERRIDE;
   const char *type_name() FL_OVERRIDE {return "widget_class";}
   int pixmapID() FL_OVERRIDE { return 48; }
diff --git fluid/Fluid_Image.cxx fluid/Fluid_Image.cxx
index bc44733..f3b2277 100644
--- fluid/Fluid_Image.cxx
+++ fluid/Fluid_Image.cxx
@@ -46,38 +46,28 @@ void Fluid_Image::deimage(Fl_Widget *o) {
   if (o->window() != o) o->deimage(img);
 }
 
-static int pixmap_header_written = 0;
-static int bitmap_header_written = 0;
-static int image_header_written = 0;
-static int jpeg_header_written = 0;
-static int png_header_written = 0;
-static int gif_header_written = 0;
-static int animated_gif_header_written = 0;
-static int bmp_header_written = 0;
-static int svg_header_written = 0;
-
 /** Write the contents of the name() file as binary source code.
  \param fmt short name of file contents for error message
  \return 0 if the file could not be opened or read */
-size_t Fluid_Image::write_static_binary(const char* fmt) {
+size_t Fluid_Image::write_static_binary(Fd_Code_Writer& f, const char* fmt) {
   size_t nData = 0;
   enter_project_dir();
-  FILE *f = fl_fopen(name(), "rb");
+  FILE *in = fl_fopen(name(), "rb");
   leave_project_dir();
-  if (!f) {
-    write_file_error(fmt);
+  if (!in) {
+    write_file_error(f, fmt);
     return 0;
   } else {
-    fseek(f, 0, SEEK_END);
-    nData = ftell(f);
-    fseek(f, 0, SEEK_SET);
+    fseek(in, 0, SEEK_END);
+    nData = ftell(in);
+    fseek(in, 0, SEEK_SET);
     if (nData) {
       char *data = (char*)calloc(nData, 1);
-      if (fread(data, nData, 1, f)==0) { /* ignore */ }
-      write_cdata(data, (int)nData);
+      if (fread(data, nData, 1, in)==0) { /* ignore */ }
+      f.write_cdata(data, (int)nData);
       free(data);
     }
-    fclose(f);
+    fclose(in);
   }
   return nData;
 }
@@ -85,41 +75,38 @@ size_t Fluid_Image::write_static_binary(const char* fmt) {
 /** Write the contents of the name() file as textual source code.
  \param fmt short name of file contents for error message
  \return 0 if the file could not be opened or read */
-size_t Fluid_Image::write_static_text(const char* fmt) {
+size_t Fluid_Image::write_static_text(Fd_Code_Writer& f, const char* fmt) {
   size_t nData = 0;
   enter_project_dir();
-  FILE *f = fl_fopen(name(), "rb");
+  FILE *in = fl_fopen(name(), "rb");
   leave_project_dir();
-  if (!f) {
-    write_file_error(fmt);
+  if (!in) {
+    write_file_error(f, fmt);
     return 0;
   } else {
-    fseek(f, 0, SEEK_END);
-    nData = ftell(f);
-    fseek(f, 0, SEEK_SET);
+    fseek(in, 0, SEEK_END);
+    nData = ftell(in);
+    fseek(in, 0, SEEK_SET);
     if (nData) {
       char *data = (char*)calloc(nData+1, 1);
-      if (fread(data, nData, 1, f)==0) { /* ignore */ }
-      write_cstring(data, (int)nData);
+      if (fread(data, nData, 1, in)==0) { /* ignore */ }
+      f.write_cstring(data, (int)nData);
       free(data);
     }
-    fclose(f);
+    fclose(in);
   }
   return nData;
 }
 
-void Fluid_Image::write_static_rgb(const char* idata_name) {
+void Fluid_Image::write_static_rgb(Fd_Code_Writer& f, const char* idata_name) {
   // Write image data...
-  write_c("\n");
-  if (image_header_written != write_number) {
-    write_c("#include <FL/Fl_Image.H>\n");
-    image_header_written = write_number;
-  }
-  write_c("static const unsigned char %s[] =\n", idata_name);
+  f.write_c("\n");
+  f.write_c_once("#include <FL/Fl_Image.H>\n");
+  f.write_c("static const unsigned char %s[] =\n", idata_name);
   const int extra_data = img->ld() ? (img->ld()-img->w()*img->d()) : 0;
-  write_cdata(img->data()[0], (img->w() * img->d() + extra_data) * img->h());
-  write_c(";\n");
-  write_initializer("Fl_RGB_Image", "%s, %d, %d, %d, %d", idata_name, img->w(), img->h(), img->d(), img->ld());
+  f.write_cdata(img->data()[0], (img->w() * img->d() + extra_data) * img->h());
+  f.write_c(";\n");
+  write_initializer(f, "Fl_RGB_Image", "%s, %d, %d, %d, %d", idata_name, img->w(), img->h(), img->d(), img->ld());
 }
 
 /**
@@ -132,126 +119,102 @@ void Fluid_Image::write_static_rgb(const char* idata_name) {
 
  \param compressed write data in the original compressed file format
  */
-void Fluid_Image::write_static(int compressed) {
+void Fluid_Image::write_static(Fd_Code_Writer& f, int compressed) {
   if (!img) return;
-  const char *idata_name = unique_id(this, "idata", fl_filename_name(name()), 0);
-  function_name_ = unique_id(this, "image", fl_filename_name(name()), 0);
+  const char *idata_name = f.unique_id(this, "idata", fl_filename_name(name()), 0);
+  function_name_ = f.unique_id(this, "image", fl_filename_name(name()), 0);
   
   if (is_animated_gif_) {
     // Write animated gif image data...
-    write_c("\n");
-    if (animated_gif_header_written != write_number) {
-      write_c("#include <FL/Fl_Anim_GIF_Image.H>\n");
-      animated_gif_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    size_t nData = write_static_binary("AnimGIF");
-    write_c(";\n");
-    write_initializer("Fl_Anim_GIF_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_Anim_GIF_Image.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    size_t nData = write_static_binary(f, "AnimGIF");
+    f.write_c(";\n");
+    write_initializer(f, "Fl_Anim_GIF_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
   } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(name()), ".gif")==0) {
     // Write gif image data...
-    write_c("\n");
-    if (gif_header_written != write_number) {
-      write_c("#include <FL/Fl_GIF_Image.H>\n");
-      gif_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    size_t nData = write_static_binary("GIF");
-    write_c(";\n");
-    write_initializer("Fl_GIF_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_GIF_Image.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    size_t nData = write_static_binary(f, "GIF");
+    f.write_c(";\n");
+    write_initializer(f, "Fl_GIF_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
   } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(name()), ".bmp")==0) {
     // Write bmp image data...
-    write_c("\n");
-    if (bmp_header_written != write_number) {
-      write_c("#include <FL/Fl_BMP_Image.H>\n");
-      bmp_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    size_t nData = write_static_binary("BMP");
-    write_c(";\n");
-    write_initializer("Fl_BMP_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_BMP_Image.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    size_t nData = write_static_binary(f, "BMP");
+    f.write_c(";\n");
+    write_initializer(f, "Fl_BMP_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
   } else if (img->count() > 1) {
     // Write Pixmap data...
-    write_c("\n");
-    if (pixmap_header_written != write_number) {
-      write_c("#include <FL/Fl_Pixmap.H>\n");
-      pixmap_header_written = write_number;
-    }
-    write_c("static const char *%s[] = {\n", idata_name);
-    write_cstring(img->data()[0], (int)strlen(img->data()[0]));
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_Pixmap.H>\n");
+    f.write_c("static const char *%s[] = {\n", idata_name);
+    f.write_cstring(img->data()[0], (int)strlen(img->data()[0]));
 
     int i;
     int ncolors, chars_per_color;
     sscanf(img->data()[0], "%*d%*d%d%d", &ncolors, &chars_per_color);
 
     if (ncolors < 0) {
-      write_c(",\n");
-      write_cstring(img->data()[1], ncolors * -4);
+      f.write_c(",\n");
+      f.write_cstring(img->data()[1], ncolors * -4);
       i = 2;
     } else {
       for (i = 1; i <= ncolors; i ++) {
-        write_c(",\n");
-        write_cstring(img->data()[i], (int)strlen(img->data()[i]));
+        f.write_c(",\n");
+        f.write_cstring(img->data()[i], (int)strlen(img->data()[i]));
       }
     }
     for (; i < img->count(); i ++) {
-      write_c(",\n");
-      write_cstring(img->data()[i], img->w() * chars_per_color);
+      f.write_c(",\n");
+      f.write_cstring(img->data()[i], img->w() * chars_per_color);
     }
-    write_c("\n};\n");
-    write_initializer("Fl_Pixmap", "%s", idata_name);
+    f.write_c("\n};\n");
+    write_initializer(f, "Fl_Pixmap", "%s", idata_name);
   } else if (img->d() == 0) {
     // Write Bitmap data...
-    write_c("\n");
-    if (bitmap_header_written != write_number) {
-      write_c("#include <FL/Fl_Bitmap.H>\n");
-      bitmap_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    write_cdata(img->data()[0], ((img->w() + 7) / 8) * img->h());
-    write_c(";\n");
-    write_initializer( "Fl_Bitmap", "%s, %d, %d, %d", idata_name, ((img->w() + 7) / 8) * img->h(), img->w(), img->h());
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_Bitmap.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    f.write_cdata(img->data()[0], ((img->w() + 7) / 8) * img->h());
+    f.write_c(";\n");
+    write_initializer(f, "Fl_Bitmap", "%s, %d, %d, %d", idata_name, ((img->w() + 7) / 8) * img->h(), img->w(), img->h());
   } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(name()), ".jpg")==0) {
     // Write jpeg image data...
-    write_c("\n");
-    if (jpeg_header_written != write_number) {
-      write_c("#include <FL/Fl_JPEG_Image.H>\n");
-      jpeg_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    size_t nData = write_static_binary("JPEG");
-    write_c(";\n");
-    write_initializer("Fl_JPEG_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_JPEG_Image.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    size_t nData = write_static_binary(f, "JPEG");
+    f.write_c(";\n");
+    write_initializer(f, "Fl_JPEG_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
   } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(name()), ".png")==0) {
     // Write png image data...
-    write_c("\n");
-    if (png_header_written != write_number) {
-      write_c("#include <FL/Fl_PNG_Image.H>\n");
-      png_header_written = write_number;
-    }
-    write_c("static const unsigned char %s[] =\n", idata_name);
-    size_t nData = write_static_binary("PNG");
-    write_c(";\n");
-    write_initializer("Fl_PNG_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
+    f.write_c("\n");
+    f.write_c_once("#include <FL/Fl_PNG_Image.H>\n");
+    f.write_c("static const unsigned char %s[] =\n", idata_name);
+    size_t nData = write_static_binary(f, "PNG");
+    f.write_c(";\n");
+    write_initializer(f, "Fl_PNG_Image", "\"%s\", %s, %d", fl_filename_name(name()), idata_name, nData);
   } else if (fl_ascii_strcasecmp(fl_filename_ext(name()), ".svg")==0 || fl_ascii_strcasecmp(fl_filename_ext(name()), ".svgz")==0) {
     bool gzipped = (strcmp(fl_filename_ext(name()), ".svgz") == 0);
     // Write svg image data...
     if (compressed) {
-      write_c("\n");
-      if (svg_header_written != write_number) {
-        write_c("#include <FL/Fl_SVG_Image.H>\n");
-        svg_header_written = write_number;
-      }
+      f.write_c("\n");
+      f.write_c_once("#include <FL/Fl_SVG_Image.H>\n");
       if (gzipped) {
-        write_c("static const unsigned char %s[] =\n", idata_name);
-        size_t nData = write_static_binary("SVGZ");
-        write_c(";\n");
-        write_initializer("Fl_SVG_Image", "\"%s\", %s, %ld", fl_filename_name(name()), idata_name, nData);
+        f.write_c("static const unsigned char %s[] =\n", idata_name);
+        size_t nData = write_static_binary(f, "SVGZ");
+        f.write_c(";\n");
+        write_initializer(f, "Fl_SVG_Image", "\"%s\", %s, %ld", fl_filename_name(name()), idata_name, nData);
       } else {
-        write_c("static const char %s[] =\n", idata_name);
-        write_static_text("SVG");
-        write_c(";\n");
-        write_initializer("Fl_SVG_Image", "\"%s\", %s", fl_filename_name(name()), idata_name);
+        f.write_c("static const char %s[] =\n", idata_name);
+        write_static_text(f, "SVG");
+        f.write_c(";\n");
+        write_initializer(f, "Fl_SVG_Image", "\"%s\", %s", fl_filename_name(name()), idata_name);
       }
     } else {
       // if FLUID runs from the command line, make sure that the image is not
@@ -264,24 +227,24 @@ void Fluid_Image::write_static(int compressed) {
         svg_image = rgb_image->as_svg_image();
       if (svg_image) {
         svg_image->resize(svg_image->w(), svg_image->h());
-        write_static_rgb(idata_name);
+        write_static_rgb(f, idata_name);
       } else {
-        write_file_error("RGB_from_SVG");
+        write_file_error(f, "RGB_from_SVG");
       }
     }
   } else {
-    write_static_rgb(idata_name);
+    write_static_rgb(f, idata_name);
   }
 }
 
-void Fluid_Image::write_file_error(const char *fmt) {
-  write_c("#warning Cannot read %s file \"%s\": %s\n", fmt, name(), strerror(errno));
+void Fluid_Image::write_file_error(Fd_Code_Writer& f, const char *fmt) {
+  f.write_c("#warning Cannot read %s file \"%s\": %s\n", fmt, name(), strerror(errno));
   enter_project_dir();
-  write_c("// Searching in path \"%s\"\n", fl_getcwd(0, FL_PATH_MAX));
+  f.write_c("// Searching in path \"%s\"\n", fl_getcwd(0, FL_PATH_MAX));
   leave_project_dir();
 }
 
-void Fluid_Image::write_initializer(const char *type_name, const char *format, ...) {
+void Fluid_Image::write_initializer(Fd_Code_Writer& f, const char *type_name, const char *format, ...) {
   /* Outputs code that returns (and initializes if needed) an Fl_Image as follows:
    static Fl_Image *'function_name_'() {
      static Fl_Image *image = NULL;
@@ -291,32 +254,32 @@ void Fluid_Image::write_initializer(const char *type_name, const char *format, .
    } */
   va_list ap;
   va_start(ap, format);
-  write_c("static Fl_Image *%s() {\n", function_name_);
+  f.write_c("static Fl_Image *%s() {\n", function_name_);
   if (is_animated_gif_)
-    write_c("%sFl_GIF_Image::animate = true;\n", indent(1));
-  write_c("%sstatic Fl_Image *image = NULL;\n", indent(1));
-  write_c("%sif (!image)\n", indent(1));
-  write_c("%simage = new %s(", indent(2), type_name);
-  vwrite_c(format, ap);
-  write_c(");\n");
-  write_c("%sreturn image;\n", indent(1));
-  write_c("}\n");
+    f.write_c("%sFl_GIF_Image::animate = true;\n", f.indent(1));
+  f.write_c("%sstatic Fl_Image *image = NULL;\n", f.indent(1));
+  f.write_c("%sif (!image)\n", f.indent(1));
+  f.write_c("%simage = new %s(", f.indent(2), type_name);
+  f.vwrite_c(format, ap);
+  f.write_c(");\n");
+  f.write_c("%sreturn image;\n", f.indent(1));
+  f.write_c("}\n");
   va_end(ap);
 }
 
-void Fluid_Image::write_code(int bind, const char *var, int inactive) {
+void Fluid_Image::write_code(Fd_Code_Writer& f, int bind, const char *var, int inactive) {
   /* Outputs code that attaches an image to an Fl_Widget or Fl_Menu_Item.
    This code calls a function output before by Fluid_Image::write_initializer() */
   if (img) {
-    write_c("%s%s->%s%s( %s() );\n", indent(), var, bind ? "bind_" : "", inactive ? "deimage" : "image", function_name_);
+    f.write_c("%s%s->%s%s( %s() );\n", f.indent(), var, bind ? "bind_" : "", inactive ? "deimage" : "image", function_name_);
     if (is_animated_gif_)
-      write_c("%s((Fl_Anim_GIF_Image*)(%s()))->canvas(%s, Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS);\n", indent(), function_name_, var);
+      f.write_c("%s((Fl_Anim_GIF_Image*)(%s()))->canvas(%s, Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS);\n", f.indent(), function_name_, var);
   }
 }
 
-void Fluid_Image::write_inline(int inactive) {
+void Fluid_Image::write_inline(Fd_Code_Writer& f, int inactive) {
   if (img)
-    write_c("%s()", function_name_);
+    f.write_c("%s()", function_name_);
 }
 
 
@@ -345,7 +308,10 @@ Fluid_Image* Fluid_Image::find(const char *iname) {
   enter_project_dir();
   FILE *f = fl_fopen(iname,"rb");
   if (!f) {
-    read_error("%s : %s",iname,strerror(errno));
+    if (batch_mode)
+      fprintf(stderr, "Can't open image file:\n%s\n%s",iname,strerror(errno));
+    else
+      fl_message("Can't open image file:\n%s\n%s",iname,strerror(errno));
     leave_project_dir();
     return 0;
   }
@@ -356,7 +322,10 @@ Fluid_Image* Fluid_Image::find(const char *iname) {
   if (!ret->img || !ret->img->w() || !ret->img->h()) {
     delete ret;
     ret = 0;
-    read_error("%s : unrecognized image format", iname);
+    if (batch_mode)
+      fprintf(stderr, "Can't read image file:\n%s\nunrecognized image format",iname);
+    else
+      fl_message("Can't read image file:\n%s\nunrecognized image format",iname);
   }
   leave_project_dir();
   if (!ret) return 0;
diff --git fluid/Fluid_Image.h fluid/Fluid_Image.h
index deb9ecf..73387ff 100644
--- fluid/Fluid_Image.h
+++ fluid/Fluid_Image.h
@@ -23,6 +23,8 @@
 
 #include <FL/Fl_Shared_Image.H>
 
+#include "code.h"
+
 class Fluid_Image {
   bool is_animated_gif_;
   const char *name_;
@@ -32,9 +34,9 @@ class Fluid_Image {
 protected:
   Fluid_Image(const char *name); // no public constructor
   ~Fluid_Image(); // no public destructor
-  size_t write_static_binary(const char* fmt);
-  size_t write_static_text(const char* fmt);
-  void write_static_rgb(const char* idata_name);
+  size_t write_static_binary(Fd_Code_Writer& f, const char* fmt);
+  size_t write_static_text(Fd_Code_Writer& f, const char* fmt);
+  void write_static_rgb(Fd_Code_Writer& f, const char* idata_name);
 public:
   int written;
   static Fluid_Image* find(const char *);
@@ -42,11 +44,11 @@ public:
   void increment();
   void image(Fl_Widget *); // set the image of this widget
   void deimage(Fl_Widget *); // set the deimage of this widget
-  void write_static(int compressed);
-  void write_initializer(const char *type_name, const char *format, ...);
-  void write_code(int bind, const char *var, int inactive = 0);
-  void write_inline(int inactive = 0);
-  void write_file_error(const char *fmt);
+  void write_static(Fd_Code_Writer& f, int compressed);
+  void write_initializer(Fd_Code_Writer& f, const char *type_name, const char *format, ...);
+  void write_code(Fd_Code_Writer& f, int bind, const char *var, int inactive = 0);
+  void write_inline(Fd_Code_Writer& f, int inactive = 0);
+  void write_file_error(Fd_Code_Writer& f, const char *fmt);
   const char *name() const {return name_;}
 };
 
diff --git fluid/about_panel.cxx fluid/about_panel.cxx
index b01616e..8c2054d 100644
--- fluid/about_panel.cxx
+++ fluid/about_panel.cxx
@@ -22,6 +22,7 @@ void show_help(const char *name);
 Fl_Double_Window *about_panel=(Fl_Double_Window *)0;
 
 #include <FL/Fl_Anim_GIF_Image.H>
+
 static const unsigned char idata_fluid[] =
 {71,73,70,56,57,97,96,0,96,0,132,31,0,0,1,0,3,31,63,46,48,45,0,54,108,78,80,
 77,64,123,116,124,126,123,125,173,98,107,166,116,171,204,63,220,233,19,253,254,
diff --git fluid/code.cxx fluid/code.cxx
index 6d1ab3f..f257c6a 100644
--- fluid/code.cxx
+++ fluid/code.cxx
@@ -34,15 +34,6 @@
 /// \defgroup cfile C Code File Operations
 /// \{
 
-static FILE *code_file = NULL;
-static FILE *header_file = NULL;
-
-/// Store the current indentation level for the C source code.
-int indentation = 0;
-
-int write_number = 0;
-
-int write_sourceview = 0;
 
 /**
  Return true if c can be in a C identifier.
@@ -52,40 +43,177 @@ int is_id(char c) {
   return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
 }
 
+/**
+ Write a file that contains all label and tooltip strings for internationalisation.
+ */
+int write_strings(const char *sfile) {
+  FILE *fp = fl_fopen(sfile, "w");
+  Fl_Type *p;
+  Fl_Widget_Type *w;
+  int i;
+
+  if (!fp) return 1;
+
+  switch (g_project.i18n_type) {
+    case 0 : /* None, just put static text out */
+      fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
+              FL_VERSION);
+      for (p = Fl_Type::first; p; p = p->next) {
+        if (p->is_widget()) {
+          w = (Fl_Widget_Type *)p;
+
+          if (w->label()) {
+            for (const char *s = w->label(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            putc('\n', fp);
+          }
+
+          if (w->tooltip()) {
+            for (const char *s = w->tooltip(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            putc('\n', fp);
+          }
+        }
+      }
+      break;
+    case 1 : /* GNU gettext, put a .po file out */
+      fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
+              FL_VERSION);
+      for (p = Fl_Type::first; p; p = p->next) {
+        if (p->is_widget()) {
+          w = (Fl_Widget_Type *)p;
+
+          if (w->label()) {
+            const char *s;
+
+            fputs("msgid \"", fp);
+            for (s = w->label(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+
+            fputs("msgstr \"", fp);
+            for (s = w->label(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+          }
+
+          if (w->tooltip()) {
+            const char *s;
+
+            fputs("msgid \"", fp);
+            for (s = w->tooltip(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+
+            fputs("msgstr \"", fp);
+            for (s = w->tooltip(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+          }
+        }
+      }
+      break;
+    case 2 : /* POSIX catgets, put a .msg file out */
+      fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
+              FL_VERSION);
+      fprintf(fp, "$set %s\n", g_project.i18n_set.value());
+      fputs("$quote \"\n", fp);
+
+      for (i = 1, p = Fl_Type::first; p; p = p->next) {
+        if (p->is_widget()) {
+          w = (Fl_Widget_Type *)p;
+
+          if (w->label()) {
+            fprintf(fp, "%d \"", i ++);
+            for (const char *s = w->label(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+          }
+
+          if (w->tooltip()) {
+            fprintf(fp, "%d \"", i ++);
+            for (const char *s = w->tooltip(); *s; s ++)
+              if (*s < 32 || *s > 126 || *s == '\"')
+                fprintf(fp, "\\%03o", *s);
+              else
+                putc(*s, fp);
+            fputs("\"\n", fp);
+          }
+        }
+      }
+      break;
+  }
+
+  return fclose(fp);
+}
+
 ////////////////////////////////////////////////////////////////
 // Generate unique but human-readable identifiers:
 
-struct id {
+struct Fd_Identifier_Tree {
   char* text;
   void* object;
-  id *left, *right;
-  id (const char* t, void* o) : text(fl_strdup(t)), object(o) {left = right = 0;}
-  ~id();
+  Fd_Identifier_Tree *left, *right;
+  Fd_Identifier_Tree (const char* t, void* o) : text(fl_strdup(t)), object(o) {left = right = 0;}
+  ~Fd_Identifier_Tree();
 };
 
-id::~id() {
+Fd_Identifier_Tree::~Fd_Identifier_Tree() {
   delete left;
   free((void *)text);
   delete right;
 }
 
-static id* id_root;
+/** \brief Return a unique name for the given object.
+
+ This function combines the anem and label into an identifier. It then checks
+ if that id was already taken by another object, and if so, appends a
+ hexadecimal value which is incremented until the id is unique in this file.
+
+ If a new id was created, it is stored in the id tree.
 
-// TODO: document me
-const char* unique_id(void* o, const char* type, const char* name, const char* label) {
+ \param[in] o create an ID for this object
+ \param[in] type is the first word of the ID
+ \param[in] name if name is set, it is appended to the ID
+ \param[in] label else if label is set, it is appended, skipping non-keyword characters
+ \return buffer to a unique identifier, managed by Fd_Code_Writer, so caller must NOT free() it
+ */
+const char* Fd_Code_Writer::unique_id(void* o, const char* type, const char* name, const char* label) {
   char buffer[128];
   char* q = buffer;
+  char* q_end = q + 128 - 8 - 1; // room for hex number and NUL
   while (*type) *q++ = *type++;
   *q++ = '_';
   const char* n = name;
   if (!n || !*n) n = label;
   if (n && *n) {
     while (*n && !is_id(*n)) n++;
-    while (is_id(*n)) *q++ = *n++;
+    while (is_id(*n) && (q < q_end)) *q++ = *n++;
   }
   *q = 0;
   // okay, search the tree and see if the name was already used:
-  id** p = &id_root;
+  Fd_Identifier_Tree** p = &id_root;
   int which = 0;
   while (*p) {
     int i = strcmp(buffer, (*p)->text);
@@ -99,7 +227,7 @@ const char* unique_id(void* o, const char* type, const char* name, const char* l
     else if (i < 0) p = &((*p)->left);
     else p  = &((*p)->right);
   }
-  *p = new id(buffer, o);
+  *p = new Fd_Identifier_Tree(buffer, o);
   return (*p)->text;
 }
 
@@ -121,7 +249,7 @@ const char* unique_id(void* o, const char* type, const char* name, const char* l
  \param[in] set generate this indent depth
  \return pointer to a static string
  */
-const char *indent(int set) {
+const char *Fd_Code_Writer::indent(int set) {
   static const char* spaces = "                                ";
   int i = set * 2;
   if (i>32) i = 32;
@@ -133,7 +261,7 @@ const char *indent(int set) {
  Return a C string that indents code to the current source file depth.
  \return pointer to a static string
  */
-const char *indent() {
+const char *Fd_Code_Writer::indent() {
   return indent(indentation);
 }
 
@@ -143,45 +271,59 @@ const char *indent() {
     change the `indentation` variable; offset can be negative
  \return pointer to a static string
  */
-const char *indent_plus(int offset) {
+const char *Fd_Code_Writer::indent_plus(int offset) {
   return indent(indentation+offset);
 }
 
 
 ////////////////////////////////////////////////////////////////
 // declarations/include files:
-// Each string generated by write_declare is written only once to
+// Each string generated by write_h_once is written only once to
 // the header file.  This is done by keeping a binary tree of all
 // the calls so far and not printing it if it is in the tree.
 
-struct included {
+struct Fd_Text_Tree {
   char *text;
-  included *left, *right;
-  included(const char *t) {
+  Fd_Text_Tree *left, *right;
+  Fd_Text_Tree(const char *t) {
     text = fl_strdup(t);
     left = right = 0;
   }
-  ~included();
+  ~Fd_Text_Tree();
 };
 
-included::~included() {
+Fd_Text_Tree::~Fd_Text_Tree() {
   delete left;
   free((void *)text);
   delete right;
 }
-static included *included_root;
+
+struct Fd_Pointer_Tree {
+  void *ptr;
+  Fd_Pointer_Tree *left, *right;
+  Fd_Pointer_Tree(void *p) {
+    ptr = p;
+    left = right = 0;
+  }
+  ~Fd_Pointer_Tree();
+};
+
+Fd_Pointer_Tree::~Fd_Pointer_Tree() {
+  delete left;
+  delete right;
+}
 
 /**
- Print a formatted line to the header file, unless the same line was produced before.
+ Print a formatted line to the header file, unless the same line was produced before in this header file.
  \param[in] format printf-style formatting text, followed by a vararg list
  */
-int write_declare(const char *format, ...) {
+int Fd_Code_Writer::write_h_once(const char *format, ...) {
   va_list args;
   char buf[1024];
   va_start(args, format);
   vsnprintf(buf, sizeof(buf), format, args);
   va_end(args);
-  included **p = &included_root;
+  Fd_Text_Tree **p = &text_in_header;
   while (*p) {
     int i = strcmp(buf,(*p)->text);
     if (!i) return 0;
@@ -189,17 +331,53 @@ int write_declare(const char *format, ...) {
     else p  = &((*p)->right);
   }
   fprintf(header_file,"%s\n",buf);
-  *p = new included(buf);
+  *p = new Fd_Text_Tree(buf);
   return 1;
 }
 
-////////////////////////////////////////////////////////////////
+/**
+ Print a formatted line to the source file, unless the same line was produced before in this code file.
+ \param[in] format printf-style formatting text, followed by a vararg list
+ */
+int Fd_Code_Writer::write_c_once(const char *format, ...) {
+  va_list args;
+  char buf[1024];
+  va_start(args, format);
+  vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  Fd_Text_Tree **p = &text_in_header;
+  while (*p) {
+    int i = strcmp(buf,(*p)->text);
+    if (!i) return 0;
+    else if (i < 0) p = &((*p)->left);
+    else p  = &((*p)->right);
+  }
+  p = &text_in_code;
+  while (*p) {
+    int i = strcmp(buf,(*p)->text);
+    if (!i) return 0;
+    else if (i < 0) p = &((*p)->left);
+    else p  = &((*p)->right);
+  }
+  fprintf(code_file,"%s\n",buf);
+  *p = new Fd_Text_Tree(buf);
+  return 1;
+}
 
-// silly thing to prevent declaring unused variables:
-// When this symbol is on, all attempts to write code don't write
-// anything, but set a variable if it looks like the variable "o" is used:
-int varused_test;
-int varused;
+/**
+ Return true if this pointer was already included in the code file.
+ If it was not, add it to the list and return false.
+ */
+bool Fd_Code_Writer::c_contains(void *pp) {
+  Fd_Pointer_Tree **p = &ptr_in_code;
+  while (*p) {
+    if ((*p)->ptr == pp) return true;
+    else if ((*p)->ptr < pp) p = &((*p)->left);
+    else p  = &((*p)->right);
+  }
+  *p = new Fd_Pointer_Tree(pp);
+  return false;
+}
 
 /**
  Write a C string to the code file, escaping non-ASCII characters.
@@ -215,9 +393,9 @@ int varused;
  \param[in] s write this string
  \param[in] length write so many bytes in this string
 
- \see write_cstring(const char*)
+ \see f.write_cstring(const char*)
  */
-void write_cstring(const char *s, int length) {
+void Fd_Code_Writer::write_cstring(const char *s, int length) {
   if (varused_test) {
     varused = 1;
     return;
@@ -314,9 +492,9 @@ void write_cstring(const char *s, int length) {
 /**
  Write a C string, escaping non-ASCII characters.
  \param[in] s write this string
- \see write_cstring(const char*, int)
+ \see f.write_cstring(const char*, int)
  */
-void write_cstring(const char *s) {
+void Fd_Code_Writer::write_cstring(const char *s) {
   write_cstring(s, (int)strlen(s));
 }
 
@@ -325,7 +503,7 @@ void write_cstring(const char *s) {
  The output is bracketed in { and }. The content is written
  as decimal bytes, i.e. `{ 1, 2, 200 }`
  */
-void write_cdata(const char *s, int length) {
+void Fd_Code_Writer::write_cdata(const char *s, int length) {
   if (varused_test) {
     varused = 1;
     return;
@@ -363,7 +541,7 @@ void write_cdata(const char *s, int length) {
  \param[in] format printf-style formatting text
  \param[in] args list of arguments
  */
-void vwrite_c(const char* format, va_list args) {
+void Fd_Code_Writer::vwrite_c(const char* format, va_list args) {
   if (varused_test) {
     varused = 1;
     return;
@@ -375,7 +553,7 @@ void vwrite_c(const char* format, va_list args) {
  Print a formatted line to the source file.
  \param[in] format printf-style formatting text, followed by a vararg list
  */
-void write_c(const char* format,...) {
+void Fd_Code_Writer::write_c(const char* format,...) {
   va_list args;
   va_start(args, format);
   vwrite_c(format, args);
@@ -390,7 +568,7 @@ void write_c(const char* format,...) {
  \param[in] c line of code
  \param[in] com optional commentary
  */
-void write_cc(const char *indent, int n, const char *c, const char *com) {
+void Fd_Code_Writer::write_cc(const char *indent, int n, const char *c, const char *com) {
   write_c("%s%.*s", indent, n, c);
   char cc = c[n-1];
   if (cc!='}' && cc!=';')
@@ -404,7 +582,7 @@ void write_cc(const char *indent, int n, const char *c, const char *com) {
  Print a formatted line to the header file.
  \param[in] format printf-style formatting text, followed by a vararg list
  */
-void write_h(const char* format,...) {
+void Fd_Code_Writer::write_h(const char* format,...) {
   if (varused_test) return;
   va_list args;
   va_start(args, format);
@@ -420,7 +598,7 @@ void write_h(const char* format,...) {
  \param[in] c line of code
  \param[in] com optional commentary
  */
-void write_hc(const char *indent, int n, const char* c, const char *com) {
+void Fd_Code_Writer::write_hc(const char *indent, int n, const char* c, const char *com) {
   write_h("%s%.*s", indent, n, c);
   char cc = c[n-1];
   if (cc!='}' && cc!=';')
@@ -434,7 +612,7 @@ void write_hc(const char *indent, int n, const char* c, const char *com) {
  Write one or more lines of code, indenting each one of them.
  \param[in] textlines one or more lines of text, seperated by \\n
  */
-void write_c_indented(const char *textlines, int inIndent, char inTrailwWith) {
+void Fd_Code_Writer::write_c_indented(const char *textlines, int inIndent, char inTrailwWith) {
   if (textlines) {
     indentation += inIndent;
     for (;;) {
@@ -470,7 +648,7 @@ void write_c_indented(const char *textlines, int inIndent, char inTrailwWith) {
 /**
  Recursively dump code, putting children between the two parts of the parent code.
  */
-static Fl_Type* write_code(Fl_Type* p) {
+Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) {
   if (write_sourceview) {
     p->code_position = (int)ftell(code_file);
     if (p->header_position_end==-1)
@@ -479,7 +657,7 @@ static Fl_Type* write_code(Fl_Type* p) {
   // write all code that come before the children code
   // (but don't write the last comment until the very end)
   if (!(p==Fl_Type::last && p->is_comment()))
-    p->write_code1();
+    p->write_code1(*this);
   // recursively write the code of all children
   Fl_Type* q;
   if (p->is_widget() && p->is_class()) {
@@ -495,7 +673,7 @@ static Fl_Type* write_code(Fl_Type* p) {
     }
 
     // write all code that come after the children
-    p->write_code2();
+    p->write_code2(*this);
 
     for (q = p->next; q && q->level > p->level;) {
       if (!strcmp(q->type_name(), "Function")) q = write_code(q);
@@ -512,7 +690,7 @@ static Fl_Type* write_code(Fl_Type* p) {
   } else {
     for (q = p->next; q && q->level > p->level;) q = write_code(q);
     // write all code that come after the children
-    p->write_code2();
+    p->write_code2(*this);
   }
   if (write_sourceview) {
     p->code_position_end = (int)ftell(code_file);
@@ -531,11 +709,11 @@ static Fl_Type* write_code(Fl_Type* p) {
  \param[in] t filename of the header file
  \return 0 if the operation failed, 1 if it was successful
  */
-int write_code(const char *s, const char *t) {
+int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_sourceview) {
+  write_sourceview = to_sourceview;
   const char *filemode = "w";
   if (write_sourceview)
     filemode = "wb";
-  write_number++;
   delete id_root; id_root = 0;
   indentation = 0;
   current_class = 0L;
@@ -561,7 +739,7 @@ int write_code(const char *s, const char *t) {
       first_type->header_position = (int)ftell(header_file);
     }
     // it is ok to write non-recusive code here, because comments have no children or code2 blocks
-    first_type->write_code1();
+    first_type->write_code1(*this);
     if (write_sourceview) {
       first_type->code_position_end = (int)ftell(code_file);
       first_type->header_position_end = (int)ftell(header_file);
@@ -585,10 +763,12 @@ int write_code(const char *s, const char *t) {
   }
 
   if (g_project.avoid_early_includes==0) {
-    write_declare("#include <FL/Fl.H>");
+    write_h_once("#include <FL/Fl.H>");
   }
   if (t && g_project.include_H_from_C) {
-    if (g_project.header_file_name[0] == '.' && strchr(g_project.header_file_name, '/') == NULL) {
+    if (to_sourceview) {
+      write_c("#include \"CodeView.h\"\n");
+    } else if (g_project.header_file_name[0] == '.' && strchr(g_project.header_file_name, '/') == NULL) {
       write_c("#include \"%s\"\n", fl_filename_name(t));
     } else {
       write_c("#include \"%s\"\n", t);
@@ -641,14 +821,14 @@ int write_code(const char *s, const char *t) {
   for (Fl_Type* p = first_type; p;) {
     // write all static data for this & all children first
     if (write_sourceview) p->header_position = (int)ftell(header_file);
-    p->write_static();
+    p->write_static(*this);
     if (write_sourceview) {
       p->header_position_end = (int)ftell(header_file);
       if (p->header_position==p->header_position_end) p->header_position_end = -1;
     }
     for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) {
       if (write_sourceview) q->header_position = (int)ftell(header_file);
-      q->write_static();
+      q->write_static(*this);
       if (write_sourceview) {
         q->header_position_end = (int)ftell(header_file);
         if (q->header_position==q->header_position_end) q->header_position_end = -1;
@@ -658,8 +838,6 @@ int write_code(const char *s, const char *t) {
     p = write_code(p);
   }
 
-  delete included_root; included_root = 0;
-
   if (!s) return 1;
 
   fprintf(header_file, "#endif\n");
@@ -670,147 +848,29 @@ int write_code(const char *s, const char *t) {
       last_type->code_position = (int)ftell(code_file);
       last_type->header_position = (int)ftell(header_file);
     }
-    last_type->write_code1();
+    last_type->write_code1(*this);
     if (write_sourceview) {
       last_type->code_position_end = (int)ftell(code_file);
       last_type->header_position_end = (int)ftell(header_file);
     }
   }
+  int x = 0, y = 0;
 
-  int x = fclose(code_file);
+  if (code_file != stdout)
+    x = fclose(code_file);
   code_file = 0;
-  int y = fclose(header_file);
+  if (header_file != stdout)
+    y = fclose(header_file);
   header_file = 0;
   return x >= 0 && y >= 0;
 }
 
-int write_strings(const char *sfile) {
-  FILE *fp = fl_fopen(sfile, "w");
-  Fl_Type *p;
-  Fl_Widget_Type *w;
-  int i;
-
-  if (!fp) return 1;
-
-  switch (g_project.i18n_type) {
-  case 0 : /* None, just put static text out */
-      fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
-              FL_VERSION);
-      for (p = Fl_Type::first; p; p = p->next) {
-        if (p->is_widget()) {
-          w = (Fl_Widget_Type *)p;
-
-          if (w->label()) {
-            for (const char *s = w->label(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            putc('\n', fp);
-          }
-
-          if (w->tooltip()) {
-            for (const char *s = w->tooltip(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            putc('\n', fp);
-          }
-        }
-      }
-      break;
-  case 1 : /* GNU gettext, put a .po file out */
-      fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
-              FL_VERSION);
-      for (p = Fl_Type::first; p; p = p->next) {
-        if (p->is_widget()) {
-          w = (Fl_Widget_Type *)p;
-
-          if (w->label()) {
-            const char *s;
-
-            fputs("msgid \"", fp);
-            for (s = w->label(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-
-            fputs("msgstr \"", fp);
-            for (s = w->label(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-          }
-
-          if (w->tooltip()) {
-            const char *s;
-
-            fputs("msgid \"", fp);
-            for (s = w->tooltip(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-
-            fputs("msgstr \"", fp);
-            for (s = w->tooltip(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-          }
-        }
-      }
-      break;
-  case 2 : /* POSIX catgets, put a .msg file out */
-      fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
-              FL_VERSION);
-      fprintf(fp, "$set %s\n", g_project.i18n_set.value());
-      fputs("$quote \"\n", fp);
-
-      for (i = 1, p = Fl_Type::first; p; p = p->next) {
-        if (p->is_widget()) {
-          w = (Fl_Widget_Type *)p;
-
-          if (w->label()) {
-            fprintf(fp, "%d \"", i ++);
-            for (const char *s = w->label(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-          }
-
-          if (w->tooltip()) {
-            fprintf(fp, "%d \"", i ++);
-            for (const char *s = w->tooltip(); *s; s ++)
-              if (*s < 32 || *s > 126 || *s == '\"')
-                fprintf(fp, "\\%03o", *s);
-              else
-                putc(*s, fp);
-            fputs("\"\n", fp);
-          }
-        }
-      }
-      break;
-  }
-
-  return fclose(fp);
-}
 
 /**
  Write the public/private/protected keywords inside the class.
  This avoids repeating these words if the mode is already set.
  */
-void write_public(int state) {
+void Fd_Code_Writer::write_public(int state) {
   if (!current_class && !current_widget_class) return;
   if (current_class && current_class->write_public_state == state) return;
   if (current_widget_class && current_widget_class->write_public_state == state) return;
@@ -823,5 +883,27 @@ void write_public(int state) {
   }
 }
 
+
+Fd_Code_Writer::Fd_Code_Writer()
+: code_file(NULL),
+  header_file(NULL),
+  id_root(NULL),
+  text_in_header(NULL),
+  text_in_code(NULL),
+  ptr_in_code(NULL),
+  indentation(0),
+  write_sourceview(false),
+  varused_test(0),
+  varused(0)
+{
+}
+
+Fd_Code_Writer::~Fd_Code_Writer()
+{
+  delete ptr_in_code;
+  delete text_in_code;
+  delete text_in_header;
+}
+
 /// \}
 
diff --git fluid/code.h fluid/code.h
index 5e9a702..1b59607 100644
--- fluid/code.h
+++ fluid/code.h
@@ -20,28 +20,59 @@
 #include <FL/fl_attr.h>
 
 #include <stdarg.h>
+#include <stdio.h>
 
-extern int indentation;
-extern int write_number;
-extern int write_sourceview;
+class Fl_Type;
+struct Fd_Identifier_Tree;
+struct Fd_Text_Tree;
+struct Fd_Pointer_Tree;
 
 int is_id(char c);
-const char* unique_id(void* o, const char*, const char*, const char*);
-const char *indent();
-const char *indent(int set);
-const char *indent_plus(int offset);
-int write_declare(const char *, ...) __fl_attr((__format__ (__printf__, 1, 2)));
-void write_cstring(const char *,int length);
-void write_cstring(const char *);
-void write_cdata(const char *,int length);
-void vwrite_c(const char* format, va_list args);
-void write_c(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2)));
-void write_cc(const char *, int, const char*, const char*);
-void write_h(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2)));
-void write_hc(const char *, int, const char*, const char*);
-void write_c_indented(const char *textlines, int inIndent, char inTrailwWith);
-int write_code(const char *cfile, const char *hfile);
 int write_strings(const char *sfile);
-void write_public(int state); // writes pubic:/private: as needed
+
+class Fd_Code_Writer
+{
+protected:
+  FILE *code_file;
+  FILE *header_file;
+  Fd_Identifier_Tree* id_root;
+  Fd_Text_Tree *text_in_header;
+  Fd_Text_Tree *text_in_code;
+  Fd_Pointer_Tree *ptr_in_code;
+
+public:
+  int indentation;
+  bool write_sourceview;
+  // silly thing to prevent declaring unused variables:
+  // When this symbol is on, all attempts to write code don't write
+  // anything, but set a variable if it looks like the variable "o" is used:
+  int varused_test;
+  int varused;
+
+public:
+  Fd_Code_Writer();
+  ~Fd_Code_Writer();
+  const char* unique_id(void* o, const char*, const char*, const char*);
+  void indent_more() { indentation++; }
+  void indent_less() { indentation--; }
+  const char *indent();
+  const char *indent(int set);
+  const char *indent_plus(int offset);
+  int write_h_once(const char *, ...) __fl_attr((__format__ (__printf__, 2, 3)));
+  int write_c_once(const char *, ...) __fl_attr((__format__ (__printf__, 2, 3)));
+  bool c_contains(void* ptr);
+  void write_cstring(const char *,int length);
+  void write_cstring(const char *);
+  void write_cdata(const char *,int length);
+  void vwrite_c(const char* format, va_list args);
+  void write_c(const char*, ...) __fl_attr((__format__ (__printf__, 2, 3)));
+  void write_cc(const char *, int, const char*, const char*);
+  void write_h(const char*, ...) __fl_attr((__format__ (__printf__, 2, 3)));
+  void write_hc(const char *, int, const char*, const char*);
+  void write_c_indented(const char *textlines, int inIndent, char inTrailwWith);
+  Fl_Type* write_code(Fl_Type* p);
+  int write_code(const char *cfile, const char *hfile, bool to_sourceview=false);
+  void write_public(int state); // writes pubic:/private: as needed
+};
 
 #endif // _FLUID_CODE_H
diff --git fluid/file.cxx fluid/file.cxx
index cf457aa..d8920e1 100644
--- fluid/file.cxx
+++ fluid/file.cxx
@@ -6,7 +6,7 @@
 // They are somewhat similar to tcl, using matching { and }
 // to quote strings.
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -30,6 +30,7 @@
 #include "widget_browser.h"
 #include "shell_command.h"
 #include "code.h"
+#include "undo.h"
 
 #include <FL/Fl.H>
 #include <FL/Fl_Group.H>
@@ -41,147 +42,104 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
-/// \defgroup flfile .fl Design File Operations
+/// \defgroup flfile .fl Project File Operations
 /// \{
 
 // This file contains code to read and write .fl files.
-// TODO: there is a name confusion with routines that write to the C and Header
-// TODO: files vs. those that write to the .fl file which should be fixed.
 
-static FILE *fout;
-static FILE *fin;
+int fdesign_flip = 0;
 
-static int needspace;
-static int lineno;
-static const char *fname;
+/** \brief Read a .fl project file.
 
-int fdesign_flip;
-int fdesign_magic;
+ The .fl file format is documented in `fluid/README_fl.txt`.
 
-double read_version;
-
-////////////////////////////////////////////////////////////////
-// BASIC FILE WRITING:
-
-/**
- Open the .fl design file for writing.
- If the filename is NULL, associate stdout instead.
- \param[in] s the filename or NULL for stdout
- \return 1 if successful. 0 if the operation failed
+ \param[in] filename read this file
+ \param[in] merge if this is set, merge the file into an existing project
+    at Fl_Type::current
+ \param[in] strategy add new nodes after current or as last child
+ \return 0 if the operation failed, 1 if it succeeded
  */
-static int open_write(const char *s) {
-  if (!s) {fout = stdout; return 1;}
-  FILE *f = fl_fopen(s,"w");
-  if (!f) return 0;
-  fout = f;
-  return 1;
+int read_file(const char *filename, int merge, Strategy strategy) {
+  Fd_Project_Reader f;
+  return f.read_project(filename, merge, strategy);
 }
 
-/**
- Close the .fl design file.
- Don't close, if data was sent to stdout.
- */
-static int close_write() {
-  if (fout != stdout) {
-    int x = fclose(fout);
-    fout = stdout;
-    return x >= 0;
-  }
-  return 1;
-}
+/** \brief Write an .fl design description file.
 
-/**
- Write a string to the .fl file, quoting characters if necessary.
- */
-void write_word(const char *w) {
-  if (needspace) putc(' ', fout);
-  needspace = 1;
-  if (!w || !*w) {fprintf(fout,"{}"); return;}
-  const char *p;
-  // see if it is a single word:
-  for (p = w; is_id(*p); p++) ;
-  if (!*p) {fprintf(fout,"%s",w); return;}
-  // see if there are matching braces:
-  int n = 0;
-  for (p = w; *p; p++) {
-    if (*p == '{') n++;
-    else if (*p == '}') {n--; if (n<0) break;}
-  }
-  int mismatched = (n != 0);
-  // write out brace-quoted string:
-  putc('{', fout);
-  for (; *w; w++) {
-    switch (*w) {
-    case '{':
-    case '}':
-      if (!mismatched) break;
-    case '\\':
-    case '#':
-      putc('\\',fout);
-      break;
-    }
-    putc(*w,fout);
-  }
-  putc('}', fout);
-}
+ The .fl file format is documented in `fluid/README_fl.txt`.
 
-/**
- Write an arbitrary formatted word to the .fl file, or a comment, etc .
- If needspace is set, then one space is written before the string
- unless the format starts with a newline character \\n.
+ \param[in] filename create this file, and if it exists, overwrite it
+ \param[in] selected_only write only the selected nodes in the widget_tree. This
+    is used to implement copy and paste.
+ \return 0 if the operation failed, 1 if it succeeded
  */
-void write_string(const char *format, ...) {
-  va_list args;
-  va_start(args, format);
-  if (needspace && *format != '\n') fputc(' ',fout);
-  vfprintf(fout, format, args);
-  va_end(args);
-  needspace = !isspace(format[strlen(format)-1] & 255);
+int write_file(const char *filename, int selected_only) {
+  Fd_Project_Writer out;
+  return out.write_project(filename, selected_only);
 }
 
 /**
- Start a new line in the .fl file and indent it for a given nesting level.
+ Convert a single ASCII char, assumed to be a hex digit, into its decimal value.
  */
-void write_indent(int n) {
-  fputc('\n',fout);
-  while (n--) {fputc(' ',fout); fputc(' ',fout);}
-  needspace = 0;
+static int hexdigit(int x) {
+  if (isdigit(x)) return x-'0';
+  if (isupper(x)) return x-'A'+10;
+  if (islower(x)) return x-'a'+10;
+  return 20;
 }
 
-/**
- Write a '{' to the .fl file at the given indenting level.
- */
-void write_open(int) {
-  if (needspace) fputc(' ',fout);
-  fputc('{',fout);
-  needspace = 0;
-}
+// ---- Fd_Project_Reader ---------------------------------------------- MARK: -
 
 /**
- Write a '}' to the .fl file at the given indenting level.
+ A simple growing buffer.
+ Oh how I wish sometimes we would upgrade to modern C++.
  */
-void write_close(int n) {
-  if (needspace) write_indent(n);
-  fputc('}',fout);
-  needspace = 1;
+void Fd_Project_Reader::expand_buffer(int length) {
+  if (length >= buflen) {
+    if (!buflen) {
+      buflen = length+1;
+      buffer = (char*)malloc(buflen);
+    } else {
+      buflen = 2*buflen;
+      if (length >= buflen) buflen = length+1;
+      buffer = (char *)realloc((void *)buffer,buflen);
+    }
+  }
 }
 
+/** \brief Construct local project reader. */
+Fd_Project_Reader::Fd_Project_Reader()
+: fin(NULL),
+  lineno(0),
+  fname(NULL),
+  buffer(NULL),
+  buflen(0),
+  read_version(0.0)
+{
+}
 
-////////////////////////////////////////////////////////////////
-// BASIC FILE READING:
+/** \brief Release project reader resources. */
+Fd_Project_Reader::~Fd_Project_Reader()
+{
+}
 
 /**
  Open an .fl file for reading.
  \param[in] s filename, if NULL, read from stdin instead
  \return 0 if the operation failed, 1 if it succeeded
  */
-static int open_read(const char *s) {
+int Fd_Project_Reader::open_read(const char *s) {
   lineno = 1;
-  if (!s) {fin = stdin; fname = "stdin"; return 1;}
-  FILE *f = fl_fopen(s,"r");
-  if (!f) return 0;
-  fin = f;
-  fname = s;
+  if (!s) {
+    fin = stdin;
+    fname = "stdin";
+  } else {
+    FILE *f = fl_fopen(s,"r");
+    if (!f)
+      return 0;
+    fin = f;
+    fname = s;
+  }
   return 1;
 }
 
@@ -189,7 +147,7 @@ static int open_read(const char *s) {
  Close the .fl file.
  \return 0 if the operation failed, 1 if it succeeded
  */
-static int close_read() {
+int Fd_Project_Reader::close_read() {
   if (fin != stdin) {
     int x = fclose(fin);
     fin = 0;
@@ -199,250 +157,43 @@ static int close_read() {
 }
 
 /**
- Display an error while reading the file.
- If the .fl file isn't opened for reading, pop up an FLTK dialog, otherwise
- print to stdout.
- \note Matt: I am not sure why it is done this way. Shouldn;t this depend on \c batch_mode?
- */
-void read_error(const char *format, ...) {
-  va_list args;
-  va_start(args, format);
-  if (!fin) {
-    char buffer[1024];
-    vsnprintf(buffer, sizeof(buffer), format, args);
-    fl_message("%s", buffer);
-  } else {
-    fprintf(stderr, "%s:%d: ", fname, lineno);
-    vfprintf(stderr, format, args);
-    fprintf(stderr, "\n");
-  }
-  va_end(args);
-}
-
-/**
- Convert a single ASCII char, assumed to be a hex digit, into its decimal value.
- */
-static int hexdigit(int x) {
-  if (isdigit(x)) return x-'0';
-  if (isupper(x)) return x-'A'+10;
-  if (islower(x)) return x-'a'+10;
-  return 20;
-}
-
-/**
  Convert an ASCII sequence form the \.fl file that starts with a \\ into a single character.
  Conversion includes the common C style \\ characters like \\n, \\x## hex
  values, and \\o### octal values.
  */
-static int read_quoted() {      // read whatever character is after a \ .
+int Fd_Project_Reader::read_quoted() {      // read whatever character is after a \ .
   int c,d,x;
   switch(c = fgetc(fin)) {
-  case '\n': lineno++; return -1;
-  case 'a' : return('\a');
-  case 'b' : return('\b');
-  case 'f' : return('\f');
-  case 'n' : return('\n');
-  case 'r' : return('\r');
-  case 't' : return('\t');
-  case 'v' : return('\v');
-  case 'x' :    /* read hex */
-    for (c=x=0; x<3; x++) {
-      int ch = fgetc(fin);
-      d = hexdigit(ch);
-      if (d > 15) {ungetc(ch,fin); break;}
-      c = (c<<4)+d;
-    }
-    break;
-  default:              /* read octal */
-    if (c<'0' || c>'7') break;
-    c -= '0';
-    for (x=0; x<2; x++) {
-      int ch = fgetc(fin);
-      d = hexdigit(ch);
-      if (d>7) {ungetc(ch,fin); break;}
-      c = (c<<3)+d;
-    }
-    break;
-  }
-  return(c);
-}
-
-static char *buffer;
-static int buflen;
-
-/**
- A simple growing buffer.
- Oh how I wish sometimes we would upgrade to modern C++.
- */
-static void expand_buffer(int length) {
-  if (length >= buflen) {
-    if (!buflen) {
-      buflen = length+1;
-      buffer = (char*)malloc(buflen);
-    } else {
-      buflen = 2*buflen;
-      if (length >= buflen) buflen = length+1;
-      buffer = (char *)realloc((void *)buffer,buflen);
-    }
-  }
-}
-
-/**
- Return a word read from the .fl file, or NULL at the EOF.
-
- This will skip all comments (# to end of line), and evaluate
- all \\xxx sequences and use \\ at the end of line to remove the newline.
-
- A word is any one of:
-  - a continuous string of non-space chars except { and } and #
-  - everything between matching {...} (unless wantbrace != 0)
-  - the characters '{' and '}'
- */
-const char *read_word(int wantbrace) {
-  int x;
-
-  // skip all the whitespace before it:
-  for (;;) {
-    x = getc(fin);
-    if (x < 0 && feof(fin)) {   // eof
-      return 0;
-    } else if (x == '#') {      // comment
-      do x = getc(fin); while (x >= 0 && x != '\n');
-      lineno++;
-      continue;
-    } else if (x == '\n') {
-      lineno++;
-    } else if (!isspace(x & 255)) {
+    case '\n': lineno++; return -1;
+    case 'a' : return('\a');
+    case 'b' : return('\b');
+    case 'f' : return('\f');
+    case 'n' : return('\n');
+    case 'r' : return('\r');
+    case 't' : return('\t');
+    case 'v' : return('\v');
+    case 'x' :    /* read hex */
+      for (c=x=0; x<3; x++) {
+        int ch = fgetc(fin);
+        d = hexdigit(ch);
+        if (d > 15) {ungetc(ch,fin); break;}
+        c = (c<<4)+d;
+      }
+      break;
+    default:              /* read octal */
+      if (c<'0' || c>'7') break;
+      c -= '0';
+      for (x=0; x<2; x++) {
+        int ch = fgetc(fin);
+        d = hexdigit(ch);
+        if (d>7) {ungetc(ch,fin); break;}
+        c = (c<<3)+d;
+      }
       break;
-    }
-  }
-
-  expand_buffer(100);
-
-  if (x == '{' && !wantbrace) {
-
-    // read in whatever is between braces
-    int length = 0;
-    int nesting = 0;
-    for (;;) {
-      x = getc(fin);
-      if (x<0) {read_error("Missing '}'"); break;}
-      else if (x == '#') { // embedded comment
-        do x = getc(fin); while (x >= 0 && x != '\n');
-        lineno++;
-        continue;
-      } else if (x == '\n') lineno++;
-      else if (x == '\\') {x = read_quoted(); if (x<0) continue;}
-      else if (x == '{') nesting++;
-      else if (x == '}') {if (!nesting--) break;}
-      buffer[length++] = x;
-      expand_buffer(length);
-    }
-    buffer[length] = 0;
-    return buffer;
-
-  } else if (x == '{' || x == '}') {
-    // all the punctuation is a word:
-    buffer[0] = x;
-    buffer[1] = 0;
-    return buffer;
-
-  } else {
-
-    // read in an unquoted word:
-    int length = 0;
-    for (;;) {
-      if (x == '\\') {x = read_quoted(); if (x<0) continue;}
-      else if (x<0 || isspace(x & 255) || x=='{' || x=='}' || x=='#') break;
-      buffer[length++] = x;
-      expand_buffer(length);
-      x = getc(fin);
-    }
-    ungetc(x, fin);
-    buffer[length] = 0;
-    return buffer;
-
-  }
-}
-
-////////////////////////////////////////////////////////////////
-
-/**
- Write an .fl design description file.
- \param[in] filename create this file, and if it exists, overwrite it
- \param[in] selected_only write only the selected nodes in the widget_tree. This
-    is used to implement copy and paste.
- */
-int write_file(const char *filename, int selected_only) {
-  if (!open_write(filename)) return 0;
-  write_string("# data file for the Fltk User Interface Designer (fluid)\n"
-               "version %.4f",FL_VERSION);
-  if(!g_project.include_H_from_C)
-    write_string("\ndo_not_include_H_from_C");
-  if(g_project.use_FL_COMMAND)
-    write_string("\nuse_FL_COMMAND");
-  if (g_project.utf8_in_src)
-    write_string("\nutf8_in_src");
-  if (g_project.avoid_early_includes)
-    write_string("\navoid_early_includes");
-  if (g_project.i18n_type) {
-    write_string("\ni18n_type %d", g_project.i18n_type);
-    write_string("\ni18n_include"); write_word(g_project.i18n_include);
-    write_string("\ni18n_conditional"); write_word(g_project.i18n_conditional);
-    switch (g_project.i18n_type) {
-    case 1 : /* GNU gettext */
-        write_string("\ni18n_function"); write_word(g_project.i18n_function);
-        write_string("\ni18n_static_function"); write_word(g_project.i18n_static_function);
-        break;
-    case 2 : /* POSIX catgets */
-        if (g_project.i18n_file[0]) {
-          write_string("\ni18n_file");
-          write_word(g_project.i18n_file);
-        }
-        write_string("\ni18n_set"); write_word(g_project.i18n_set);
-        break;
-    }
-  }
-
-  if (!selected_only) {
-    write_string("\nheader_name"); write_word(g_project.header_file_name);
-    write_string("\ncode_name"); write_word(g_project.code_file_name);
-
-#if 0
-    // https://github.com/fltk/fltk/issues/328
-    // Project wide settings require a redesign.
-    shell_settings_write();
-    if (shell_settings_windows.command) {
-      write_string("\nwin_shell_cmd"); write_word(shell_settings_windows.command);
-      write_string("\nwin_shell_flags"); write_string("%d", shell_settings_windows.flags);
-    }
-    if (shell_settings_linux.command) {
-      write_string("\nlinux_shell_cmd"); write_word(shell_settings_linux.command);
-      write_string("\nlinux_shell_flags"); write_string("%d", shell_settings_linux.flags);
-    }
-    if (shell_settings_macos.command) {
-      write_string("\nmac_shell_cmd"); write_word(shell_settings_macos.command);
-      write_string("\nmac_shell_flags"); write_string("%d", shell_settings_macos.flags);
-    }
-#endif
-  }
-
-  for (Fl_Type *p = Fl_Type::first; p;) {
-    if (!selected_only || p->selected) {
-      p->write();
-      write_string("\n");
-      int q = p->level;
-      for (p = p->next; p && p->level > q; p = p->next) {/*empty*/}
-    } else {
-      p = p->next;
-    }
   }
-  return close_write();
+  return(c);
 }
 
-////////////////////////////////////////////////////////////////
-// read all the objects out of the input file:
-
 /**
  Recursively read child nodes in the .fl design file.
 
@@ -452,9 +203,9 @@ int write_file(const char *filename, int selected_only) {
  \param[in] paste if set, merge into existing design, else replace design
  \param[in] strategy add nodes after current or as last child
  \param[in] skip_options this is set if the options were already found in
-    a previous call, and there is no need to waste time searchingg for them.
+ a previous call, and there is no need to waste time searchingg for them.
  */
-static void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_options=0) {
+void Fd_Project_Reader::read_children(Fl_Type *p, int paste, Strategy strategy, char skip_options) {
   Fl_Type::current = p;
   for (;;) {
     const char *c = read_word();
@@ -605,71 +356,171 @@ static void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_op
         c = read_word(1);
       }
 
-      if (strcmp(c,"{")) {
-        read_error("Missing property list for %s\n",t->title());
-        goto REUSE_C;
-      }
+      if (strcmp(c,"{")) {
+        read_error("Missing property list for %s\n",t->title());
+        goto REUSE_C;
+      }
+
+      t->open_ = 0;
+      for (;;) {
+        const char *cc = read_word();
+        if (!cc || !strcmp(cc,"}")) break;
+        t->read_property(*this, cc);
+      }
+
+      if (!t->is_parent()) continue;
+      c = read_word(1);
+      if (strcmp(c,"{")) {
+        read_error("Missing child list for %s\n",t->title());
+        goto REUSE_C;
+      }
+      read_children(t, 0, strategy, skip_options);
+      t->postprocess_read();
+    }
+
+    Fl_Type::current = p;
+
+  CONTINUE:;
+  }
+}
+
+/** \brief Read a .fl project file.
+ \param[in] filename read this file
+ \param[in] merge if this is set, merge the file into an existing project
+ at Fl_Type::current
+ \param[in] strategy add new nodes after current or as last child
+ \return 0 if the operation failed, 1 if it succeeded
+ */
+int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy strategy) {
+  Fl_Type *o;
+  undo_suspend();
+  read_version = 0.0;
+  if (!open_read(filename)) {
+    undo_resume();
+    return 0;
+  }
+  if (merge)
+    deselect();
+  else
+    g_project.reset();
+  read_children(Fl_Type::current, merge, strategy);
+  Fl_Type::current = 0;
+  // Force menu items to be rebuilt...
+  for (o = Fl_Type::first; o; o = o->next)
+    if (o->is_menu_button())
+      o->add_child(0,0);
+  for (o = Fl_Type::first; o; o = o->next)
+    if (o->selected) {
+      Fl_Type::current = o;
+      break;
+    }
+  selection_changed(Fl_Type::current);
+  shell_settings_read();
+  int ret = close_read();
+  undo_resume();
+  return ret;
+}
+
+/**
+ Display an error while reading the file.
+ If the .fl file isn't opened for reading, pop up an FLTK dialog, otherwise
+ print to stdout.
+ \note Matt: I am not sure why it is done this way. Shouldn't this depend on \c batch_mode?
+ */
+void Fd_Project_Reader::read_error(const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  if (!fin) {
+    char buffer[1024];
+    vsnprintf(buffer, sizeof(buffer), format, args);
+    fl_message("%s", buffer);
+  } else {
+    fprintf(stderr, "%s:%d: ", fname, lineno);
+    vfprintf(stderr, format, args);
+    fprintf(stderr, "\n");
+  }
+  va_end(args);
+}
+
+/**
+ Return a word read from the .fl file, or NULL at the EOF.
+
+ This will skip all comments (# to end of line), and evaluate
+ all \\xxx sequences and use \\ at the end of line to remove the newline.
+
+ A word is any one of:
+ - a continuous string of non-space chars except { and } and #
+ - everything between matching {...} (unless wantbrace != 0)
+ - the characters '{' and '}'
+ */
+const char *Fd_Project_Reader::read_word(int wantbrace) {
+  int x;
+
+  // skip all the whitespace before it:
+  for (;;) {
+    x = getc(fin);
+    if (x < 0 && feof(fin)) {   // eof
+      return 0;
+    } else if (x == '#') {      // comment
+      do x = getc(fin); while (x >= 0 && x != '\n');
+      lineno++;
+      continue;
+    } else if (x == '\n') {
+      lineno++;
+    } else if (!isspace(x & 255)) {
+      break;
+    }
+  }
+
+  expand_buffer(100);
 
-      t->open_ = 0;
-      for (;;) {
-        const char *cc = read_word();
-        if (!cc || !strcmp(cc,"}")) break;
-        t->read_property(cc);
-      }
+  if (x == '{' && !wantbrace) {
 
-      if (!t->is_parent()) continue;
-      c = read_word(1);
-      if (strcmp(c,"{")) {
-        read_error("Missing child list for %s\n",t->title());
-        goto REUSE_C;
-      }
-      read_children(t, 0, strategy, skip_options);
-      t->postprocess_read();
+    // read in whatever is between braces
+    int length = 0;
+    int nesting = 0;
+    for (;;) {
+      x = getc(fin);
+      if (x<0) {read_error("Missing '}'"); break;}
+      else if (x == '#') { // embedded comment
+        do x = getc(fin); while (x >= 0 && x != '\n');
+        lineno++;
+        continue;
+      } else if (x == '\n') lineno++;
+      else if (x == '\\') {x = read_quoted(); if (x<0) continue;}
+      else if (x == '{') nesting++;
+      else if (x == '}') {if (!nesting--) break;}
+      buffer[length++] = x;
+      expand_buffer(length);
     }
+    buffer[length] = 0;
+    return buffer;
 
-    Fl_Type::current = p;
+  } else if (x == '{' || x == '}') {
+    // all the punctuation is a word:
+    buffer[0] = x;
+    buffer[1] = 0;
+    return buffer;
 
-  CONTINUE:;
-  }
-}
+  } else {
 
-/**
- Read a .fl design file.
- \param[in] filename read this file
- \param[in] merge if this is set, merge the file into an existing design
-    at Fl_Type::current
- \param[in] strategy add new nodes after current or as last child
- \return 0 if the operation failed, 1 if it succeeded
- */
-int read_file(const char *filename, int merge, Strategy strategy) {
-  Fl_Type *o;
-  read_version = 0.0;
-  if (!open_read(filename))
-    return 0;
-  if (merge)
-    deselect();
-  else
-    g_project.reset();
-  read_children(Fl_Type::current, merge, strategy);
-  Fl_Type::current = 0;
-  // Force menu items to be rebuilt...
-  for (o = Fl_Type::first; o; o = o->next)
-    if (o->is_menu_button())
-      o->add_child(0,0);
-  for (o = Fl_Type::first; o; o = o->next)
-    if (o->selected) {
-      Fl_Type::current = o;
-      break;
+    // read in an unquoted word:
+    int length = 0;
+    for (;;) {
+      if (x == '\\') {x = read_quoted(); if (x<0) continue;}
+      else if (x<0 || isspace(x & 255) || x=='{' || x=='}' || x=='#') break;
+      buffer[length++] = x;
+      expand_buffer(length);
+      x = getc(fin);
     }
-  selection_changed(Fl_Type::current);
-  shell_settings_read();
-  return close_read();
-}
+    ungetc(x, fin);
+    buffer[length] = 0;
+    return buffer;
 
-////////////////////////////////////////////////////////////////
-// Read Forms and XForms fdesign files:
+  }
+}
 
-static int read_fdesign_line(const char*& name, const char*& value) {
+int Fd_Project_Reader::read_fdesign_line(const char*& name, const char*& value) {
   int length = 0;
   int x;
   // find a colon:
@@ -707,53 +558,53 @@ static int read_fdesign_line(const char*& name, const char*& value) {
 }
 
 static const char *class_matcher[] = {
-"FL_CHECKBUTTON", "Fl_Check_Button",
-"FL_ROUNDBUTTON", "Fl_Round_Button",
-"FL_ROUND3DBUTTON", "Fl_Round_Button",
-"FL_LIGHTBUTTON", "Fl_Light_Button",
-"FL_FRAME", "Fl_Box",
-"FL_LABELFRAME", "Fl_Box",
-"FL_TEXT", "Fl_Box",
-"FL_VALSLIDER", "Fl_Value_Slider",
-"FL_MENU", "Fl_Menu_Button",
-"3", "FL_BITMAP",
-"1", "FL_BOX",
-"71","FL_BROWSER",
-"11","FL_BUTTON",
-"4", "FL_CHART",
-"42","FL_CHOICE",
-"61","FL_CLOCK",
-"25","FL_COUNTER",
-"22","FL_DIAL",
-"101","FL_FREE",
-"31","FL_INPUT",
-"12","Fl_Light_Button",
-"41","FL_MENU",
-"23","FL_POSITIONER",
-"13","Fl_Round_Button",
-"21","FL_SLIDER",
-"2", "FL_BOX", // was FL_TEXT
-"62","FL_TIMER",
-"24","Fl_Value_Slider",
-0};
+  "FL_CHECKBUTTON", "Fl_Check_Button",
+  "FL_ROUNDBUTTON", "Fl_Round_Button",
+  "FL_ROUND3DBUTTON", "Fl_Round_Button",
+  "FL_LIGHTBUTTON", "Fl_Light_Button",
+  "FL_FRAME", "Fl_Box",
+  "FL_LABELFRAME", "Fl_Box",
+  "FL_TEXT", "Fl_Box",
+  "FL_VALSLIDER", "Fl_Value_Slider",
+  "FL_MENU", "Fl_Menu_Button",
+  "3", "FL_BITMAP",
+  "1", "FL_BOX",
+  "71","FL_BROWSER",
+  "11","FL_BUTTON",
+  "4", "FL_CHART",
+  "42","FL_CHOICE",
+  "61","FL_CLOCK",
+  "25","FL_COUNTER",
+  "22","FL_DIAL",
+  "101","FL_FREE",
+  "31","FL_INPUT",
+  "12","Fl_Light_Button",
+  "41","FL_MENU",
+  "23","FL_POSITIONER",
+  "13","Fl_Round_Button",
+  "21","FL_SLIDER",
+  "2", "FL_BOX", // was FL_TEXT
+  "62","FL_TIMER",
+  "24","Fl_Value_Slider",
+  0};
 
 
 /**
-  Finish a group of widgets and optionally transform its children's coordinates.
+ Finish a group of widgets and optionally transform its children's coordinates.
 
-  Implements the same functionality as Fl_Group::forms_end() from the forms
-  compatibility library would have done:
+ Implements the same functionality as Fl_Group::forms_end() from the forms
+ compatibility library would have done:
 
-  - resize the group to surround its children if the group's w() == 0
-  - optionally flip the \p y coordinates of all children relative to the group's window
-  - Fl_Group::end() the group
+ - resize the group to surround its children if the group's w() == 0
+ - optionally flip the \p y coordinates of all children relative to the group's window
+ - Fl_Group::end() the group
 
-  \note Copied from forms_compatibility.cxx and modified as a static fluid
-    function so we don't have to link to fltk_forms.
+ \note Copied from forms_compatibility.cxx and modified as a static fluid
+ function so we don't have to link to fltk_forms.
 
-  \param[in]  g     the Fl_Group widget
-  \param[in]  flip  flip children's \p y coordinates if true (non-zero)
-*/
+ \param[in]  g     the Fl_Group widget
+ \param[in]  flip  flip children's \p y coordinates if true (non-zero)
+ */
 static void forms_end(Fl_Group *g, int flip) {
   // set the dimensions of a group to surround its contents
   const int nc = g->children();
@@ -794,8 +645,8 @@ static void forms_end(Fl_Group *g, int flip) {
  FLTK widgets.
  \see http://xforms-toolkit.org
  */
-void read_fdesign() {
-  fdesign_magic = atoi(read_word());
+void Fd_Project_Reader::read_fdesign() {
+  int fdesign_magic = atoi(read_word());
   fdesign_flip = (fdesign_magic < 13000);
   Fl_Widget_Type *window = 0;
   Fl_Widget_Type *group = 0;
@@ -849,4 +700,203 @@ void read_fdesign() {
   }
 }
 
+// ---- Fd_Project_Writer ---------------------------------------------- MARK: -
+
+/** \brief Construct local project writer. */
+Fd_Project_Writer::Fd_Project_Writer()
+: fout(NULL),
+  needspace(0)
+{
+}
+
+/** \brief Release project writer resources. */
+Fd_Project_Writer::~Fd_Project_Writer()
+{
+}
+
+/**
+ Open the .fl design file for writing.
+ If the filename is NULL, associate stdout instead.
+ \param[in] s the filename or NULL for stdout
+ \return 1 if successful. 0 if the operation failed
+ */
+int Fd_Project_Writer::open_write(const char *s) {
+  if (!s) {
+    fout = stdout;
+  } else {
+    FILE *f = fl_fopen(s,"w");
+    if (!f) return 0;
+    fout = f;
+  }
+  return 1;
+}
+
+/**
+ Close the .fl design file.
+ Don't close, if data was sent to stdout.
+ */
+int Fd_Project_Writer::close_write() {
+  if (fout != stdout) {
+    int x = fclose(fout);
+    fout = stdout;
+    return x >= 0;
+  }
+  return 1;
+}
+
+/** \brief Write an .fl design description file.
+ \param[in] filename create this file, and if it exists, overwrite it
+ \param[in] selected_only write only the selected nodes in the widget_tree. This
+ is used to implement copy and paste.
+ \return 0 if the operation failed, 1 if it succeeded
+ */
+int Fd_Project_Writer::write_project(const char *filename, int selected_only) {
+  undo_suspend();
+  if (!open_write(filename)) {
+    undo_resume();
+    return 0;
+  }
+  write_string("# data file for the Fltk User Interface Designer (fluid)\n"
+               "version %.4f",FL_VERSION);
+  if(!g_project.include_H_from_C)
+    write_string("\ndo_not_include_H_from_C");
+  if(g_project.use_FL_COMMAND)
+    write_string("\nuse_FL_COMMAND");
+  if (g_project.utf8_in_src)
+    write_string("\nutf8_in_src");
+  if (g_project.avoid_early_includes)
+    write_string("\navoid_early_includes");
+  if (g_project.i18n_type) {
+    write_string("\ni18n_type %d", g_project.i18n_type);
+    write_string("\ni18n_include"); write_word(g_project.i18n_include);
+    write_string("\ni18n_conditional"); write_word(g_project.i18n_conditional);
+    switch (g_project.i18n_type) {
+      case 1 : /* GNU gettext */
+        write_string("\ni18n_function"); write_word(g_project.i18n_function);
+        write_string("\ni18n_static_function"); write_word(g_project.i18n_static_function);
+        break;
+      case 2 : /* POSIX catgets */
+        if (g_project.i18n_file[0]) {
+          write_string("\ni18n_file");
+          write_word(g_project.i18n_file);
+        }
+        write_string("\ni18n_set"); write_word(g_project.i18n_set);
+        break;
+    }
+  }
+
+  if (!selected_only) {
+    write_string("\nheader_name"); write_word(g_project.header_file_name);
+    write_string("\ncode_name"); write_word(g_project.code_file_name);
+
+#if 0
+    // https://github.com/fltk/fltk/issues/328
+    // Project wide settings require a redesign.
+    shell_settings_write();
+    if (shell_settings_windows.command) {
+      write_string("\nwin_shell_cmd"); write_word(shell_settings_windows.command);
+      write_string("\nwin_shell_flags"); write_string("%d", shell_settings_windows.flags);
+    }
+    if (shell_settings_linux.command) {
+      write_string("\nlinux_shell_cmd"); write_word(shell_settings_linux.command);
+      write_string("\nlinux_shell_flags"); write_string("%d", shell_settings_linux.flags);
+    }
+    if (shell_settings_macos.command) {
+      write_string("\nmac_shell_cmd"); write_word(shell_settings_macos.command);
+      write_string("\nmac_shell_flags"); write_string("%d", shell_settings_macos.flags);
+    }
+#endif
+  }
+
+  for (Fl_Type *p = Fl_Type::first; p;) {
+    if (!selected_only || p->selected) {
+      p->write(*this);
+      write_string("\n");
+      int q = p->level;
+      for (p = p->next; p && p->level > q; p = p->next) {/*empty*/}
+    } else {
+      p = p->next;
+    }
+  }
+  int ret = close_write();
+  undo_resume();
+  return ret;
+}
+
+/**
+ Write a string to the .fl file, quoting characters if necessary.
+ */
+void Fd_Project_Writer::write_word(const char *w) {
+  if (needspace) putc(' ', fout);
+  needspace = 1;
+  if (!w || !*w) {fprintf(fout,"{}"); return;}
+  const char *p;
+  // see if it is a single word:
+  for (p = w; is_id(*p); p++) ;
+  if (!*p) {fprintf(fout,"%s",w); return;}
+  // see if there are matching braces:
+  int n = 0;
+  for (p = w; *p; p++) {
+    if (*p == '{') n++;
+    else if (*p == '}') {n--; if (n<0) break;}
+  }
+  int mismatched = (n != 0);
+  // write out brace-quoted string:
+  putc('{', fout);
+  for (; *w; w++) {
+    switch (*w) {
+    case '{':
+    case '}':
+      if (!mismatched) break;
+    case '\\':
+    case '#':
+      putc('\\',fout);
+      break;
+    }
+    putc(*w,fout);
+  }
+  putc('}', fout);
+}
+
+/**
+ Write an arbitrary formatted word to the .fl file, or a comment, etc .
+ If needspace is set, then one space is written before the string
+ unless the format starts with a newline character \\n.
+ */
+void Fd_Project_Writer::write_string(const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  if (needspace && *format != '\n') fputc(' ',fout);
+  vfprintf(fout, format, args);
+  va_end(args);
+  needspace = !isspace(format[strlen(format)-1] & 255);
+}
+
+/**
+ Start a new line in the .fl file and indent it for a given nesting level.
+ */
+void Fd_Project_Writer::write_indent(int n) {
+  fputc('\n',fout);
+  while (n--) {fputc(' ',fout); fputc(' ',fout);}
+  needspace = 0;
+}
+
+/**
+ Write a '{' to the .fl file at the given indenting level.
+ */
+void Fd_Project_Writer::write_open(int) {
+  if (needspace) fputc(' ',fout);
+  fputc('{',fout);
+  needspace = 0;
+}
+
+/**
+ Write a '}' to the .fl file at the given indenting level.
+ */
+void Fd_Project_Writer::write_close(int n) {
+  if (needspace) write_indent(n);
+  fputc('}',fout);
+  needspace = 1;
+}
+
 /// \}
diff --git fluid/file.h fluid/file.h
index 5470d1b..457d14e 100644
--- fluid/file.h
+++ fluid/file.h
@@ -1,7 +1,7 @@
 //
 // Fluid file routines for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -21,22 +21,57 @@
 
 #include <FL/fl_attr.h>
 
-extern double read_version;
+class Fl_Type;
+
 extern int fdesign_flip;
-extern int fdesign_magic;
 
-void write_word(const char *);
-void write_string(const char *,...) __fl_attr((__format__ (__printf__, 1, 2)));
-void write_indent(int n);
-void write_open(int);
-void write_close(int n);
+int read_file(const char *, int merge, Strategy strategy=kAddAsLastChild);
+int write_file(const char *, int selected_only = 0);
 
-void read_error(const char *format, ...);
-const char *read_word(int wantbrace = 0);
+class Fd_Project_Reader
+{
+protected:
+  FILE *fin;
+  int lineno;
+  const char *fname;
+  char *buffer;
+  int buflen;
+  void expand_buffer(int length);
 
-int write_file(const char *, int selected_only = 0);
+public:
+  double read_version;
 
-int read_file(const char *, int merge, Strategy strategy=kAddAsLastChild);
-void read_fdesign();
+public:
+  Fd_Project_Reader();
+  ~Fd_Project_Reader();
+  int open_read(const char *s);
+  int close_read();
+  int read_quoted();
+  void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_options=0);
+  int read_project(const char *, int merge, Strategy strategy=kAddAsLastChild);
+  void read_error(const char *format, ...);
+  const char *read_word(int wantbrace = 0);
+  int read_fdesign_line(const char*& name, const char*& value);
+  void read_fdesign();
+};
+
+class Fd_Project_Writer
+{
+protected:
+  FILE *fout;
+  int needspace;
+
+public:
+  Fd_Project_Writer();
+  ~Fd_Project_Writer();
+  int open_write(const char *s);
+  int close_write();
+  int write_project(const char *filename, int selected_only);
+  void write_word(const char *);
+  void write_string(const char *,...) __fl_attr((__format__ (__printf__, 2, 3)));
+  void write_indent(int n);
+  void write_open(int);
+  void write_close(int n);
+};
 
 #endif // _FLUID_FILE_H
diff --git fluid/fluid.cxx fluid/fluid.cxx
index fdd5b99..56fc38b 100644
--- fluid/fluid.cxx
+++ fluid/fluid.cxx
@@ -981,11 +981,14 @@ void new_from_template_cb(Fl_Widget *w, void *v) {
  with the extension \c code_file_name which are both
  settable by the user.
 
- In batch_mode, the function will either be silent, or write an error message
- to \c stderr and exit with exit code 1.
+ If the code filename has not been set yet, a "save file as" dialog will be
+ presented to the user.
 
- In interactive mode, we will pop up an error message, or, if the user
- hasn't isabled that, pop up a confirmation message.
+ In batch_mode, the function will either be silent, or, if opening or writing
+ the files fails, write an error message to \c stderr and exit with exit code 1.
+
+ In interactive mode, it will pop up an error message, or, if the user
+ hasn't disabled that, pop up a confirmation message.
 
  \return 1 if the operation failed, 0 if it succeeded
  */
@@ -1013,7 +1016,8 @@ int write_code_files() {
     strlcpy(hname, g_project.header_file_name, FL_PATH_MAX);
   }
   if (!batch_mode) enter_project_dir();
-  int x = write_code(cname,hname);
+  Fd_Code_Writer f;
+  int x = f.write_code(cname, hname);
   if (!batch_mode) leave_project_dir();
   strlcat(cname, " and ", FL_PATH_MAX);
   strlcat(cname, hname, FL_PATH_MAX);
@@ -1931,9 +1935,9 @@ void update_sourceview_cb(Fl_Button*, void*)
     g_project.header_file_name = sv_header_filename;
 
     // generate the code and load the files
-    write_sourceview = 1;
+    Fd_Code_Writer f;
     // generate files
-    if (write_code(sv_source_filename, sv_header_filename))
+    if (f.write_code(sv_source_filename, sv_header_filename, true))
     {
       // load file into source editor
       int pos = sv_source->top_line();
@@ -1946,7 +1950,6 @@ void update_sourceview_cb(Fl_Button*, void*)
       // update the source code highlighting
       update_sourceview_position();
     }
-    write_sourceview = 0;
 
     g_project.code_file_name = code_file_name_bak;
     g_project.header_file_name = header_file_name_bak;
diff --git fluid/function_panel.cxx fluid/function_panel.cxx
index 12fd7f4..4c55c26 100644
--- fluid/function_panel.cxx
+++ fluid/function_panel.cxx
@@ -1,7 +1,7 @@
 //
 // Code dialogs for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
diff --git fluid/function_panel.fl fluid/function_panel.fl
index c830de7..a5cf2ae 100644
--- fluid/function_panel.fl
+++ fluid/function_panel.fl
@@ -5,7 +5,7 @@ code_name {.cxx}
 comment {//
 // Code dialogs for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -17,7 +17,7 @@ comment {//
 //
 //     https://www.fltk.org/bugs.php
 //
-} {in_source in_header
+} {selected in_source in_header
 }
 
 decl {\#include "fluid.h"} {private local
@@ -483,7 +483,7 @@ Function {make_comment_panel()} {open
     xywh {780 296 550 280} type Double labelsize 11 resizable
     code0 {o->size_range(320, 180);} modal visible
   } {
-    Fl_Text_Editor comment_input {selected
+    Fl_Text_Editor comment_input {
       xywh {110 10 430 230} box DOWN_BOX labelsize 11 textfont 4 textsize 11 textcolor 58 resizable
       code0 {o->when(FL_WHEN_ENTER_KEY_CHANGED|FL_WHEN_RELEASE);}
       code1 {o->buffer(new Fl_Text_Buffer());}
diff --git fluid/function_panel.h fluid/function_panel.h
index 29562db..0de7230 100644
--- fluid/function_panel.h
+++ fluid/function_panel.h
@@ -1,7 +1,7 @@
 //
 // Code dialogs for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2023 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
diff --git fluid/print_panel.cxx fluid/print_panel.cxx
index 3633c8a..4dec8e7 100644
--- fluid/print_panel.cxx
+++ fluid/print_panel.cxx
@@ -112,6 +112,7 @@ Fl_Menu_Item menu_print_page_size[] = {
 };
 
 #include <FL/Fl_Pixmap.H>
+
 static const char *idata_print_color[] = {
 "24 24 17 1",
 " \tc None",
@@ -157,7 +158,9 @@ static const char *idata_print_color[] = {
 "     %%%%%%  ******     "
 };
 static Fl_Image *image_print_color() {
-  static Fl_Image *image = new Fl_Pixmap(idata_print_color);
+  static Fl_Image *image = NULL;
+  if (!image)
+    image = new Fl_Pixmap(idata_print_color);
   return image;
 }
 
@@ -206,7 +209,9 @@ static const char *idata_print_gray[] = {
 "     %%%%%%  ******     "
 };
 static Fl_Image *image_print_gray() {
-  static Fl_Image *image = new Fl_Pixmap(idata_print_gray);
+  static Fl_Image *image = NULL;
+  if (!image)
+    image = new Fl_Pixmap(idata_print_gray);
   return image;
 }
 
diff --git fluid/print_panel.fl fluid/print_panel.fl
index 8b402d0..eaaefcf 100644
--- fluid/print_panel.fl
+++ fluid/print_panel.fl
@@ -26,7 +26,7 @@ decl {\#include "fluid.h"} {private local
 decl {\#include <FL/fl_string_functions.h>} {private local
 }
 
-decl {\#include "../src/flstring.h"} {private local
+decl {\#include "../src/flstring.h"} {selected private local
 }
 
 decl {\#include <stdlib.h>} {private local
@@ -39,7 +39,7 @@ Function {make_print_panel()} {open
 } {
   Fl_Window print_panel {
     label Print
-    xywh {465 222 465 235} type Double hide modal
+    xywh {465 222 465 235} type Double modal visible
   } {
     Fl_Group print_panel_controls {open
       xywh {10 10 447 216}
@@ -213,7 +213,7 @@ print_collate_group[1 - i]->hide();}
     label {Printer Properties}
     callback {print_properties_panel->hide();
 print_update_status();}
-    xywh {462 486 290 130} type Double hide modal
+    xywh {462 486 290 130} type Double modal visible
   } {
     Fl_Choice print_page_size {
       label {Page Size:}
@@ -233,16 +233,16 @@ print_update_status();}
       xywh {110 45 170 40} labelfont 1 labelsize 12 align 4
     } {
       Fl_Button {print_output_mode[0]} {
-        image {pixmaps/print_color.xpm} xywh {110 45 30 40} type Radio box BORDER_BOX down_box BORDER_BOX value 1 color 7 selection_color 0
+        image {pixmaps/print_color.xpm} compress_image 0 xywh {110 45 30 40} type Radio box BORDER_BOX down_box BORDER_BOX value 1 color 7 selection_color 0
       }
       Fl_Button {print_output_mode[1]} {
-        image {pixmaps/print_color.xpm} xywh {150 50 40 30} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
+        image {pixmaps/print_color.xpm} compress_image 0 xywh {150 50 40 30} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
       }
       Fl_Button {print_output_mode[2]} {
-        image {pixmaps/print_gray.xpm} xywh {200 45 30 40} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
+        image {pixmaps/print_gray.xpm} compress_image 0 xywh {200 45 30 40} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
       }
       Fl_Button {print_output_mode[3]} {
-        image {pixmaps/print_gray.xpm} xywh {240 50 40 30} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
+        image {pixmaps/print_gray.xpm} compress_image 0 xywh {240 50 40 30} type Radio box BORDER_BOX down_box BORDER_BOX color 7 selection_color 0
       }
     }
     Fl_Return_Button {} {
@@ -328,7 +328,7 @@ if (defname[0]) {
 print_update_status();} {}
 }
 
-Function {print_update_status()} {open selected return_type void
+Function {print_update_status()} {open return_type void
 } {
   code {FILE *lpstat;
 char command[1024];
diff --git fluid/template_panel.cxx fluid/template_panel.cxx
index b23bc96..f318b76 100644
--- fluid/template_panel.cxx
+++ fluid/template_panel.cxx
@@ -138,7 +138,7 @@ Fl_Double_Window* make_template_panel() {
       template_browser->labelfont(1);
       template_browser->callback((Fl_Callback*)cb_template_browser);
       template_browser->align(Fl_Align(FL_ALIGN_TOP_LEFT));
-      template_browser->when(3);
+      template_browser->when(FL_WHEN_CHANGED | FL_WHEN_NOT_CHANGED);
     } // Fl_Browser* template_browser
     { template_preview = new Fl_Box(200, 28, 250, 250);
       template_preview->box(FL_THIN_DOWN_BOX);
@@ -149,7 +149,7 @@ Fl_Double_Window* make_template_panel() {
       template_name->labelfont(1);
       template_name->textfont(4);
       template_name->callback((Fl_Callback*)cb_template_name);
-      template_name->when(3);
+      template_name->when(FL_WHEN_CHANGED | FL_WHEN_NOT_CHANGED);
     } // Fl_Input* template_name
     { template_instance = new Fl_Input(198, 288, 252, 25, "Instance Name:");
       template_instance->labelfont(1);
diff --git fluid/widget_browser.cxx fluid/widget_browser.cxx
index b1d799e..ec59d7d 100644
--- fluid/widget_browser.cxx
+++ fluid/widget_browser.cxx
@@ -299,7 +299,7 @@ void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const {
   if (show_comments && l->comment()) {
     copy_trunc(buf, l->comment(), 80, 0);
     comment_incr = textsize()-1;
-    Fl_Color comment_color = fl_color_average(FL_DARK_GREEN, FL_BLACK, 0.9);
+    Fl_Color comment_color = fl_color_average(FL_DARK_GREEN, FL_BLACK, 0.9f);
     if (l->new_selected) fl_color(fl_contrast(comment_color, FL_SELECTION_COLOR));
     else fl_color(fl_contrast(comment_color, color()));
     fl_font(textfont()+FL_ITALIC, textsize()-2);
diff --git fluid/widget_panel.fl fluid/widget_panel.fl
index e36e73a..317b165 100644
--- fluid/widget_panel.fl
+++ fluid/widget_panel.fl
@@ -49,7 +49,7 @@ Function {make_widget_panel()} {
           xywh {95 40 309 20} labelfont 1 labelsize 11 align 4
         } {
           Fl_Input {} {
-            callback label_cb
+            callback label_cb selected
             tooltip {The label text for the widget.
 Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 textsize 11 resizable
           }
@@ -110,7 +110,7 @@ or compressed in the original file format} xywh {364 90 20 20} type Toggle
             code3 {\#include "pixmaps.h"}
           }
           Fl_Button {} {
-            callback bind_deimage_cb selected
+            callback bind_deimage_cb
             tooltip {bind the image to the widget, so it will be deleted automatically} xywh {384 90 20 20} type Toggle
             code0 {o->image(bind_pixmap);}
             code3 {\#include "pixmaps.h"}
diff --git src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
index 6433cf5..e0cbf26 100644
--- src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
+++ src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
@@ -1271,6 +1271,7 @@ double Fl_Cairo_Graphics_Driver::width(unsigned int utf32) {
 
 double Fl_Cairo_Graphics_Driver::width(const char* str, int n) {
   if (!font_descriptor()) return -1;
+  if ((str == NULL) || (n == 0)) return 0.;
   if (n == fl_utf8len(*str)) { // str contains a single unicode character
     int l;
     unsigned c = fl_utf8decode(str, str+n, &l);
diff --git src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
index ea04ca5..9fc98f0 100644
--- src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
+++ src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
@@ -1273,6 +1273,7 @@ double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int utf32) {
 }
 
 double Fl_Xlib_Graphics_Driver::width_unscaled(const char* str, int n) {
+  if ((str == NULL) || (n == 0)) return 0.;
   if (n == fl_utf8len(*str)) { // str contains a single unicode character
     int l;
     unsigned c = fl_utf8decode(str, str+n, &l);
diff --git test/boxtype.cxx test/boxtype.cxx
index 24d176e..a2a92d3 100644
--- test/boxtype.cxx
+++ test/boxtype.cxx
@@ -18,7 +18,7 @@
 #include <stdio.h>
 #include <FL/Fl.H>
 #include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Box.H>
+#include <FL/Fl_Button.H>
 #include <FL/Fl_Scheme_Choice.H>
 #include <FL/fl_draw.H>
 
@@ -82,7 +82,8 @@ void bt(const char *name, Fl_Boxtype type, int square=0) {
   N++;
   x = x*W+10;
   y = y*H+10;
-  Fl_Box *b = new Fl_Box(type,x,y,square ? H-20 : W-20,H-20,name);
+  Fl_Button *b = new Fl_Button(x,y,square ? H-20 : W-20,H-20,name);
+  b->box(type);
   b->labelsize(11);
   if (inactive) {
     b->color(FL_GREEN);
diff --git test/valuators.fl test/valuators.fl
index 1db8083..4883507 100644
--- test/valuators.fl
+++ test/valuators.fl
@@ -37,7 +37,7 @@ Function {} {open
     Fl_Slider {} {
       label FL_HORIZONTAL
       user_data {"Fl_Slider FL_HORIZONTAL"}
-      callback callback
+      callback callback selected
       xywh {140 80 130 20} type Horizontal selection_color 1 labelsize 8
     }
     Fl_Slider {} {
@@ -125,7 +125,7 @@ Function {} {open
     Fl_Scrollbar {} {
       label {FL_VERTICAL (0) ->}
       user_data {"Fl_Scrollbar FL_VERTICAL"}
-      callback callback selected
+      callback callback
       tooltip {Vertical Scrollbar} xywh {405 30 20 90} labelsize 8 align 13 maximum 100 value 20
     }
     Fl_Box {} {
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.