foxygit / doom Log in
commit bf2f9ea62a48d70496057e4f7e444e746e61f462
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sat Sep 9 16:48:09 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sat Sep 9 16:48:09 2006 +0000

    Add reference counts on callback tables so that if a callback destroys
    the widget that owns the callback the program doesnt crash.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 599
---
 textscreen/txt_widget.c | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c
index 79528c7f..c66cf8dc 100644
--- a/textscreen/txt_widget.c
+++ b/textscreen/txt_widget.c
@@ -33,6 +33,7 @@ typedef struct

 struct txt_callback_table_s
 {
+    int refcount;
     txt_callback_t *callbacks;
     int num_callbacks;
 };
@@ -44,21 +45,34 @@ txt_callback_table_t *TXT_NewCallbackTable(void)
     table = malloc(sizeof(txt_callback_table_t));
     table->callbacks = NULL;
     table->num_callbacks = 0;
+    table->refcount = 1;

     return table;
 }

-void TXT_DestroyCallbackTable(txt_callback_table_t *table)
+void TXT_RefCallbackTable(txt_callback_table_t *table)
+{
+    ++table->refcount;
+}
+
+void TXT_UnrefCallbackTable(txt_callback_table_t *table)
 {
     int i;

-    for (i=0; i<table->num_callbacks; ++i)
+    --table->refcount;
+
+    if (table->refcount == 0)
     {
-        free(table->callbacks[i].signal_name);
-    }
+        // No more references to this table
+
+        for (i=0; i<table->num_callbacks; ++i)
+        {
+            free(table->callbacks[i].signal_name);
+        }

-    free(table->callbacks);
-    free(table);
+        free(table->callbacks);
+        free(table);
+    }
 }

 void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class)
@@ -111,6 +125,11 @@ void TXT_EmitSignal(TXT_UNCAST_ARG(widget), char *signal_name)

     table = widget->callback_table;

+    // Don't destroy the table while we're searching through it
+    // (one of the callbacks may destroy this window)
+
+    TXT_RefCallbackTable(table);
+
     // Search the table for all callbacks with this name and invoke
     // the functions.

@@ -121,6 +140,10 @@ void TXT_EmitSignal(TXT_UNCAST_ARG(widget), char *signal_name)
             table->callbacks[i].func(widget, table->callbacks[i].user_data);
         }
     }
+
+    // Finished using the table
+
+    TXT_UnrefCallbackTable(table);
 }

 void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget))
@@ -148,7 +171,7 @@ void TXT_DestroyWidget(TXT_UNCAST_ARG(widget))
     TXT_CAST_ARG(txt_widget_t, widget);

     widget->widget_class->destructor(widget);
-    TXT_DestroyCallbackTable(widget->callback_table);
+    TXT_UnrefCallbackTable(widget->callback_table);
     free(widget);
 }