Make sure atk objects exist while processing signals

https://bugzilla.gnome.org/show_bug.cgi?id=793543

---
 jni/src/AtkWrapper.c |   90 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 69 insertions(+), 21 deletions(-)

--- a/jni/src/AtkWrapper.c
+++ b/jni/src/AtkWrapper.c
@@ -208,6 +208,7 @@ alloc_callback_para (JNIEnv *jniEnv, job
       g_warning("\nalloc_callback_para: jaw_impl == NULL\n");
     return NULL;
   }
+  g_object_ref(G_OBJECT(jaw_impl));
   CallbackPara *para = g_new(CallbackPara, 1);
   para->global_ac = ac;
   para->jaw_impl = jaw_impl;
@@ -235,6 +236,8 @@ free_callback_para (CallbackPara *para)
 
   (*jniEnv)->DeleteGlobalRef(jniEnv, para->global_ac);
 
+  g_object_unref(G_OBJECT(para->jaw_impl));
+
   if (para->args) {
     (*jniEnv)->DeleteGlobalRef(jniEnv, para->args);
   }
@@ -242,6 +245,36 @@ free_callback_para (CallbackPara *para)
   g_free(para);
 }
 
+/* List of callback params to be freed */
+static GSList *callback_para_frees;
+static GMutex callback_para_frees_mutex;
+
+/* Add a note that this callback param should be freed from the application */
+static void queue_free_callback_para(CallbackPara *para)
+{
+  g_mutex_lock(&callback_para_frees_mutex);
+  callback_para_frees = g_slist_prepend(callback_para_frees, para);
+  g_mutex_unlock(&callback_para_frees_mutex);
+}
+
+/* Process the unreference requests */
+static void callback_para_process_frees(void)
+{
+  GSList *list, *cur, *next;
+
+  g_mutex_lock(&callback_para_frees_mutex);
+  list = callback_para_frees;
+  callback_para_frees = NULL;
+  g_mutex_unlock(&callback_para_frees_mutex);
+
+  for (cur = list; cur != NULL; cur = next)
+  {
+    free_callback_para(cur->data);
+    next = g_slist_next(cur);
+    g_slist_free_1(cur);
+  }
+}
+
 static gboolean
 focus_notify_handler (gpointer p)
 {
@@ -252,7 +285,7 @@ focus_notify_handler (gpointer p)
                                  ATK_STATE_SHOWING,
                                  1);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -268,6 +301,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(focus_notify_handler, para);
 }
@@ -282,13 +316,13 @@ window_open_handler (gpointer p)
   if (!g_strcmp0(atk_role_get_name(atk_object_get_role(atk_obj)),
                  "redundant object"))
   {
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
 
   if (atk_object_get_role(atk_obj) == ATK_ROLE_TOOL_TIP)
   {
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
 
@@ -307,7 +341,7 @@ window_open_handler (gpointer p)
     g_signal_emit_by_name(atk_obj, "create", 0);
   }
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -324,7 +358,8 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      if (jaw_debug)
      g_warning("%s: global_ac == NULL", __func__);
    return;
-  } 
+  }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   para->is_toplevel = (jIsToplevel == JNI_TRUE) ? TRUE : FALSE;
   jni_main_idle_add(window_open_handler, para);
@@ -339,13 +374,13 @@ window_close_handler (gpointer p)
 
   if (!g_strcmp0(atk_role_get_name(atk_object_get_role(atk_obj)), "redundant object"))
   {
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
 
   if (atk_object_get_role(atk_obj) == ATK_ROLE_TOOL_TIP)
   {
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
 
@@ -363,7 +398,7 @@ window_close_handler (gpointer p)
     g_signal_emit_by_name(atk_obj, "destroy", 0);
   }
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -380,6 +415,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   para->is_toplevel = (jIsToplevel == JNI_TRUE) ? TRUE : FALSE;
   jni_main_idle_add(window_close_handler, para);
@@ -393,7 +429,7 @@ window_minimize_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "minimize", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -409,6 +445,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(window_minimize_handler, para);
 }
@@ -421,7 +458,7 @@ window_maximize_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "maximize", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -436,6 +473,7 @@ JNIEXPORT void JNICALL Java_org_GNOME_Ac
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac );
   jni_main_idle_add(window_maximize_handler, para);
 }
@@ -448,7 +486,7 @@ window_restore_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "restore", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -464,6 +502,7 @@ JNIEXPORT void JNICALL Java_org_GNOME_Ac
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(window_restore_handler, para);
 }
@@ -476,7 +515,7 @@ window_activate_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "activate", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -491,6 +530,7 @@ JNIEXPORT void JNICALL Java_org_GNOME_Ac
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(window_activate_handler, para);
 }
@@ -503,7 +543,7 @@ window_deactivate_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "deactivate", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -520,6 +560,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(window_deactivate_handler, para);
 }
@@ -532,7 +573,7 @@ window_state_change_handler (gpointer p)
 
   g_signal_emit_by_name(atk_obj, "state-change", 0);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -549,6 +590,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(window_state_change_handler, para);
 }
@@ -815,7 +857,7 @@ signal_emit_handler (gpointer p)
     default:
       break;
   }
-  free_callback_para(para);
+  queue_free_callback_para(para);
   return G_SOURCE_REMOVE;
 }
 
@@ -832,6 +874,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   jobjectArray global_args = (jobjectArray)(*jniEnv)->NewGlobalRef(jniEnv, args);
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   para->signal_id = (gint)id;
@@ -900,7 +943,7 @@ object_state_change_handler (gpointer p)
                                  para->atk_state,
                                  para->state_value);
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
   return G_SOURCE_REMOVE;
 }
 
@@ -917,6 +960,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   AtkStateType state_type = jaw_util_get_atk_state_type_from_java_state( jniEnv, state );
   para->atk_state = state_type;
@@ -941,7 +985,7 @@ component_added_handler (gpointer p)
                                    1);
   }
 
-  free_callback_para(para);
+  queue_free_callback_para(para);
   return G_SOURCE_REMOVE;
 }
 
@@ -957,6 +1001,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
       g_warning("Java_org_GNOME_Accessibility_AtkWrapper_componentAdded: global_ac == NULL");
     return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(component_added_handler, para);
 }
@@ -971,12 +1016,12 @@ component_removed_handler (gpointer p)
   {
     if (jaw_debug)
       g_warning("component_removed_handler: atk_obj == NULL");
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
   if (atk_object_get_role(atk_obj) == ATK_ROLE_TOOL_TIP)
     atk_object_notify_state_change(atk_obj, ATK_STATE_SHOWING, FALSE);
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -993,6 +1038,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
       g_warning("Java_org_GNOME_Accessibility_AtkWrapper_componentRemoved: global_ac == NULL");
     return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(component_removed_handler, para);
 }
@@ -1010,11 +1056,11 @@ bounds_changed_handler (gpointer p)
   {
     if (jaw_debug)
       g_warning("bounds_changed_handler: atk_obj == NULL");
-    free_callback_para(para);
+    queue_free_callback_para(para);
     return G_SOURCE_REMOVE;
   }
   g_signal_emit_by_name(atk_obj, "bounds_changed");
-  free_callback_para(para);
+  queue_free_callback_para(para);
 
   return G_SOURCE_REMOVE;
 }
@@ -1030,6 +1076,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
      g_warning("%s: global_ac == NULL", __func__);
    return;
   }
+  callback_para_process_frees();
   CallbackPara *para = alloc_callback_para(jniEnv, global_ac);
   jni_main_idle_add(bounds_changed_handler, para);
 }
@@ -1149,6 +1196,7 @@ JNICALL Java_org_GNOME_Accessibility_Atk
 {
   jboolean key_consumed;
   jobject global_key_event = (*jniEnv)->NewGlobalRef(jniEnv, jAtkKeyEvent);
+  callback_para_process_frees();
   jni_main_idle_add(key_dispatch_handler, (gpointer)global_key_event);
 
   if(jaw_debug)
