summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Judson Rosen2017-03-26 22:24:41 -0400
committerJoshua Judson Rosen2017-03-28 22:07:50 -0400
commit7be1d57200e9672910ae0cef74ee0074e171dbf1 (patch)
tree4f0a00643d025d9404484f4592a8f6c81bc40710
parentapi: accept symbols (as well as strings) (diff)
downloadgnurobots-7be1d57200e9672910ae0cef74ee0074e171dbf1.tar.gz
Invert GTK+/guile thread relationship
Making the GTK+ thread the main thread, and subordinating the guile thread, lets the GUI continue to live after the robot has died-- which means that we'll be able to switch to just doing everything in the GUI without requiring a separate xterm to see the final stats after the robot dies.
-rw-r--r--include/ui-window.h2
-rw-r--r--src/main.c67
-rw-r--r--src/ui-window.c13
3 files changed, 45 insertions, 37 deletions
diff --git a/include/ui-window.h b/include/ui-window.h
index d9740a2..c8fa337 100644
--- a/include/ui-window.h
+++ b/include/ui-window.h
@@ -54,7 +54,7 @@ struct _UIWindowClass
GType ui_window_get_type(void) G_GNUC_CONST;
GtkWidget *ui_window_new();
-void ui_window_postinit(UIWindow *window, Map* map);
+void ui_window_postinit(UIWindow *window, Map* volatile* map);
G_END_DECLS
diff --git a/src/main.c b/src/main.c
index 8710ca1..f8ea6d4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -49,9 +49,13 @@ GList *robots = NULL;
GRobot *robot = NULL; /* The current robot */
UIWindow *ui;
UIArena *arena;
-Map *map;
+Map *map = NULL;
+gboolean loading = TRUE;
+volatile gboolean *ploading = &loading;
-gpointer callback(gpointer data);
+gpointer callback_scm(gpointer data);
+void gui_init();
+void gui_main();
SCM catch_handler(void *data, SCM tag, SCM throw_args);
gint is_file_readable(const gchar * filename);
@@ -67,6 +71,7 @@ gint main(gint argc, gchar *argv[])
gchar maps_path[MAX_PATH], scripts_path[MAX_PATH];
+ static
gchar *main_argv[5] = { "GNU Robots",
NULL,
NULL,
@@ -252,7 +257,20 @@ gint main(gint argc, gchar *argv[])
main_argv[2] = "";
}
+ gui_init();
+
+ g_thread_unref(g_thread_new(NULL, callback_scm, main_argv));
+
+ gui_main();
+
+ return 0; /* never gets here, but keeps compiler happy */
+}
+
+gpointer callback_scm(gpointer data)
+{
/* Start Guile environment. Does not exit */
+ char **main_argv = data;
+
g_printf("%s\n", PKGINFO);
g_printf("%s\n", COPYRIGHT);
g_printf("GNU Robots comes with ABSOLUTELY NO WARRANTY\n");
@@ -264,7 +282,7 @@ gint main(gint argc, gchar *argv[])
scm_boot_guile(3, main_argv, main_prog, NULL);
- return 0; /* never gets here, but keeps compiler happy */
+ return NULL; /* never gets here, but keeps compiler happy */
}
/************************************************************************
@@ -278,8 +296,6 @@ void main_prog(void *closure, gint argc, gchar *argv[])
{
gchar *map_file = argv[1];
gchar *robot_program = argv[2];
- gboolean loading = TRUE;
- volatile gboolean *ploading = &loading;
api_init();
@@ -293,9 +309,6 @@ void main_prog(void *closure, gint argc, gchar *argv[])
exit_nicely();
}
- gdk_threads_init();
- g_thread_unref(g_thread_new(NULL, callback, &loading));
-
/* ensure the robot is placed properly */
MAP_SET_OBJECT(map, G_ROBOT_POSITION_Y(robot),
G_ROBOT_POSITION_X(robot), ROBOT);
@@ -339,27 +352,33 @@ void main_prog(void *closure, gint argc, gchar *argv[])
exit_nicely();
}
-gpointer callback(gpointer data)
+void gui_init()
{
+ g_printf("Loading GTK Interface ... Please wait\n\n");
+
+ gdk_threads_init();
+ gdk_threads_enter();
gtk_init(0, NULL);
ui = UI_WINDOW(ui_window_new());
- ui_window_postinit(ui, map);
-
arena = UI_ARENA(ui->priv->arena);
+ gdk_threads_leave();
+}
+
+void gui_main()
+{
+ gdk_threads_enter();
+ ui_window_postinit(ui, &map); /* waits for guile to load map... */
/* draw the map */
ui_arena_draw(arena);
ui_arena_update_status(arena, "Welcome to GNU Robots",
robot->energy, robot->score, robot->shields);
- *(gboolean*)data = FALSE;
+ *ploading = FALSE;
- gdk_threads_enter();
gtk_main();
gdk_threads_leave();
-
- return NULL;
}
/************************************************************************
@@ -410,27 +429,12 @@ void exit_nicely()
{
glong score, energy, shields, shots, units;
- /* Stop the UI */
- if (ui != NULL)
- {
- g_object_unref(G_OBJECT(ui));
- }
-
- /* Get rid of the map object */
- if (map != NULL)
- {
- g_object_unref(G_OBJECT(map));
- }
-
/* Show statistics */
g_object_get(G_OBJECT(robot),
"shields", &shields,
"energy", &energy,
"units", &units, "shots", &shots, "score", &score, NULL);
- g_list_foreach(robots, (GFunc) g_object_unref, NULL);
- g_list_free(robots);
-
g_printf(
"\n-----------------------STATISTICS-----------------------\n");
g_printf("Shields: %ld\n", (shields < 0 ? 0 : shields));
@@ -450,8 +454,7 @@ void exit_nicely()
g_printf("** Robot ran out of energy.\n");
}
- /* Quit program */
- exit(0);
+ g_thread_exit(0);
}
/************************************************************************
diff --git a/src/ui-window.c b/src/ui-window.c
index fb6f2ed..e923c24 100644
--- a/src/ui-window.c
+++ b/src/ui-window.c
@@ -56,16 +56,21 @@ static void ui_window_init(UIWindow *window)
gtk_window_set_title(GTK_WINDOW(window), "GNU Robots");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+
+ window->priv->cmdwin = ui_cmdwin_new();
+ window->priv->arena = ui_arena_new();
}
-void ui_window_postinit(UIWindow *window, Map* map)
+void ui_window_postinit(UIWindow *window, Map* volatile* map)
{
GtkWidget *vbox;
vbox = gtk_vbox_new(FALSE, 2);
- window->priv->cmdwin = ui_cmdwin_new();
- window->priv->arena = ui_arena_new();
- ui_arena_set_map(UI_ARENA(window->priv->arena), map);
+
+ while(!*map); /* wait for map object creation by guile thread */
+
+ /* ... because we need guile to load the map before we do this: */
+ ui_arena_set_map(UI_ARENA(window->priv->arena), *map);
/* TODO: Add menu first etc */
gtk_box_pack_start(GTK_BOX(vbox), window->priv->arena, TRUE, TRUE, 0);