Fix some memory leakage
[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 /* Internal function: See if there is a corresponding graphics file */
74 static void
75 search_for_graphics_file(const char *filename, ChimaraIF *glk)
76 {
77
78         extern GSettings *prefs_settings;
79
80         /* First get the name of the story file */
81         char *scratch = g_path_get_basename(filename);
82         *(strrchr(scratch, '.')) = '\0';
83
84         /* Check in the stored resource path, if set */
85         char *resource_path;
86         g_settings_get(prefs_settings, "resource-path", "ms", &resource_path);
87
88         /* Otherwise check in the current directory */
89         if(!resource_path)
90                 resource_path = g_path_get_dirname(filename);
91
92         char *blorbfile = g_strconcat(resource_path, "/", scratch, ".blb", NULL);
93         if(g_file_test(blorbfile, G_FILE_TEST_EXISTS))
94                 g_object_set(glk, "graphics-file", blorbfile, NULL);
95
96         g_free(blorbfile);
97         g_free(scratch);
98         g_free(resource_path);
99 }
100
101 void
102 on_open_activate(GtkAction *action, ChimaraGlk *glk) 
103 {
104         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
105         
106         if(!confirm_open_new_game(glk))
107                 return;
108
109         GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Open Game"),
110             window,
111             GTK_FILE_CHOOSER_ACTION_OPEN,
112             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
113             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
114             NULL);
115
116         /* Get last opened path */
117         extern GSettings *state_settings;
118         gchar *path;
119         g_settings_get(state_settings, "last-open-path", "ms", &path);
120         if(path) {
121                 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
122                 g_free(path);
123         }
124
125         if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
126                 GError *error = NULL;
127                 extern GSettings *prefs_settings;
128                 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
129
130                 search_for_graphics_file(filename, CHIMARA_IF(glk));
131                 if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
132                         error_dialog(window, error, _("Could not open game file '%s': "), filename);
133                         g_free(filename);
134                         gtk_widget_destroy(dialog);
135                         return;
136                 }
137                 
138                 path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
139                 if(path) {
140                         g_settings_set(state_settings, "last-open-path", "ms", path);
141                         g_free(path);
142                 }
143
144                 /* Add file to recent files list */
145                 GtkRecentManager *manager = gtk_recent_manager_get_default();
146                 gchar *uri;
147                 
148                 if(!(uri = g_filename_to_uri(filename, NULL, &error)))
149                         g_warning(_("Could not convert filename '%s' to URI: %s"), filename, error->message);
150                 else {
151                         if(!gtk_recent_manager_add_item(manager, uri))
152                                 g_warning(_("Could not add URI '%s' to recent files list."), uri);
153                         g_free(uri);
154                 }
155                 g_free(filename);
156         }
157         gtk_widget_destroy(dialog);
158 }
159
160 void
161 on_recent_item_activated(GtkRecentChooser *chooser, ChimaraGlk *glk)
162 {
163         GError *error = NULL;
164         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
165         gchar *uri = gtk_recent_chooser_get_current_uri(chooser);
166         gchar *filename;
167         if(!(filename = g_filename_from_uri(uri, NULL, &error))) {
168                 error_dialog(window, error, _("Could not open game file '%s': "), uri);
169                 goto finally;
170         }
171         
172         if(!confirm_open_new_game(glk))
173                 goto finally2;
174         
175         search_for_graphics_file(filename, CHIMARA_IF(glk));
176         if(!chimara_if_run_game(CHIMARA_IF(glk), filename, &error)) {
177                 error_dialog(window, error, _("Could not open game file '%s': "), filename);
178                 goto finally2;
179         }
180         
181         /* Add file to recent files list again, this updates it to most recently used */
182         GtkRecentManager *manager = gtk_recent_manager_get_default();
183         if(!gtk_recent_manager_add_item(manager, uri))
184                 g_warning(_("Could not add URI '%s' to recent files list."), uri);
185
186 finally2:
187         g_free(filename);
188 finally:
189         g_free(uri);
190 }
191
192 void
193 on_stop_activate(GtkAction *action, ChimaraGlk *glk)
194 {
195         chimara_glk_stop(glk);
196 }
197
198 void 
199 on_quit_chimara_activate(GtkAction *action, ChimaraGlk *glk) 
200 {
201         gtk_main_quit();
202 }
203
204 void
205 on_copy_activate(GtkAction *action, ChimaraGlk *glk)
206 {
207         GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
208         GtkWidget *focus = gtk_window_get_focus(toplevel);
209         /* Call "copy clipboard" on any widget that defines it */
210         if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
211                 g_signal_emit_by_name(focus, "copy-clipboard");
212 }
213
214 void
215 on_paste_activate(GtkAction *action, ChimaraGlk *glk)
216 {
217         GtkWindow *toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
218         GtkWidget *focus = gtk_window_get_focus(toplevel);
219         /* Call "paste clipboard" on any widget that defines it */
220         if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
221                 g_signal_emit_by_name(focus, "paste-clipboard");
222 }
223
224 void
225 on_preferences_activate(GtkAction *action, ChimaraGlk *glk)
226 {
227         extern GtkWidget *prefswindow;
228         gtk_window_present(GTK_WINDOW(prefswindow));
229 }
230
231 void
232 on_toolbar_toggled(GtkToggleAction *action, ChimaraGlk *glk)
233 {
234         extern GtkWidget *toolbar;
235         
236         if(gtk_toggle_action_get_active(action))
237                 gtk_widget_show(toolbar);
238         else
239                 gtk_widget_hide(toolbar);
240 }
241
242 void
243 on_undo_activate(GtkAction *action, ChimaraGlk *glk)
244 {
245         chimara_glk_feed_line_input(glk, "undo");
246 }
247
248 void 
249 on_save_activate(GtkAction *action, ChimaraGlk *glk) 
250 {
251         chimara_glk_feed_line_input(glk, "save");
252 }
253
254 void 
255 on_restore_activate(GtkAction *action, ChimaraGlk *glk) 
256 {
257         chimara_glk_feed_line_input(glk, "restore");
258 }
259
260 void 
261 on_restart_activate(GtkAction *action, ChimaraGlk *glk) 
262 {
263         chimara_glk_feed_line_input(glk, "restart");
264 }
265
266 void 
267 on_quit_activate(GtkAction *action, ChimaraGlk *glk) 
268 {
269         chimara_glk_feed_line_input(glk, "quit");
270 }
271
272 void
273 on_about_activate(GtkAction *action, ChimaraGlk *glk)
274 {
275         extern GtkWidget *aboutwindow;
276         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(aboutwindow), PACKAGE_VERSION);
277         gtk_window_present(GTK_WINDOW(aboutwindow));
278 }
279
280 gboolean 
281 on_window_delete_event(GtkWidget *widget, GdkEvent *event, ChimaraGlk *glk) 
282 {
283         gtk_main_quit();
284         return TRUE;
285 }