diff --git a/GormCore/Plugins/Xib/GormXIBModelGenerator.h b/GormCore/Plugins/Xib/GormXIBModelGenerator.h
new file mode 100644
index 00000000..47e09a77
--- /dev/null
+++ b/GormCore/Plugins/Xib/GormXIBModelGenerator.h
@@ -0,0 +1,69 @@
+/**
GormXIBKeyedArchiver
+
+ Interface of GormXIBKeyedArchiver
+
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ Author: Gregory John Casamento
+ Date: 2023
+
+ This file is part of the GNUstep GUI Library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; see the file COPYING.LIB.
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GormXIBModelGenerator_H_INCLUDE
+#define GormXIBModelGenerator_H_INCLUDE
+
+#import
+
+@class GormDocument;
+@class NSMutableDictionary;
+@class NSString;
+@class NSData;
+
+@interface GormXIBModelGenerator : NSObject
+{
+ GormDocument *_gormDocument;
+ NSMutableDictionary *_mappingDictionary;
+}
+
+/**
+ * Returns an autoreleased GormXIBModelGenerator object;
+ */
++ (instancetype) xibWithGormDocument: (GormDocument *)doc;
+
+/**
+ * Initialize with GormDocument object to parse the XML from or into.
+ */
+- (instancetype) initWithGormDocument: (GormDocument *)doc;
+
+/**
+ * The data for the XIB document that has been created
+ */
+- (NSData *) data;
+
+/**
+ * Exports XIB file. This method starts the process and calls
+ * another method that recurses through the objects in the model and
+ * maps any properties as appropriate when exporting.
+ */
+- (BOOL) exportXIBDocumentWithName: (NSString *)name;
+
+@end
+
+#endif // GormXIBModelGenerator_H_INCLUDE
diff --git a/GormCore/Plugins/Xib/GormXIBModelGenerator.m b/GormCore/Plugins/Xib/GormXIBModelGenerator.m
new file mode 100644
index 00000000..0c0cccb5
--- /dev/null
+++ b/GormCore/Plugins/Xib/GormXIBModelGenerator.m
@@ -0,0 +1,341 @@
+/** GormXIBKeyedArchiver
+
+ Interface of GormXIBKeyedArchiver
+
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ Author: Gregory John Casamento
+ Date: 2023
+
+ This file is part of the GNUstep GUI Library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; see the file COPYING.LIB.
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+
+#import
+#import
+#import
+
+#import "GormDocument.h"
+#import "GormDocumentController.h"
+#import "GormFilePrefsManager.h"
+#import "GormProtocol.h"
+#import "GormPrivate.h"
+
+#import "GormXIBModelGenerator.h"
+
+@implementation GormXIBModelGenerator
+
+/**
+ * Returns an autoreleast GormXIBDocument object;
+ */
++ (instancetype) xibWithGormDocument: (GormDocument *)doc
+{
+ return AUTORELEASE([[self alloc] initWithGormDocument: doc]);
+}
+
+/**
+ * Initialize with GormDocument object to parse the XML from or into.
+ */
+- (instancetype) initWithGormDocument: (GormDocument *)doc
+{
+ self = [super init];
+ if (self != nil)
+ {
+ ASSIGN(_gormDocument, doc);
+ _mappingDictionary = [[NSMutableDictionary alloc] init];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ DESTROY(_gormDocument);
+ DESTROY(_mappingDictionary);
+
+ [super dealloc];
+}
+
+- (NSString *) _convertName: (NSString *)className
+{
+ NSString *result = [className stringByReplacingOccurrencesOfString: @"NS"
+ withString: @""];
+
+ // Try removing other prefixes...
+ result = [result stringByReplacingOccurrencesOfString: @"GS"
+ withString: @""];
+ result = [result stringByReplacingOccurrencesOfString: @"Gorm"
+ withString: @""];
+
+ // Lowercase the first letter of the class to make the element name
+ NSString *first = [[result substringToIndex: 1] lowercaseString];
+ NSString *rest = [result substringFromIndex: 1];
+
+ result = [NSString stringWithFormat: @"%@%@", first, rest];
+
+ return result;
+}
+
+- (NSString *) _createIdentifierForObject: (id)obj
+{
+ NSString *result = nil;
+
+ if ([obj isKindOfClass: [GormObjectProxy class]])
+ {
+ NSString *className = [obj className];
+
+ if ([className isEqualToString: @"NSApplication"])
+ {
+ result = @"-3";
+ }
+ else if ([className isEqualToString: @"NSOwner"])
+ {
+ result = @"-2";
+ }
+ else if ([className isEqualToString: @"NSFirst"])
+ {
+ result = @"-1";
+ }
+ }
+ else
+ {
+ result = [_gormDocument nameForObject: obj];
+ }
+
+ return result;
+}
+
+- (NSString *) _userLabelForObject: (id)obj
+{
+ NSString *result = nil;
+
+ if ([obj isKindOfClass: [GormObjectProxy class]])
+ {
+ NSString *className = [obj className];
+
+ if ([className isEqualToString: @"NSApplication"])
+ {
+ result = @"Application";
+ }
+ else if ([className isEqualToString: @"NSOwner"])
+ {
+ result = @"File's Owner";
+ }
+ else if ([className isEqualToString: @"NSFirst"])
+ {
+ result = @"First Responder";
+ }
+ }
+
+ return result;
+}
+
+- (void) _collectObjectsFromObject: (id)obj
+ withNode: (NSXMLElement *)node
+{
+ NSString *ident = [self _createIdentifierForObject: obj];
+
+ if (ident != nil)
+ {
+ NSString *className = NSStringFromClass([obj class]);
+ NSString *elementName = [self _convertName: className];
+ NSXMLElement *elem = [NSXMLNode elementWithName: elementName];
+ NSXMLNode *attr = [NSXMLNode attributeWithName: @"id" stringValue: ident];
+ [elem addAttribute: attr];
+
+ NSString *userLabel = [self _userLabelForObject: obj];
+ if (userLabel != nil)
+ {
+ attr = [NSXMLNode attributeWithName: @"userLabel" stringValue: userLabel];
+ [elem addAttribute: attr];
+ }
+
+ if ([obj isKindOfClass: [GormObjectProxy class]] ||
+ [obj respondsToSelector: @selector(className)])
+ {
+ if ([className isEqualToString: [obj className]] == NO)
+ {
+ className = [obj className];
+ attr = [NSXMLNode attributeWithName: @"customClass" stringValue: className];
+ [elem addAttribute: attr];
+ }
+ }
+
+ [node addChild: elem];
+
+ // If the object responds to "title" get that and add it to the XML
+ if ([obj respondsToSelector: @selector(title)])
+ {
+ NSString *title = [obj title];
+ if (title != nil)
+ {
+ attr = [NSXMLNode attributeWithName: @"title" stringValue: title];
+ [elem addAttribute: attr];
+ }
+ }
+
+ // For each different class, recurse through the structure as needed.
+ if ([obj isKindOfClass: [NSMenu class]] ||
+ [obj isKindOfClass: [NSPopUpButton class]])
+ {
+ NSArray *items = [obj itemArray];
+ NSEnumerator *en = [items objectEnumerator];
+ id item = nil;
+ while ((item = [en nextObject]) != nil)
+ {
+ [self _collectObjectsFromObject: item
+ withNode: elem];
+ }
+ }
+ else if ([obj isKindOfClass: [NSMenuItem class]])
+ {
+ NSMenu *sm = [obj submenu];
+ if (sm != nil)
+ {
+ [self _collectObjectsFromObject: sm
+ withNode: elem];
+ }
+ }
+ else if ([obj isKindOfClass: [NSWindow class]])
+ {
+ [self _collectObjectsFromObject: [obj contentView]
+ withNode: elem];
+ }
+ else if ([obj isKindOfClass: [NSView class]])
+ {
+ NSArray *subviews = [obj subviews];
+ NSEnumerator *en = [subviews objectEnumerator];
+ id v = nil;
+
+ while ((v = [en nextObject]) != nil)
+ {
+ [self _collectObjectsFromObject: v
+ withNode: elem];
+ }
+ }
+ }
+}
+
+- (void) _buildXIBDocumentWithParentNode: (NSXMLElement *)parentNode
+{
+ NSEnumerator *en = [[_gormDocument topLevelObjects] objectEnumerator];
+ id o = nil;
+
+ [_gormDocument deactivateEditors];
+ while ((o = [en nextObject]) != nil)
+ {
+ [self _collectObjectsFromObject: o
+ withNode: parentNode];
+ }
+ [_gormDocument reactivateEditors];
+}
+
+- (NSData *) data
+{
+ NSString *plugInId = @"com.apple.InterfaceBuilder.CocoaPlugin"; // @"gnu.gnustep.Gorm";
+ NSString *typeId = @"com.apple.InterfaceBuilder3.Cocoa.XIB"; // @"gnu.gnustep.Gorm";
+ // NSString *toolId = @"gnu.gnustep.Gorm";
+ // NSString *toolName = @"Gorm";
+ NSString *toolVersion = @"21507"; // [NSString stringWithFormat: @"%d", [GormFilePrefsManager currentVersion]];
+
+ // id delegate = [NSApp delegate];
+
+ // Build root element...
+ NSXMLElement *rootElement = [NSXMLNode elementWithName: @"document"];
+ NSXMLNode *attr = [NSXMLNode namespaceWithName: @"type"
+ stringValue: typeId];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"version" stringValue: @"3.0"];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"toolsVersion" stringValue: toolVersion];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"targetRuntime" stringValue: @"MacOSX.Cocoa"];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"useAutolayout" stringValue: @"YES"];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"propertyAccessControl" stringValue: @"none"];
+ [rootElement addAttribute: attr];
+
+ attr = [NSXMLNode attributeWithName: @"customObjectInstantiationMethod" stringValue: @"direct"];
+ [rootElement addAttribute: attr];
+
+ // Build dependencies...
+ NSXMLElement *dependencies = [NSXMLNode elementWithName: @"dependencies"];
+ NSXMLElement *deployment = [NSXMLNode elementWithName: @"deployment"];
+ attr = [NSXMLNode attributeWithName: @"identifier" stringValue: @"macosx"];
+ [deployment addAttribute: attr];
+ [dependencies addChild: deployment];
+
+ NSXMLElement *plugIn = [NSXMLNode elementWithName: @"plugIn"];
+ attr = [NSXMLNode attributeWithName: @"identifier" stringValue: plugInId];
+ [plugIn addAttribute: attr];
+ attr = [NSXMLNode attributeWithName: @"version" stringValue: toolVersion];
+ [plugIn addAttribute: attr];
+ [dependencies addChild: plugIn];
+
+ NSXMLElement *capability = [NSXMLNode elementWithName: @"capability"];
+ attr = [NSXMLNode attributeWithName: @"name" stringValue: plugInId];
+ [capability addAttribute: attr];
+ attr = [NSXMLNode attributeWithName: @"minToolsVersion" stringValue: toolVersion];
+ [capability addAttribute: attr];
+ [dependencies addChild: capability];
+ [rootElement addChild: dependencies];
+
+ NSXMLDocument *xibDocument = [NSXMLNode documentWithRootElement: rootElement];
+ NSXMLElement *objects = [NSXMLNode elementWithName: @"objects"];
+
+ // add body to document...
+ [rootElement addChild: objects];
+
+ // Recursively build the XIB document from the GormDocument...
+ [self _buildXIBDocumentWithParentNode: objects];
+
+ NSData *data = [xibDocument XMLDataWithOptions: NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement ];
+
+ return data;
+}
+
+- (BOOL) exportXIBDocumentWithName: (NSString *)name
+{
+ BOOL result = NO;
+
+ if (name != nil)
+ {
+ NSData *data = [self data];
+ NSString *xmlString = [[NSString alloc] initWithBytes: [data bytes] length: [data length] encoding: NSUTF8StringEncoding];
+
+ AUTORELEASE(xmlString);
+ result = [xmlString writeToFile: name atomically: YES];
+ }
+
+ return result;
+}
+
+@end
diff --git a/GormCore/Plugins/Xib/GormXibWrapperBuilder.m b/GormCore/Plugins/Xib/GormXibWrapperBuilder.m
new file mode 100644
index 00000000..e1d95c63
--- /dev/null
+++ b/GormCore/Plugins/Xib/GormXibWrapperBuilder.m
@@ -0,0 +1,53 @@
+/* GormWrapperBuilder
+ *
+ * Copyright (C) 2006-2013 Free Software Foundation, Inc.
+ *
+ * Author: Gregory John Casamento
+ * Date: 2006
+ *
+ * This file is part of GNUstep.
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
+ */
+
+#import
+#import
+
+#import
+
+#import "GormXIBModelGenerator.h"
+
+@interface GormXibWrapperBuilder : GormWrapperBuilder
+@end
+
+@implementation GormXibWrapperBuilder
+
++ (NSString *) fileType
+{
+ return @"GSXibFileType";
+}
+
+- (NSMutableDictionary *)buildFileWrapperDictionaryWithDocument: (GormDocument *)doc
+{
+ GormXIBModelGenerator *generator = [GormXIBModelGenerator xibWithGormDocument: doc];
+ NSData *data = [generator data];
+ NSMutableDictionary *fileWrappers = [NSMutableDictionary dictionary];
+ NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents: data];
+
+ [fileWrappers setObject: fileWrapper forKey: @"file.xib"];
+
+ return fileWrappers;
+}
+@end