]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/preferences.cpp
reformat code! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / radiant / preferences.cpp
index a691d812770cdd93c22fc26b8c7d2983a1b77f27..fbd9815169fb935bc5bcea1b316638e47eab80ed 100644 (file)
@@ -1,23 +1,23 @@
 /*
-Copyright (C) 1999-2006 Id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
 
-This file is part of GtkRadiant.
+   This file is part of GtkRadiant.
 
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 //
 // User preferences
@@ -26,25 +26,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
 #include "preferences.h"
+#include "globaldefs.h"
+
+#include <gtk/gtk.h>
 #include "environment.h"
 
 #include "debugging/debugging.h"
 
-#include <gtk/gtkmain.h>
-#include <gtk/gtkvbox.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtkframe.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtkspinbutton.h>
-#include <gtk/gtkscrolledwindow.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreeview.h>
-#include <gtk/gtktreestore.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtknotebook.h>
-
 #include "generic/callback.h"
 #include "math/vector.h"
 #include "string/string.h"
@@ -64,113 +52,110 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "gtkdlgs.h"
 
 
-
-void Global_constructPreferences(PreferencesPage& page)
+void Global_constructPreferences(PreferencesPage &page)
 {
-  page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
+    page.appendCheckBox("Console", "Enable Logging", g_Console_enableLogging);
 }
 
-void Interface_constructPreferences(PreferencesPagepage)
+void Interface_constructPreferences(PreferencesPage &page)
 {
-#ifdef WIN32
-  page.appendCheckBox("", "Default Text Editor", g_TextEditor_useWin32Editor);
+#if GDEF_OS_WINDOWS
+    page.appendCheckBox( "", "Default Text Editor", g_TextEditor_useWin32Editor );
 #else
-  {
-    GtkWidget* use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
-    GtkWidget* custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
-    Widget_connectToggleDependency(custom_editor, use_custom);
-  }
+    {
+        ui::CheckButton use_custom = page.appendCheckBox("Text Editor", "Custom", g_TextEditor_useCustomEditor);
+        ui::Widget custom_editor = page.appendPathEntry("Text Editor Command", g_TextEditor_editorCommand, true);
+        Widget_connectToggleDependency(custom_editor, use_custom);
+    }
 #endif
 }
 
-void Mouse_constructPreferences(PreferencesPagepage)
+void Mouse_constructPreferences(PreferencesPage &page)
 {
-  {
-    const char* buttons[] = { "2 button", "3 button", };
-    page.appendRadio("Mouse Type",  g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
-  }
-  page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
+    {
+        const char *buttons[] = {"2 button", "3 button",};
+        page.appendRadio("Mouse Type", g_glwindow_globals.m_nMouseType, STRING_ARRAY_RANGE(buttons));
+    }
+    page.appendCheckBox("Right Button", "Activates Context Menu", g_xywindow_globals.m_bRightClick);
 }
-void Mouse_constructPage(PreferenceGroup& group)
+
+void Mouse_constructPage(PreferenceGroup &group)
 {
-  PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
-  Mouse_constructPreferences(page);
+    PreferencesPage page(group.createPage("Mouse", "Mouse Preferences"));
+    Mouse_constructPreferences(page);
 }
+
 void Mouse_registerPreferencesPage()
 {
-  PreferencesDialog_addInterfacePage(FreeCaller1<PreferenceGroup&, Mouse_constructPage>());
+    PreferencesDialog_addInterfacePage(makeCallbackF(Mouse_constructPage));
 }
 
 
 /*!
-=========================================================
-Games selection dialog
-=========================================================
-*/
+   =========================================================
+   Games selection dialog
+   =========================================================
+ */
 
 #include <map>
+#include <uilib/uilib.h>
 
-inline const charxmlAttr_getName(xmlAttrPtr attr)
+inline const char *xmlAttr_getName(xmlAttrPtr attr)
 {
-  return reinterpret_cast<const char*>(attr->name);
+    return reinterpret_cast<const char *>( attr->name );
 }
 
-inline const charxmlAttr_getValue(xmlAttrPtr attr)
+inline const char *xmlAttr_getValue(xmlAttrPtr attr)
 {
-  return reinterpret_cast<const char*>(attr->children->content);
+    return reinterpret_cast<const char *>( attr->children->content );
 }
 
-CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedStringgameFile)
+CGameDescription::CGameDescription(xmlDocPtr pDoc, const CopiedString &gameFile)
 {
-  // read the user-friendly game name 
-  xmlNodePtr pNode = pDoc->children;
-
-  while (strcmp((const char*)pNode->name, "game") && pNode != 0)
-  {
-    pNode=pNode->next;
-  }
-  if (!pNode)
-  {
-    Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
-  }
-
-  for(xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next)
-  {
-    m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
-  }
-
-  {
-    StringOutputStream path(256);
-    path << AppPath_get() << gameFile.c_str() << "/";
-    mGameToolsPath = path.c_str();
-  }
-
-  ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()), "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
-
-  mGameFile = gameFile;
-  {
-    GameDescription::iterator i = m_gameDescription.find("type");
-    if(i == m_gameDescription.end())
+    // read the user-friendly game name
+    xmlNodePtr pNode = pDoc->children;
+
+    while (strcmp((const char *) pNode->name, "game") && pNode != 0) {
+        pNode = pNode->next;
+    }
+    if (!pNode) {
+        Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL);
+    }
+
+    for (xmlAttrPtr attr = pNode->properties; attr != 0; attr = attr->next) {
+        m_gameDescription.insert(GameDescription::value_type(xmlAttr_getName(attr), xmlAttr_getValue(attr)));
+    }
+
     {
-      globalErrorStream() << "Warning, 'type' attribute not found in '" << reinterpret_cast<const char*>(pDoc->URL) << "'\n";
-      // default
-      mGameType = "q3";
+        StringOutputStream path(256);
+        path << AppPath_get() << gameFile.c_str() << "/";
+        mGameToolsPath = path.c_str();
     }
-    else
+
+    ASSERT_MESSAGE(file_exists(mGameToolsPath.c_str()),
+                   "game directory not found: " << makeQuoted(mGameToolsPath.c_str()));
+
+    mGameFile = gameFile;
+
     {
-      mGameType = (*i).second.c_str();
+        GameDescription::iterator i = m_gameDescription.find("type");
+        if (i == m_gameDescription.end()) {
+            globalErrorStream() << "Warning, 'type' attribute not found in '"
+                                << reinterpret_cast<const char *>( pDoc->URL ) << "'\n";
+            // default
+            mGameType = "q3";
+        } else {
+            mGameType = (*i).second.c_str();
+        }
     }
-  }
 }
 
 void CGameDescription::Dump()
 {
-  globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
-  for(GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i)
-  {
-    globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
-  }
+    globalOutputStream() << "game description file: " << makeQuoted(mGameFile.c_str()) << "\n";
+    for (GameDescription::iterator i = m_gameDescription.begin(); i != m_gameDescription.end(); ++i) {
+        globalOutputStream() << (*i).first.c_str() << " = " << makeQuoted((*i).second.c_str()) << "\n";
+    }
 }
 
 CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentDescription
@@ -186,76 +171,79 @@ CGameDescription *g_pGameDescription; ///< shortcut to g_GamesDialog.m_pCurrentD
 #include "preferencedictionary.h"
 #include "stringio.h"
 
-const charconst PREFERENCES_VERSION = "1.0";
+const char *const PREFERENCES_VERSION = "1.0";
 
-bool Preferences_Load(PreferenceDictionary& preferences, const char* filename, const char *cmdline_prefix)
+bool Preferences_Load(PreferenceDictionary &preferences, const char *filename, const char *cmdline_prefix)
 {
-  bool ret = false;
-  TextFileInputStream file(filename);
-  if(!file.failed())
-  {
-    XMLStreamParser parser(file);
-    XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
-    parser.exportXML(importer);
-    ret = true;
-  }
-
-  int l = strlen(cmdline_prefix);
-  for(int i = 1; i < g_argc - 1; ++i)
-  {
-    if(g_argv[i][0] == '-')
-    {
-      if(!strncmp(g_argv[i]+1, cmdline_prefix, l))
-        if(g_argv[i][l+1] == '-')
-         preferences.importPref(g_argv[i]+l+2, g_argv[i+1]);
-      ++i;
+    bool ret = false;
+    TextFileInputStream file(filename);
+    if (!file.failed()) {
+        XMLStreamParser parser(file);
+        XMLPreferenceDictionaryImporter importer(preferences, PREFERENCES_VERSION);
+        parser.exportXML(importer);
+        ret = true;
+    }
+
+    int l = strlen(cmdline_prefix);
+    for (int i = 1; i < g_argc - 1; ++i) {
+        if (g_argv[i][0] == '-') {
+            if (!strncmp(g_argv[i] + 1, cmdline_prefix, l)) {
+                if (g_argv[i][l + 1] == '-') {
+                    preferences.importPref(g_argv[i] + l + 2, g_argv[i + 1]);
+                }
+            }
+            ++i;
+        }
     }
-  } 
 
-  return ret;
+    return ret;
 }
 
-bool Preferences_Save(PreferenceDictionary& preferences, const char* filename)
+bool Preferences_Save(PreferenceDictionary &preferences, const char *filename)
 {
-  TextFileOutputStream file(filename);
-  if(!file.failed())
-  {
-    XMLStreamWriter writer(file);
-    XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
-    exporter.exportXML(writer);
-    return true;
-  }
-  return false;
+    TextFileOutputStream file(filename);
+    if (!file.failed()) {
+        XMLStreamWriter writer(file);
+        XMLPreferenceDictionaryExporter exporter(preferences, PREFERENCES_VERSION);
+        exporter.exportXML(writer);
+        return true;
+    }
+    return false;
 }
 
-bool Preferences_Save_Safe(PreferenceDictionary& preferences, const char* filename)
+bool Preferences_Save_Safe(PreferenceDictionary &preferences, const char *filename)
 {
-  Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
-  *(tmpName.end() - 4) = 'T';
-  *(tmpName.end() - 3) = 'M';
-  *(tmpName.end() - 2) = 'P';
-  *(tmpName.end() - 1) = '\0';
-
-  return Preferences_Save(preferences, tmpName.data())
-    && (!file_exists(filename) || file_remove(filename))
-    && file_move(tmpName.data(), filename);
+    Array<char> tmpName(filename, filename + strlen(filename) + 1 + 3);
+    *(tmpName.end() - 4) = 'T';
+    *(tmpName.end() - 3) = 'M';
+    *(tmpName.end() - 2) = 'P';
+    *(tmpName.end() - 1) = '\0';
+
+    return Preferences_Save(preferences, tmpName.data())
+           && (!file_exists(filename) || file_remove(filename))
+           && file_move(tmpName.data(), filename);
 }
 
 
+struct LogConsole {
+    static void Export(const Callback<void(bool)> &returnz)
+    {
+        returnz(g_Console_enableLogging);
+    }
 
-void LogConsole_importString(const char* string)
-{
-  g_Console_enableLogging = string_equal(string, "true");
-  Sys_LogFile(g_Console_enableLogging);
-}
-typedef FreeCaller1<const char*, LogConsole_importString> LogConsoleImportStringCaller;
+    static void Import(bool value)
+    {
+        g_Console_enableLogging = value;
+        Sys_LogFile(g_Console_enableLogging);
+    }
+};
 
 
-void RegisterGlobalPreferences(PreferenceSystempreferences)
+void RegisterGlobalPreferences(PreferenceSystem &preferences)
 {
-  preferences.registerPreference("gamefile", CopiedStringImportStringCaller(g_GamesDialog.m_sGameFile), CopiedStringExportStringCaller(g_GamesDialog.m_sGameFile));
-  preferences.registerPreference("gamePrompt", BoolImportStringCaller(g_GamesDialog.m_bGamePrompt), BoolExportStringCaller(g_GamesDialog.m_bGamePrompt));
-  preferences.registerPreference("log console", LogConsoleImportStringCaller(), BoolExportStringCaller(g_Console_enableLogging));
+    preferences.registerPreference("gamefile", make_property_string(g_GamesDialog.m_sGameFile));
+    preferences.registerPreference("gamePrompt", make_property_string(g_GamesDialog.m_bGamePrompt));
+    preferences.registerPreference("log console", make_property_string<LogConsole>());
 }
 
 
@@ -263,284 +251,241 @@ PreferenceDictionary g_global_preferences;
 
 void GlobalPreferences_Init()
 {
-  RegisterGlobalPreferences(g_global_preferences);
+    RegisterGlobalPreferences(g_global_preferences);
 }
 
 void CGameDialog::LoadPrefs()
 {
-  // load global .pref file
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+    // load global .pref file
+    StringOutputStream strGlobalPref(256);
+    strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
 
-  globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
+    globalOutputStream() << "loading global preferences from " << makeQuoted(strGlobalPref.c_str()) << "\n";
 
-  if(!Preferences_Load(g_global_preferences, strGlobalPref.c_str(), "global"))
-  {
-    globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
-  }
+    if (!Preferences_Load(g_global_preferences, strGlobalPref.c_str(), "global")) {
+        globalOutputStream() << "failed to load global preferences from " << strGlobalPref.c_str() << "\n";
+    }
 }
 
 void CGameDialog::SavePrefs()
 {
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+    StringOutputStream strGlobalPref(256);
+    strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
 
-  globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
+    globalOutputStream() << "saving global preferences to " << strGlobalPref.c_str() << "\n";
 
-  if(!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str()))
-  {
-    globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
-  }
+    if (!Preferences_Save_Safe(g_global_preferences, strGlobalPref.c_str())) {
+        globalOutputStream() << "failed to save global preferences to " << strGlobalPref.c_str() << "\n";
+    }
 }
 
 void CGameDialog::DoGameDialog()
 {
-  // show the UI
-  DoModal();
+    // show the UI
+    DoModal();
 
-  // we save the prefs file
-  SavePrefs();
+    // we save the prefs file
+    SavePrefs();
 }
 
 void CGameDialog::GameFileImport(int value)
 {
-  m_nComboSelect = value;
-  // use value to set m_sGameFile
-  std::list<CGameDescription *>::iterator iGame = mGames.begin();
-  int i;
-  for(i=0; i<value; i++)
-  {
-    ++iGame;
-  }
-  m_sGameFile = (*iGame)->mGameFile;
+    m_nComboSelect = value;
+    // use value to set m_sGameFile
+    std::list<CGameDescription *>::iterator iGame = mGames.begin();
+    int i;
+    for (i = 0; i < value; i++) {
+        ++iGame;
+    }
+    m_sGameFile = (*iGame)->mGameFile;
 }
 
-void CGameDialog::GameFileExport(const IntImportCallback& importCallback) const
+void CGameDialog::GameFileExport(const Callback<void(int)> &importCallback) const
 {
-  // use m_sGameFile to set value
-  std::list<CGameDescription *>::const_iterator iGame;
-  int i = 0;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    if ((*iGame)->mGameFile == m_sGameFile)
-    {
-      m_nComboSelect = i;
-      break;
+    // use m_sGameFile to set value
+    std::list<CGameDescription *>::const_iterator iGame;
+    int i = 0;
+    for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
+        if ((*iGame)->mGameFile == m_sGameFile) {
+            m_nComboSelect = i;
+            break;
+        }
+        i++;
     }
-    i++;
-  }
-  importCallback(m_nComboSelect);
+    importCallback(m_nComboSelect);
 }
 
-void CGameDialog_GameFileImport(CGameDialog& self, int value)
-{
-  self.GameFileImport(value);
-}
+struct CGameDialog_GameFile {
+    static void Export(const CGameDialog &self, const Callback<void(int)> &returnz)
+    {
+        self.GameFileExport(returnz);
+    }
 
-void CGameDialog_GameFileExport(CGameDialog& self, const IntImportCallback& importCallback)
-{
-  self.GameFileExport(importCallback);
-}
+    static void Import(CGameDialog &self, int value)
+    {
+        self.GameFileImport(value);
+    }
+};
 
-void CGameDialog::CreateGlobalFrame(PreferencesPagepage)
+void CGameDialog::CreateGlobalFrame(PreferencesPage &page)
 {
-  std::vector<const char*> games;
-  games.reserve(mGames.size());
-  for(std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i)
-  {
-    games.push_back((*i)->getRequiredKeyValue("name"));
-  }
-  page.appendCombo(
-    "Select the game",
-    StringArrayRange(&(*games.begin()), &(*games.end())),
-    ReferenceCaller1<CGameDialog, int, CGameDialog_GameFileImport>(*this),
-    ReferenceCaller1<CGameDialog, const IntImportCallback&, CGameDialog_GameFileExport>(*this)
-  );
-  page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
+    std::vector<const char *> games;
+    games.reserve(mGames.size());
+    for (std::list<CGameDescription *>::iterator i = mGames.begin(); i != mGames.end(); ++i) {
+        games.push_back((*i)->getRequiredKeyValue("name"));
+    }
+    page.appendCombo(
+            "Select the game",
+            StringArrayRange(&(*games.begin()), &(*games.end())),
+            make_property<CGameDialog_GameFile>(*this)
+    );
+    page.appendCheckBox("Startup", "Show Global Preferences", m_bGamePrompt);
 }
 
-GtkWindow* CGameDialog::BuildDialog()
+ui::Window CGameDialog::BuildDialog()
 {
-  GtkFrame* frame = create_dialog_frame("Game settings", GTK_SHADOW_ETCHED_IN);
-
-  GtkVBox* vbox2 = create_dialog_vbox(0, 4);
-  gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox2));
+    auto frame = create_dialog_frame("Game settings", ui::Shadow::ETCHED_IN);
 
-  {
-    PreferencesPage preferencesPage(*this, GTK_WIDGET(vbox2));
-    Global_constructPreferences(preferencesPage);
-    CreateGlobalFrame(preferencesPage);
-  }
+    auto vbox2 = create_dialog_vbox(0, 4);
+    frame.add(vbox2);
 
-  return create_simple_modal_dialog_window("Global Preferences", m_modal, GTK_WIDGET(frame));
-}
-
-class LoadGameFile
-{
-  std::list<CGameDescription*>& mGames;
-  const char* mPath;
-public:
-  LoadGameFile(std::list<CGameDescription*>& games, const char* path) : mGames(games), mPath(path)
-  {
-  }
-  void operator()(const char* name) const
-  {
-    if(!extension_equal(path_get_extension(name), "game"))
     {
-      return;
+        PreferencesPage preferencesPage(*this, vbox2);
+        Global_constructPreferences(preferencesPage);
+        CreateGlobalFrame(preferencesPage);
     }
-    StringOutputStream strPath(256);
-    strPath << mPath << name;
-    globalOutputStream() << strPath.c_str() << '\n';
 
-    xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
-    if(pDoc)
-    {
-      mGames.push_front(new CGameDescription(pDoc, name));
-      xmlFreeDoc(pDoc);
-    }
-    else
-    {
-      globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
-    }
-  }
-};
+    return create_simple_modal_dialog_window("Global Preferences", m_modal, frame);
+}
 
 void CGameDialog::ScanForGames()
 {
-  StringOutputStream strGamesPath(256);
-  strGamesPath << AppPath_get() << "games/";
-  const char *path = strGamesPath.c_str();
-
-  globalOutputStream() << "Scanning for game description files: " << path << '\n';
-
-  /*!
-  \todo FIXME LINUX:
-  do we put game description files below AppPath, or in ~/.radiant
-  i.e. read only or read/write?
-  my guess .. readonly cause it's an install
-  we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
-  (if that's really needed)
-  */
-
-  Directory_forEach(path, LoadGameFile(mGames, path));
+    StringOutputStream strGamesPath(256);
+    strGamesPath << AppPath_get() << "games/";
+    const char *path = strGamesPath.c_str();
+
+    globalOutputStream() << "Scanning for game description files: " << path << '\n';
+
+    /*!
+       \todo FIXME LINUX:
+       do we put game description files below AppPath, or in ~/.radiant
+       i.e. read only or read/write?
+       my guess .. readonly cause it's an install
+       we will probably want to add ~/.radiant/<version>/games/ scanning on top of that for developers
+       (if that's really needed)
+     */
+
+    Directory_forEach(path, [&](const char *name) {
+        if (!extension_equal(path_get_extension(name), "game")) {
+            return;
+        }
+        StringOutputStream strPath(256);
+        strPath << path << name;
+        globalOutputStream() << strPath.c_str() << '\n';
+
+        xmlDocPtr pDoc = xmlParseFile(strPath.c_str());
+        if (pDoc) {
+            mGames.push_front(new CGameDescription(pDoc, name));
+            xmlFreeDoc(pDoc);
+        } else {
+            globalErrorStream() << "XML parser failed on '" << strPath.c_str() << "'\n";
+        }
+    });
 }
 
-CGameDescriptionCGameDialog::GameDescriptionForComboItem()
+CGameDescription *CGameDialog::GameDescriptionForComboItem()
 {
-  std::list<CGameDescription *>::iterator iGame;
-  int i=0;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame,i++)
-  {
-    if (i == m_nComboSelect)
-    {
-      return (*iGame);
+    std::list<CGameDescription *>::iterator iGame;
+    int i = 0;
+    for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame, i++) {
+        if (i == m_nComboSelect) {
+            return (*iGame);
+        }
     }
-  }
-  return 0; // not found
+    return 0; // not found
 }
 
 void CGameDialog::InitGlobalPrefPath()
 {
-  g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
+    g_Preferences.m_global_rc_path = g_string_new(SettingsPath_get());
 }
 
 void CGameDialog::Reset()
 {
-  if (!g_Preferences.m_global_rc_path)
-    InitGlobalPrefPath();
-  StringOutputStream strGlobalPref(256);
-  strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
-  file_remove(strGlobalPref.c_str());
+    if (!g_Preferences.m_global_rc_path) {
+        InitGlobalPrefPath();
+    }
+    StringOutputStream strGlobalPref(256);
+    strGlobalPref << g_Preferences.m_global_rc_path->str << "global.pref";
+    file_remove(strGlobalPref.c_str());
 }
 
 void CGameDialog::Init()
 {
-  InitGlobalPrefPath();
-  LoadPrefs();
-  ScanForGames();
-  if (mGames.empty())
-  {
-         Error("Didn't find any valid game file descriptions, aborting\n");
-  }
-  else
-  {
-         std::list<CGameDescription *>::iterator iGame, iPrevGame;
-         for(iGame=mGames.begin(), iPrevGame = mGames.end(); iGame!=mGames.end(); iPrevGame = iGame, ++iGame)
-         {
-                 if(iPrevGame != mGames.end())
-                         if(strcmp((*iGame)->getRequiredKeyValue("name"), (*iPrevGame)->getRequiredKeyValue("name")) < 0)
-                         {
-                                 CGameDescription *h = *iGame;
-                                 *iGame = *iPrevGame;
-                                 *iPrevGame = h;
-                         }
-         }
-  }
-  CGameDescription* currentGameDescription = 0;
-
-  if (!m_bGamePrompt)
-  {
-    // search by .game name
-    std::list<CGameDescription *>::iterator iGame;
-    for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-    {
-      if ((*iGame)->mGameFile == m_sGameFile)
-      {
-        currentGameDescription = (*iGame);
-        break;
-      }
+    InitGlobalPrefPath();
+    LoadPrefs();
+    ScanForGames();
+    if (mGames.empty()) {
+        Error("Didn't find any valid game file descriptions, aborting\n");
+    } else {
+        std::list<CGameDescription *>::iterator iGame, iPrevGame;
+        for (iGame = mGames.begin(), iPrevGame = mGames.end(); iGame != mGames.end(); iPrevGame = iGame, ++iGame) {
+            if (iPrevGame != mGames.end()) {
+                if (strcmp((*iGame)->getRequiredKeyValue("name"), (*iPrevGame)->getRequiredKeyValue("name")) < 0) {
+                    CGameDescription *h = *iGame;
+                    *iGame = *iPrevGame;
+                    *iPrevGame = h;
+                }
+            }
+        }
+    }
+
+    CGameDescription *currentGameDescription = 0;
+
+    if (!m_bGamePrompt) {
+        // search by .game name
+        std::list<CGameDescription *>::iterator iGame;
+        for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
+            if ((*iGame)->mGameFile == m_sGameFile) {
+                currentGameDescription = (*iGame);
+                break;
+            }
+        }
     }
-  }
-  if (m_bGamePrompt || !currentGameDescription)
-  {
-    Create();
-    DoGameDialog();
-    // use m_nComboSelect to identify the game to run as and set the globals
-    currentGameDescription = GameDescriptionForComboItem();
-    ASSERT_NOTNULL(currentGameDescription);
-  }
-  g_pGameDescription = currentGameDescription;
-
-  g_pGameDescription->Dump();
+    if (m_bGamePrompt || !currentGameDescription) {
+        Create();
+        DoGameDialog();
+        // use m_nComboSelect to identify the game to run as and set the globals
+        currentGameDescription = GameDescriptionForComboItem();
+        ASSERT_NOTNULL(currentGameDescription);
+    }
+    g_pGameDescription = currentGameDescription;
+
+    g_pGameDescription->Dump();
 }
 
 CGameDialog::~CGameDialog()
 {
-  // free all the game descriptions
-  std::list<CGameDescription *>::iterator iGame;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    delete (*iGame);
-    *iGame = 0;
-  }
-  if(GetWidget() != 0)
-  {
-    Destroy();
-  }
+    // free all the game descriptions
+    std::list<CGameDescription *>::iterator iGame;
+    for (iGame = mGames.begin(); iGame != mGames.end(); ++iGame) {
+        delete (*iGame);
+        *iGame = 0;
+    }
+    if (GetWidget()) {
+        Destroy();
+    }
 }
 
-inline const char* GameDescription_getIdentifier(const CGameDescription& gameDescription)
+inline const char *GameDescription_getIdentifier(const CGameDescription &gameDescription)
 {
-  const char* identifier = gameDescription.getKeyValue("index");
-  if(string_empty(identifier))
-  {
-    identifier = "1";
-  }
-  return identifier;
+    const char *identifier = gameDescription.getKeyValue("index");
+    if (string_empty(identifier)) {
+        identifier = "1";
+    }
+    return identifier;
 }
 
-void CGameDialog::AddPacksURL(StringOutputStream &URL)
-{
-  // add the URLs for the list of game packs installed
-  // FIXME: this is kinda hardcoded for now..
-  std::list<CGameDescription *>::iterator iGame;
-  for(iGame=mGames.begin(); iGame!=mGames.end(); ++iGame)
-  {
-    URL << "&Games_dlup%5B%5D=" << GameDescription_getIdentifier(*(*iGame));
-  }
-}
 
 CGameDialog g_GamesDialog;
 
@@ -548,380 +493,386 @@ CGameDialog g_GamesDialog;
 // =============================================================================
 // Widget callbacks for PrefsDlg
 
-static void OnButtonClean (GtkWidget *widget, gpointer data) 
+static void OnButtonClean(ui::Widget widget, gpointer data)
 {
-  // make sure this is what the user wants
-  if (gtk_MessageBox(GTK_WIDGET(g_Preferences.GetWidget()), "This will close Radiant and clean the corresponding registry entries.\n"
-      "Next time you start Radiant it will be good as new. Do you wish to continue?",
-      "Reset Registry", eMB_YESNO, eMB_ICONASTERISK) == eIDYES)
-  {
-    PrefsDlg *dlg = (PrefsDlg*)data;
-    dlg->EndModal (eIDCANCEL);
-
-    g_preferences_globals.disable_ini = true;
-    Preferences_Reset();
-    gtk_main_quit();
-  }
+    // make sure this is what the user wants
+    if (ui::alert(g_Preferences.GetWidget(), "This will close Radiant and clean the corresponding registry entries.\n"
+                          "Next time you start Radiant it will be good as new. Do you wish to continue?",
+                  "Reset Registry", ui::alert_type::YESNO, ui::alert_icon::Asterisk) == ui::alert_response::YES) {
+        PrefsDlg *dlg = (PrefsDlg *) data;
+        dlg->EndModal(eIDCANCEL);
+
+        g_preferences_globals.disable_ini = true;
+        Preferences_Reset();
+        gtk_main_quit();
+    }
 }
 
 // =============================================================================
 // PrefsDlg class
 
 /*
-========
+   ========
 
-very first prefs init deals with selecting the game and the game tools path
-then we can load .ini stuff
+   very first prefs init deals with selecting the game and the game tools path
+   then we can load .ini stuff
 
-using prefs / ini settings:
-those are per-game
+   using prefs / ini settings:
+   those are per-game
 
-look in ~/.radiant/<version>/gamename
-========
-*/
+   look in ~/.radiant/<version>/gamename
+   ========
+ */
 
-#define PREFS_LOCAL_FILENAME "local.pref"
+const char *PREFS_LOCAL_FILENAME = "local.pref";
 
 void PrefsDlg::Init()
 {
-  // m_global_rc_path has been set above
-  // m_rc_path is for game specific preferences
-  // takes the form: global-pref-path/gamename/prefs-file
-
-  // this is common to win32 and Linux init now
-  m_rc_path = g_string_new (m_global_rc_path->str);
-  
-  // game sub-dir
-  g_string_append (m_rc_path, g_pGameDescription->mGameFile.c_str());
-  g_string_append (m_rc_path, "/");
-  Q_mkdir (m_rc_path->str);
-  
-  // then the ini file
-  m_inipath = g_string_new (m_rc_path->str);
-  g_string_append (m_inipath, PREFS_LOCAL_FILENAME);
+    // m_global_rc_path has been set above
+    // m_rc_path is for game specific preferences
+    // takes the form: global-pref-path/gamename/prefs-file
+
+    // this is common to win32 and Linux init now
+    m_rc_path = g_string_new(m_global_rc_path->str);
+
+    // game sub-dir
+    g_string_append(m_rc_path, g_pGameDescription->mGameFile.c_str());
+    g_string_append(m_rc_path, "/");
+    Q_mkdir(m_rc_path->str);
+
+    // then the ini file
+    m_inipath = g_string_new(m_rc_path->str);
+    g_string_append(m_inipath, PREFS_LOCAL_FILENAME);
 }
 
-void notebook_set_page(GtkWidget* notebook, GtkWidget* page)
+void notebook_set_page(ui::Widget notebook, ui::Widget page)
 {
-  int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
-  if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum)
-  {
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
-  }
+    int pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), page);
+    if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != pagenum) {
+        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), pagenum);
+    }
 }
 
-void PrefsDlg::showPrefPage(GtkWidget* prefpage)
+void PrefsDlg::showPrefPage(ui::Widget prefpage)
 {
-  notebook_set_page(m_notebook, prefpage);
-  return;
+    notebook_set_page(m_notebook, prefpage);
+    return;
 }
 
-static void treeSelection(GtkTreeSelection* selection, gpointer data)
+static void treeSelection(ui::TreeSelection selection, gpointer data)
 {
-  PrefsDlg *dlg = (PrefsDlg*)data;
-
-  GtkTreeModel* model;
-  GtkTreeIter selected;
-  if(gtk_tree_selection_get_selected(selection, &model, &selected))
-  {
-    GtkWidget* prefpage;
-    gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1);
-    dlg->showPrefPage(prefpage);
-  }
+    PrefsDlg *dlg = (PrefsDlg *) data;
+
+    GtkTreeModel *model;
+    GtkTreeIter selected;
+    if (gtk_tree_selection_get_selected(selection, &model, &selected)) {
+        ui::Widget prefpage{ui::null};
+        gtk_tree_model_get(model, &selected, 1, (gpointer *) &prefpage, -1);
+        dlg->showPrefPage(prefpage);
+    }
 }
 
 typedef std::list<PreferenceGroupCallback> PreferenceGroupCallbacks;
 
-inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks& callbacks, PreferenceGroup& group)
+inline void PreferenceGroupCallbacks_constructGroup(const PreferenceGroupCallbacks &callbacks, PreferenceGroup &group)
 {
-  for(PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
-  {
-    (*i)(group);
-  }
+    for (PreferenceGroupCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
+        (*i)(group);
+    }
 }
 
 
-inline void PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks& callbacks, const PreferenceGroupCallback& callback)
+inline void
+PreferenceGroupCallbacks_pushBack(PreferenceGroupCallbacks &callbacks, const PreferenceGroupCallback &callback)
 {
-  callbacks.push_back(callback);
+    callbacks.push_back(callback);
 }
 
 typedef std::list<PreferencesPageCallback> PreferencesPageCallbacks;
 
-inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks& callbacks, PreferencesPage& page)
+inline void PreferencesPageCallbacks_constructPage(const PreferencesPageCallbacks &callbacks, PreferencesPage &page)
 {
-  for(PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i)
-  {
-    (*i)(page);
-  }
+    for (PreferencesPageCallbacks::const_iterator i = callbacks.begin(); i != callbacks.end(); ++i) {
+        (*i)(page);
+    }
 }
 
-inline void PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks& callbacks, const PreferencesPageCallback& callback)
+inline void
+PreferencesPageCallbacks_pushBack(PreferencesPageCallbacks &callbacks, const PreferencesPageCallback &callback)
 {
-  callbacks.push_back(callback);
+    callbacks.push_back(callback);
 }
 
 PreferencesPageCallbacks g_interfacePreferences;
-void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback& callback)
+
+void PreferencesDialog_addInterfacePreferences(const PreferencesPageCallback &callback)
 {
-  PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
+    PreferencesPageCallbacks_pushBack(g_interfacePreferences, callback);
 }
+
 PreferenceGroupCallbacks g_interfaceCallbacks;
-void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback& callback)
+
+void PreferencesDialog_addInterfacePage(const PreferenceGroupCallback &callback)
 {
-  PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
+    PreferenceGroupCallbacks_pushBack(g_interfaceCallbacks, callback);
 }
 
 PreferencesPageCallbacks g_displayPreferences;
-void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback& callback)
+
+void PreferencesDialog_addDisplayPreferences(const PreferencesPageCallback &callback)
 {
-  PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
+    PreferencesPageCallbacks_pushBack(g_displayPreferences, callback);
 }
+
 PreferenceGroupCallbacks g_displayCallbacks;
-void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback& callback)
+
+void PreferencesDialog_addDisplayPage(const PreferenceGroupCallback &callback)
 {
-  PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
+    PreferenceGroupCallbacks_pushBack(g_displayCallbacks, callback);
 }
 
 PreferencesPageCallbacks g_settingsPreferences;
-void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback& callback)
+
+void PreferencesDialog_addSettingsPreferences(const PreferencesPageCallback &callback)
 {
-  PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
+    PreferencesPageCallbacks_pushBack(g_settingsPreferences, callback);
 }
+
 PreferenceGroupCallbacks g_settingsCallbacks;
-void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback& callback)
+
+void PreferencesDialog_addSettingsPage(const PreferenceGroupCallback &callback)
 {
-  PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
+    PreferenceGroupCallbacks_pushBack(g_settingsCallbacks, callback);
 }
 
-void Widget_updateDependency(GtkWidget* self, GtkWidget* toggleButton)
+void Widget_updateDependency(ui::Widget self, ui::Widget toggleButton)
 {
-  gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) && GTK_WIDGET_IS_SENSITIVE(toggleButton));
+    gtk_widget_set_sensitive(self, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggleButton)) &&
+                                   gtk_widget_is_sensitive(toggleButton));
 }
 
-void ToggleButton_toggled_Widget_updateDependency(GtkWidget *toggleButton, GtkWidget* self)
+void ToggleButton_toggled_Widget_updateDependency(ui::Widget toggleButton, ui::Widget self)
 {
-  Widget_updateDependency(self, toggleButton);
+    Widget_updateDependency(self, toggleButton);
 }
 
-void ToggleButton_state_changed_Widget_updateDependency(GtkWidget* toggleButton, GtkStateType state, GtkWidget* self)
+void ToggleButton_state_changed_Widget_updateDependency(ui::Widget toggleButton, GtkStateType state, ui::Widget self)
 {
-  if(state == GTK_STATE_INSENSITIVE)
-  {
-    Widget_updateDependency(self, toggleButton);
-  }
+    if (state == GTK_STATE_INSENSITIVE) {
+        Widget_updateDependency(self, toggleButton);
+    }
 }
 
-void Widget_connectToggleDependency(GtkWidget* self, GtkWidget* toggleButton)
+void Widget_connectToggleDependency(ui::Widget self, ui::Widget toggleButton)
 {
-  g_signal_connect(G_OBJECT(toggleButton), "state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
-  g_signal_connect(G_OBJECT(toggleButton), "toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
-  Widget_updateDependency(self, toggleButton);
+    toggleButton.connect("state_changed", G_CALLBACK(ToggleButton_state_changed_Widget_updateDependency), self);
+    toggleButton.connect("toggled", G_CALLBACK(ToggleButton_toggled_Widget_updateDependency), self);
+    Widget_updateDependency(self, toggleButton);
 }
 
 
-inline GtkWidget* getVBox(GtkWidget* page)
+inline ui::VBox getVBox(ui::Bin page)
 {
-  return gtk_bin_get_child(GTK_BIN(page));
+    return ui::VBox::from(gtk_bin_get_child(page));
 }
 
-GtkTreeIter PreferenceTree_appendPage(GtkTreeStore* store, GtkTreeIter* parent, const char* name, GtkWidget* page)
+GtkTreeIter PreferenceTree_appendPage(ui::TreeStore store, GtkTreeIter *parent, const char *name, ui::Widget page)
 {
-  GtkTreeIter group;
-  gtk_tree_store_append(store, &group, parent);
-  gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
-  return group;
+    GtkTreeIter group;
+    gtk_tree_store_append(store, &group, parent);
+    gtk_tree_store_set(store, &group, 0, name, 1, page, -1);
+    return group;
 }
 
-GtkWidget* PreferencePages_addPage(GtkWidget* notebook, const char* name)
+ui::Bin PreferencePages_addPage(ui::Widget notebook, const char *name)
 {
-  GtkWidget* preflabel = gtk_label_new(name);
-  gtk_widget_show(preflabel);
+    ui::Widget preflabel = ui::Label(name);
+    preflabel.show();
 
-  GtkWidget* pageframe = gtk_frame_new(name);
-  gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
-  gtk_widget_show(pageframe);
+    auto pageframe = ui::Frame(name);
+    gtk_container_set_border_width(GTK_CONTAINER(pageframe), 4);
+    pageframe.show();
 
-  GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
-  gtk_widget_show(vbox);
-  gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
-  gtk_container_add(GTK_CONTAINER(pageframe), vbox);
+    ui::Widget vbox = ui::VBox(FALSE, 4);
+    vbox.show();
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+    pageframe.add(vbox);
 
-  // Add the page to the notebook
-  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
+    // Add the page to the notebook
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel);
 
-  return pageframe;
+    return pageframe;
 }
 
-class PreferenceTreeGroup : public PreferenceGroup
-{
-  Dialog& m_dialog;
-  GtkWidget* m_notebook;
-  GtkTreeStore* m_store;
-  GtkTreeIter m_group;
+class PreferenceTreeGroup : public PreferenceGroup {
+    Dialog &m_dialog;
+    ui::Widget m_notebook;
+    ui::TreeStore m_store;
+    GtkTreeIter m_group;
 public:
-  PreferenceTreeGroup(Dialog& dialog, GtkWidget* notebook, GtkTreeStore* store, GtkTreeIter group) :
-    m_dialog(dialog),
-    m_notebook(notebook),
-    m_store(store),
-    m_group(group)
-  {
-  }
-  PreferencesPage createPage(const char* treeName, const char* frameName)
-  {
-    GtkWidget* page = PreferencePages_addPage(m_notebook, frameName);
-    PreferenceTree_appendPage(m_store, &m_group, treeName, page);
-    return PreferencesPage(m_dialog, getVBox(page));
-  }
+    PreferenceTreeGroup(Dialog &dialog, ui::Widget notebook, ui::TreeStore store, GtkTreeIter group) :
+            m_dialog(dialog),
+            m_notebook(notebook),
+            m_store(store),
+            m_group(group)
+    {
+    }
+
+    PreferencesPage createPage(const char *treeName, const char *frameName)
+    {
+        auto page = PreferencePages_addPage(m_notebook, frameName);
+        PreferenceTree_appendPage(m_store, &m_group, treeName, page);
+        return PreferencesPage(m_dialog, getVBox(page));
+    }
 };
 
-GtkWindow* PrefsDlg::BuildDialog()
+ui::Window PrefsDlg::BuildDialog()
 {
-  PreferencesDialog_addInterfacePreferences(FreeCaller1<PreferencesPage&, Interface_constructPreferences>());
-  Mouse_registerPreferencesPage();
+    PreferencesDialog_addInterfacePreferences(makeCallbackF(Interface_constructPreferences));
+    Mouse_registerPreferencesPage();
 
-  GtkWindow* dialog = create_floating_window("NetRadiant Preferences", m_parent);
+    ui::Window dialog = ui::Window(create_floating_window("NetRadiant Preferences", m_parent));
 
-  {
-    GtkWidget* mainvbox = gtk_vbox_new(FALSE, 5);
-    gtk_container_add(GTK_CONTAINER(dialog), mainvbox);
-    gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
-    gtk_widget_show(mainvbox);
-  
     {
-      GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
-      gtk_widget_show(hbox);
-      gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0);
-
-      {
-        GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-      {
-        GtkButton* button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
-        gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
-      }
-    }
-  
-    {
-      GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
-      gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
-      gtk_widget_show(hbox);
-  
-      {
-        GtkWidget* sc_win = gtk_scrolled_window_new(0, 0);
-        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-        gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0);
-        gtk_widget_show(sc_win);
-        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
-
-        // prefs pages notebook
-        m_notebook = gtk_notebook_new();
-        // hide the notebook tabs since its not supposed to look like a notebook
-        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
-        gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 0);
-        gtk_widget_show(m_notebook);
-
+        auto mainvbox = ui::VBox(FALSE, 5);
+        dialog.add(mainvbox);
+        gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5);
+        mainvbox.show();
 
         {
-          GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
-
-          GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-          gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
-
-          {
-            GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
-            GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL);
-            gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
-          }
-
-          {
-            GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-            g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this);
-          }
-
-          gtk_widget_show(view);
-
-          gtk_container_add(GTK_CONTAINER (sc_win), view);
-
-          {
-            /********************************************************************/
-            /* Add preference tree options                                      */
-            /********************************************************************/
-            // Front page... 
-            //GtkWidget* front =
-            PreferencePages_addPage(m_notebook, "Front Page");
+            auto hbox = ui::HBox(FALSE, 5);
+            hbox.show();
+            mainvbox.pack_end(hbox, FALSE, TRUE, 0);
 
             {
-              GtkWidget* global = PreferencePages_addPage(m_notebook, "Global Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(global));
-                Global_constructPreferences(preferencesPage);
-              }
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Global", global);
-              {
-                GtkWidget* game = PreferencePages_addPage(m_notebook, "Game");
-                PreferencesPage preferencesPage(*this, getVBox(game));
-                g_GamesDialog.CreateGlobalFrame(preferencesPage);
-
-                PreferenceTree_appendPage(store, &group, "Game", game);
-              }
+                auto button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &m_modal);
+                hbox.pack_end(button, FALSE, FALSE, 0);
             }
-
             {
-              GtkWidget* interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(interfacePage));
-                PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
-              }
-
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
-              PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
-
-              PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
+                auto button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &m_modal);
+                hbox.pack_end(button, FALSE, FALSE, 0);
             }
-
             {
-              GtkWidget* display = PreferencePages_addPage(m_notebook, "Display Preferences");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(display));
-                PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
-              }
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Display", display);
-              PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
-
-              PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
+                auto button = create_dialog_button("Clean", G_CALLBACK(OnButtonClean), this);
+                hbox.pack_end(button, FALSE, FALSE, 0);
             }
+        }
 
-            {
-              GtkWidget* settings = PreferencePages_addPage(m_notebook, "General Settings");
-              {
-                PreferencesPage preferencesPage(*this, getVBox(settings));
-                PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
-              }
-
-              GtkTreeIter group = PreferenceTree_appendPage(store, 0, "Settings", settings);
-              PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
+        {
+            auto hbox = ui::HBox(FALSE, 5);
+            mainvbox.pack_start(hbox, TRUE, TRUE, 0);
+            hbox.show();
 
-              PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
+            {
+                auto sc_win = ui::ScrolledWindow(ui::New);
+                gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+                hbox.pack_start(sc_win, FALSE, FALSE, 0);
+                sc_win.show();
+                gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN);
+
+                // prefs pages notebook
+                m_notebook = ui::Widget::from(gtk_notebook_new());
+                // hide the notebook tabs since its not supposed to look like a notebook
+                gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_notebook), FALSE);
+                hbox.pack_start(m_notebook, TRUE, TRUE, 0);
+                m_notebook.show();
+
+
+                {
+                    auto store = ui::TreeStore::from(gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER));
+
+                    auto view = ui::TreeView(ui::TreeModel::from(store._handle));
+                    gtk_tree_view_set_headers_visible(view, FALSE);
+
+                    {
+                        auto renderer = ui::CellRendererText(ui::New);
+                        auto column = ui::TreeViewColumn("Preferences", renderer, {{"text", 0}});
+                        gtk_tree_view_append_column(view, column);
+                    }
+
+                    {
+                        auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(view));
+                        selection.connect("changed", G_CALLBACK(treeSelection), this);
+                    }
+
+                    view.show();
+
+                    sc_win.add(view);
+
+                    {
+                        /********************************************************************/
+                        /* Add preference tree options                                      */
+                        /********************************************************************/
+                        // Front page...
+                        //GtkWidget* front =
+                        PreferencePages_addPage(m_notebook, "Front Page");
+
+                        {
+                            auto global = PreferencePages_addPage(m_notebook, "Global Preferences");
+                            {
+                                PreferencesPage preferencesPage(*this, getVBox(global));
+                                Global_constructPreferences(preferencesPage);
+                            }
+                            auto group = PreferenceTree_appendPage(store, 0, "Global", global);
+                            {
+                                auto game = PreferencePages_addPage(m_notebook, "Game");
+                                PreferencesPage preferencesPage(*this, getVBox(game));
+                                g_GamesDialog.CreateGlobalFrame(preferencesPage);
+
+                                PreferenceTree_appendPage(store, &group, "Game", game);
+                            }
+                        }
+
+                        {
+                            auto interfacePage = PreferencePages_addPage(m_notebook, "Interface Preferences");
+                            {
+                                PreferencesPage preferencesPage(*this, getVBox(interfacePage));
+                                PreferencesPageCallbacks_constructPage(g_interfacePreferences, preferencesPage);
+                            }
+
+                            auto group = PreferenceTree_appendPage(store, 0, "Interface", interfacePage);
+                            PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
+
+                            PreferenceGroupCallbacks_constructGroup(g_interfaceCallbacks, preferenceGroup);
+                        }
+
+                        {
+                            auto display = PreferencePages_addPage(m_notebook, "Display Preferences");
+                            {
+                                PreferencesPage preferencesPage(*this, getVBox(display));
+                                PreferencesPageCallbacks_constructPage(g_displayPreferences, preferencesPage);
+                            }
+                            auto group = PreferenceTree_appendPage(store, 0, "Display", display);
+                            PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
+
+                            PreferenceGroupCallbacks_constructGroup(g_displayCallbacks, preferenceGroup);
+                        }
+
+                        {
+                            auto settings = PreferencePages_addPage(m_notebook, "General Settings");
+                            {
+                                PreferencesPage preferencesPage(*this, getVBox(settings));
+                                PreferencesPageCallbacks_constructPage(g_settingsPreferences, preferencesPage);
+                            }
+
+                            auto group = PreferenceTree_appendPage(store, 0, "Settings", settings);
+                            PreferenceTreeGroup preferenceGroup(*this, m_notebook, store, group);
+
+                            PreferenceGroupCallbacks_constructGroup(g_settingsCallbacks, preferenceGroup);
+                        }
+                    }
+
+                    gtk_tree_view_expand_all(view);
+
+                    g_object_unref(G_OBJECT(store));
+                }
             }
-          }
-
-          gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
-    
-          g_object_unref(G_OBJECT(store));
         }
-      }
     }
-  }
 
-  gtk_notebook_set_page(GTK_NOTEBOOK(m_notebook), 0);
+    gtk_notebook_set_current_page(GTK_NOTEBOOK(m_notebook), 0);
 
-  return dialog;
+    return dialog;
 }
 
 preferences_globals_t g_preferences_globals;
@@ -929,39 +880,41 @@ preferences_globals_t g_preferences_globals;
 PrefsDlg g_Preferences;               // global prefs instance
 
 
-void PreferencesDialog_constructWindow(GtkWindow* main_window)
+void PreferencesDialog_constructWindow(ui::Window main_window)
 {
-  g_Preferences.m_parent = main_window;
-  g_Preferences.Create();
+    g_Preferences.m_parent = main_window;
+    g_Preferences.Create();
 }
+
 void PreferencesDialog_destroyWindow()
 {
-  g_Preferences.Destroy();
+    g_Preferences.Destroy();
 }
 
 
 PreferenceDictionary g_preferences;
 
-PreferenceSystemGetPreferenceSystem()
+PreferenceSystem &GetPreferenceSystem()
 {
-  return g_preferences;
+    return g_preferences;
 }
 
-class PreferenceSystemAPI
-{
-  PreferenceSystem* m_preferencesystem;
+class PreferenceSystemAPI {
+    PreferenceSystem *m_preferencesystem;
 public:
-  typedef PreferenceSystem Type;
-  STRING_CONSTANT(Name, "*");
-
-  PreferenceSystemAPI()
-  {
-    m_preferencesystem = &GetPreferenceSystem();
-  }
-  PreferenceSystem* getTable()
-  {
-    return m_preferencesystem;
-  }
+    typedef PreferenceSystem Type;
+
+    STRING_CONSTANT(Name, "*");
+
+    PreferenceSystemAPI()
+    {
+        m_preferencesystem = &GetPreferenceSystem();
+    }
+
+    PreferenceSystem *getTable()
+    {
+        return m_preferencesystem;
+    }
 };
 
 #include "modulesystem/singletonmodule.h"
@@ -973,112 +926,105 @@ StaticRegisterModule staticRegisterPreferenceSystem(StaticPreferenceSystemModule
 
 void Preferences_Load()
 {
-  g_GamesDialog.LoadPrefs();
+    g_GamesDialog.LoadPrefs();
 
-  globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
+    globalOutputStream() << "loading local preferences from " << g_Preferences.m_inipath->str << "\n";
 
-  if(!Preferences_Load(g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str()))
-  {
-    globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
-  }
+    if (!Preferences_Load(g_preferences, g_Preferences.m_inipath->str, g_GamesDialog.m_sGameFile.c_str())) {
+        globalOutputStream() << "failed to load local preferences from " << g_Preferences.m_inipath->str << "\n";
+    }
 }
 
 void Preferences_Save()
 {
-  if (g_preferences_globals.disable_ini)
-    return;
+    if (g_preferences_globals.disable_ini) {
+        return;
+    }
 
-  g_GamesDialog.SavePrefs();
+    g_GamesDialog.SavePrefs();
 
-  globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
+    globalOutputStream() << "saving local preferences to " << g_Preferences.m_inipath->str << "\n";
 
-  if(!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str))
-  {
-    globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
-  }
+    if (!Preferences_Save_Safe(g_preferences, g_Preferences.m_inipath->str)) {
+        globalOutputStream() << "failed to save local preferences to " << g_Preferences.m_inipath->str << "\n";
+    }
 }
 
 void Preferences_Reset()
 {
-  file_remove(g_Preferences.m_inipath->str);
+    file_remove(g_Preferences.m_inipath->str);
 }
 
 
-void PrefsDlg::PostModal (EMessageBoxReturn code)
+void PrefsDlg::PostModal(EMessageBoxReturn code)
 {
-  if (code == eIDOK)
-  {
-    Preferences_Save();
-    UpdateAllWindows();
-  }
+    if (code == eIDOK) {
+        Preferences_Save();
+        UpdateAllWindows();
+    }
 }
 
-std::vector<const char*> g_restart_required;
+std::vector<const char *> g_restart_required;
 
-void PreferencesDialog_restartRequired(const charstaticName)
+void PreferencesDialog_restartRequired(const char *staticName)
 {
-  g_restart_required.push_back(staticName);
+    g_restart_required.push_back(staticName);
 }
 
 void PreferencesDialog_showDialog()
 {
-  if(ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK)
-  {
-    if(!g_restart_required.empty())
-    {
-      StringOutputStream message(256);
-      message << "Preference changes require a restart:\n";
-      for(std::vector<const char*>::iterator i = g_restart_required.begin(); i != g_restart_required.end(); ++i)
-      {
-        message << (*i) << '\n';
-      }
-      gtk_MessageBox(GTK_WIDGET(MainFrame_getWindow()), message.c_str());
-      g_restart_required.clear();
+    if (ConfirmModified("Edit Preferences") && g_Preferences.DoModal() == eIDOK) {
+        if (!g_restart_required.empty()) {
+            StringOutputStream message(256);
+            message << "Preference changes require a restart:\n";
+            for (std::vector<const char *>::iterator i = g_restart_required.begin();
+                 i != g_restart_required.end(); ++i) {
+                message << (*i) << '\n';
+            }
+            ui::alert(MainFrame_getWindow(), message.c_str());
+            g_restart_required.clear();
+        }
     }
-  }
 }
 
+struct GameName {
+    static void Export(const Callback<void(const char *)> &returnz)
+    {
+        returnz(gamename_get());
+    }
 
+    static void Import(const char *value)
+    {
+        gamename_set(value);
+    }
+};
 
+struct GameMode {
+    static void Export(const Callback<void(const char *)> &returnz)
+    {
+        returnz(gamemode_get());
+    }
 
+    static void Import(const char *value)
+    {
+        gamemode_set(value);
+    }
+};
 
-void GameName_importString(const char* value)
-{
-  gamename_set(value);
-}
-typedef FreeCaller1<const char*, GameName_importString> GameNameImportStringCaller;
-void GameName_exportString(const StringImportCallback& importer)
-{
-  importer(gamename_get());
-}
-typedef FreeCaller1<const StringImportCallback&, GameName_exportString> GameNameExportStringCaller;
-
-void GameMode_importString(const char* value)
-{
-  gamemode_set(value);
-}
-typedef FreeCaller1<const char*, GameMode_importString> GameModeImportStringCaller;
-void GameMode_exportString(const StringImportCallback& importer)
-{
-  importer(gamemode_get());
-}
-typedef FreeCaller1<const StringImportCallback&, GameMode_exportString> GameModeExportStringCaller;
-
-
-void RegisterPreferences(PreferenceSystem& preferences)
+void RegisterPreferences(PreferenceSystem &preferences)
 {
-#ifdef WIN32
-  preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useWin32Editor), BoolExportStringCaller(g_TextEditor_useWin32Editor));
+#if GDEF_OS_WINDOWS
+    preferences.registerPreference( "UseCustomShaderEditor", make_property_string( g_TextEditor_useWin32Editor ) );
 #else
-  preferences.registerPreference("UseCustomShaderEditor", BoolImportStringCaller(g_TextEditor_useCustomEditor), BoolExportStringCaller(g_TextEditor_useCustomEditor));
-  preferences.registerPreference("CustomShaderEditorCommand", CopiedStringImportStringCaller(g_TextEditor_editorCommand), CopiedStringExportStringCaller(g_TextEditor_editorCommand));
+    preferences.registerPreference("UseCustomShaderEditor", make_property_string(g_TextEditor_useCustomEditor));
+    preferences.registerPreference("CustomShaderEditorCommand", make_property_string(g_TextEditor_editorCommand));
 #endif
 
-  preferences.registerPreference("GameName", GameNameImportStringCaller(), GameNameExportStringCaller());
-  preferences.registerPreference("GameMode", GameModeImportStringCaller(), GameModeExportStringCaller());
+    preferences.registerPreference("GameName", make_property<GameName>());
+    preferences.registerPreference("GameMode", make_property<GameMode>());
 }
 
 void Preferences_Init()
 {
-  RegisterPreferences(GetPreferenceSystem());
+    RegisterPreferences(GetPreferenceSystem());
 }