Clean up external Blorb file finding code
[projects/chimara/chimara.git] / player / callbacks.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * callbacks.c
4  * Copyright (C) Philip en Marijn 2008 <>
5  * 
6  * callbacks.c is free software copyrighted by Philip en Marijn.
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name ``Philip en Marijn'' nor the name of any other
17  *    contributor may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  * 
20  * callbacks.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include <libchimara/chimara-glk.h>
37 #include <libchimara/chimara-if.h>
38 #include <config.h>
39 #include "error.h"
40
41 /* If a game is running in @glk, warn the user that they will quit the currently
42 running game if they open a new one. Returns TRUE if no game was running.
43 Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
44 game if the user wishes to continue. */
45 static gboolean
46 confirm_open_new_game(ChimaraGlk *glk)
47 {
48         g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
49         
50         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
51         
52         if(chimara_glk_get_running(glk)) {
53                 GtkWidget *dialog = gtk_message_dialog_new(window,
54                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
55                     GTK_MESSAGE_WARNING,
56                     GTK_BUTTONS_CANCEL,
57                     _("Are you sure you want to open a new game?"));
58                 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
59                     _("If you open a new game, you will quit the one you are currently playing."));
60                 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
61                 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
62                 gtk_widget_destroy(dialog);
63                 
64                 if(response != GTK_RESPONSE_OK)
65                         return FALSE;
66
67                 chimara_glk_stop(glk);
68                 chimara_glk_wait(glk);
69         }
70         return TRUE;
71 }
72
73 void 
74 on_open_activate(GtkAction *action, ChimaraGlk *glk) 
75 {
76         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
77         
78         if(!confirm_open_new_game(glk))
79                 return;
80
81         GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Open Game"),
82             window,
83             GTK_FILE_CHOOSER_ACTION_OPEN,
84             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
85             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
86             NULL);
87         if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
88                 GError *error = NULL;
89                 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
90
91                 /* See if there is a corresponding graphics file */
92                 /* FIXME: hardcoded path */
93                 gchar *path = g_path_get_dirname(filename);
94                 gchar *scratch = g_path_get_basename(filename);
95                 *(strrchr(scratch, '.')) = '\0';
96                 gchar *blorbfile = g_strconcat(path, "/../Resources/", scratch, ".blb", NULL);
97                 if(g_file_test(blorbfile, G_FILE_TEST_EXISTS)) {
98                         g_object_set(glk, "graphics-file", blorbfile, NULL);
99                         g_printerr("Setting graphics file to %s\n", blorbfile);
100                 }
101                 g_free(blorbfile);
102                 g_free(path);
103                 g_free(scratch);
104
105                 if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
106                         error_dialog(window, error, _("Could not open game file '%s': "), filename);
107                         g_free(filename);
108                         gtk_widget_destroy(dialog);
109                         return;
110                 }
111                 
112                 /* Add file to recent files list */
113                 GtkRecentManager *manager = gtk_recent_manager_get_default();
114                 gchar *uri;
115                 
116                 if(!(uri = g_filename_to_uri(filename, NULL, &error)))
117                         g_warning(_("Could not convert filename '%s' to URI: %s"), filename, error->message);
118                 else {
119                         if(!gtk_recent_manager_add_item(manager, uri))
120                                 g_warning(_("Could not add URI '%s' to recent files list."), uri);
121                         g_free(uri);
122                 }
123                 g_free(filename);
124         }
125         gtk_widget_destroy(dialog);
126 }
127
128 void
129 on_recent_item_activated(GtkRecentChooser *chooser, ChimaraGlk *glk)
130 {
131         GError *error = NULL;
132         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
133         gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
134         gchar *filename;
135         if(!(filename = g_filename_from_uri(uri, NULL, &error))) {
136                 error_dialog(window, error, _("Could not open game file '%s': "), uri);
137                 g_free(uri);
138                 return;
139         }
140         
141         if(!confirm_open_new_game(glk)) {
142                 g_free(filename);
143                 g_free(uri);
144                 return;
145         }
146         
147         if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
148                 error_dialog(window, error, _("Could not open game file '%s': "), filename);
149                 g_free(filename);
150                 g_free(uri);
151                 return;
152         }
153         g_free(filename);
154         
155         /* Add file to recent files list again, this updates it to most recently used */
156         GtkRecentManager *manager = gtk_recent_manager_get_default();
157         if(!gtk_recent_manager_add_item(manager, uri))
158                 g_warning(_("Could not add URI '%s' to recent files list."), uri);
159         
160         g_free(uri);
161 }
162
163 void
164 on_stop_activate(GtkAction *action, ChimaraGlk *glk)
165 {
166         chimara_glk_stop(glk);
167 }
168
169 void 
170 on_quit_chimara_activate(GtkAction *action, ChimaraGlk *glk) 
171 {
172         gtk_main_quit();
173 }
174
175 void
176 on_copy_activate(GtkAction *action, ChimaraGlk *glk)
177 {
178         GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
179         GtkWidget *focus = gtk_window_get_focus(toplevel);
180         /* Call "copy clipboard" on any widget that defines it */
181         if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
182                 g_signal_emit_by_name(focus, "copy-clipboard");
183 }
184
185 void
186 on_paste_activate(GtkAction *action, ChimaraGlk *glk)
187 {
188         GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
189         GtkWidget *focus = gtk_window_get_focus(toplevel);
190         /* Call "paste clipboard" on any widget that defines it */
191         if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
192                 g_signal_emit_by_name(focus, "paste-clipboard");
193 }
194
195 void
196 on_preferences_activate(GtkAction *action, ChimaraGlk *glk)
197 {
198         extern GtkWidget *prefswindow;
199         gtk_window_present(GTK_WINDOW(prefswindow));
200 }
201
202 void
203 on_toolbar_toggled(GtkToggleAction *action, ChimaraGlk *glk)
204 {
205         extern GtkWidget *toolbar;
206         
207         if(gtk_toggle_action_get_active(action))
208                 gtk_widget_show(toolbar);
209         else
210                 gtk_widget_hide(toolbar);
211 }
212
213 void
214 on_undo_activate(GtkAction *action, ChimaraGlk *glk)
215 {
216         chimara_glk_feed_line_input(glk, "undo");
217 }
218
219 void 
220 on_save_activate(GtkAction *action, ChimaraGlk *glk) 
221 {
222         chimara_glk_feed_line_input(glk, "save");
223 }
224
225 void 
226 on_restore_activate(GtkAction *action, ChimaraGlk *glk) 
227 {
228         chimara_glk_feed_line_input(glk, "restore");
229 }
230
231 void 
232 on_restart_activate(GtkAction *action, ChimaraGlk *glk) 
233 {
234         chimara_glk_feed_line_input(glk, "restart");
235 }
236
237 void 
238 on_quit_activate(GtkAction *action, ChimaraGlk *glk) 
239 {
240         chimara_glk_feed_line_input(glk, "quit");
241 }
242
243 void
244 on_about_activate(GtkAction *action, ChimaraGlk *glk)
245 {
246         extern GtkWidget *aboutwindow;
247         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(aboutwindow), PACKAGE_VERSION);
248         gtk_window_present(GTK_WINDOW(aboutwindow));
249 }
250
251 gboolean 
252 on_window_delete_event(GtkWidget *widget, GdkEvent *event, ChimaraGlk *glk) 
253 {
254         gtk_main_quit();
255         return TRUE;
256 }