diff -r c584149b22f0 -r a5f3abf8b9d1 ui/gtk/text.c
--- a/ui/gtk/text.c	Wed Mar 05 21:35:36 2025 +0100
+++ b/ui/gtk/text.c	Wed Mar 05 22:09:22 2025 +0100
@@ -62,6 +62,43 @@
     }
 }
 
+static void textarea_set_text_funcs(UiText *value) {
+    
+}
+
+#if GTK_MAJOR_VERSION == 2
+static void textarea_set_undomgr(GtkWidget *text_area, UiText *value) {
+    GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
+
+    if(!value->data2) {
+        value->data2 = ui_create_undomgr();
+    }
+
+    g_signal_connect(
+            buf,
+            "changed",
+            G_CALLBACK(ui_textbuf_changed),
+            uitext);
+
+    // register undo manager
+    g_signal_connect(
+            buf,
+            "insert-text",
+            G_CALLBACK(ui_textbuf_insert),
+            var);
+    g_signal_connect(
+            buf,
+            "delete-range",
+            G_CALLBACK(ui_textbuf_delete),
+            var); 
+    g_signal_connect(
+            buf,
+            "mark-set",
+            G_CALLBACK(selection_handler),
+            uitext);
+}
+#endif
+
 UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
     UiObject* current = uic_current_obj(obj);
     UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_TEXT);
@@ -114,13 +151,20 @@
     // bind value
     if(var) {
         UiText *value = var->value;
-        GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
-        
-        if(value->value.ptr) {
-            gtk_text_buffer_set_text(buf, value->value.ptr, -1);
-            value->value.free(value->value.ptr);
+        GtkTextBuffer *buf;
+        if(value->data1 && value->datatype == UI_TEXT_TYPE_BUFFER) {
+            buf = value->data1;
+        } else {
+            buf = gtk_text_buffer_new(NULL);
+            if(value->value.ptr) {
+                gtk_text_buffer_set_text(buf, value->value.ptr, -1);
+                value->value.free(value->value.ptr);
+            }
         }
-        
+        gtk_text_view_set_buffer(GTK_TEXT_VIEW(text_area), buf);
+        value->save = ui_textarea_save;
+        value->restore = ui_textarea_restore;
+        value->destroy = ui_textarea_text_destroy;
         value->get = ui_textarea_get;
         value->set = ui_textarea_set;
         value->getsubstr = ui_textarea_getsubstr;
@@ -130,35 +174,15 @@
         value->selection = ui_textarea_selection;
         value->length = ui_textarea_length;
         value->remove = ui_textarea_remove;
+        value->data1 = buf;
+        value->data2 = NULL;
+        value->datatype == UI_TEXT_TYPE_BUFFER;
         value->value.ptr = NULL;
         value->value.free = NULL;
-        value->obj = buf;
-        if(!value->undomgr) {
-            value->undomgr = ui_create_undomgr();
-        }
         
-        g_signal_connect(
-                buf,
-                "changed",
-                G_CALLBACK(ui_textbuf_changed),
-                uitext);
-        
-        // register undo manager
-        g_signal_connect(
-                buf,
-                "insert-text",
-                G_CALLBACK(ui_textbuf_insert),
-                var);
-        g_signal_connect(
-                buf,
-                "delete-range",
-                G_CALLBACK(ui_textbuf_delete),
-                var); 
-        g_signal_connect(
-                buf,
-                "mark-set",
-                G_CALLBACK(selection_handler),
-                uitext);
+#if GTK_MAJOR_VERSION == 2
+        textarea_set_undomgr(text_area, value);
+#endif
     }
     
     return scroll_area;
@@ -175,6 +199,20 @@
     return SCROLLEDWINDOW_GET_CHILD(textarea);
 }
 
+void ui_textarea_save(UiText *text) {
+    // NOOP
+}
+
+void ui_textarea_restore(UiText *text) {
+    GtkWidget *textarea = text->obj;
+    gtk_text_view_set_buffer(GTK_TEXT_VIEW(textarea), text->data1);
+}
+
+void ui_textarea_text_destroy(UiText *text) {
+    GtkTextBuffer *buf = text->data1;
+    g_object_unref(buf);
+}
+
 char* ui_textarea_get(UiText *text) {
     if(text->value.ptr) {
         text->value.free(text->value.ptr);
@@ -299,10 +337,10 @@
 {
     UiVar *var = data;
     UiText *value = var->value;
-    if(!value->undomgr) {
-        value->undomgr = ui_create_undomgr();
+    if(!value->data2) {
+        value->data2 = ui_create_undomgr();
     }
-    UiUndoMgr *mgr = value->undomgr;
+    UiUndoMgr *mgr = value->data2;
     if(!mgr->event) {
         return;
     }
@@ -371,10 +409,10 @@
 {
     UiVar *var = data;
     UiText *value = var->value;
-    if(!value->undomgr) {
-        value->undomgr = ui_create_undomgr();
+    if(!value->data2) {
+        value->data2 = ui_create_undomgr();
     }
-    UiUndoMgr *mgr = value->undomgr;
+    UiUndoMgr *mgr = value->data2;
     if(!mgr->event) {
         return;
     }
@@ -469,7 +507,7 @@
 }
 
 void ui_text_undo(UiText *value) {
-    UiUndoMgr *mgr = value->undomgr;
+    UiUndoMgr *mgr = value->data2;
     
     if(mgr->cur) {
         UiTextBufOp *op = mgr->cur;
@@ -498,7 +536,7 @@
 }
 
 void ui_text_redo(UiText *value) {
-    UiUndoMgr *mgr = value->undomgr;
+    UiUndoMgr *mgr = value->data2;
     
     UiTextBufOp *elm = NULL;
     if(mgr->cur) {