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