2 * Copyright (C) 2008, 2009, 2010, 2011 Philip Chimento and Marijn van Vliet.
5 * Chimara is free software copyrighted by Philip Chimento and Marijn van Vliet.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither of the names Philip Chimento or Marijn van Vliet, nor the name of
16 * any other contributor may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 #include <glib-object.h>
34 #include <glib/gi18n.h>
36 #include <libchimara/chimara-glk.h>
37 #include <libchimara/chimara-if.h>
43 typedef struct _ChimaraPlayerPrivate {
45 } ChimaraPlayerPrivate;
47 #define CHIMARA_PLAYER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_PLAYER, ChimaraPlayerPrivate))
48 #define CHIMARA_PLAYER_USE_PRIVATE ChimaraPlayerPrivate *priv = CHIMARA_PLAYER_PRIVATE(self)
50 G_DEFINE_TYPE(ChimaraPlayer, chimara_player, GTK_TYPE_WINDOW);
53 change_window_title(ChimaraGlk *glk, GParamSpec *pspec, GtkWindow *window)
55 gchar *program_name, *story_name, *title;
56 g_object_get(glk, "program-name", &program_name, "story-name", &story_name, NULL);
58 gtk_window_set_title(window, "Chimara");
62 title = g_strdup_printf("%s - Chimara", program_name);
64 title = g_strdup_printf("%s - %s - Chimara", program_name, story_name);
68 gtk_window_set_title(window, title);
73 on_css_changed(GSettings *prefs_settings, char *key, ChimaraPlayer *self)
76 g_settings_get(prefs_settings, "css-file", "ms", &user_css);
78 if(!chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), user_css, NULL)) {
79 /* If the setting didn't point to a CSS file, fail silently and
81 g_settings_set(prefs_settings, "css-file", "ms", NULL);
88 chimara_player_dispose(GObject *object)
90 ChimaraPlayer *self = CHIMARA_PLAYER(object);
91 if(chimara_glk_get_running(CHIMARA_GLK(self->glk))) {
92 chimara_glk_stop(CHIMARA_GLK(self->glk));
93 chimara_glk_wait(CHIMARA_GLK(self->glk));
97 G_OBJECT_CLASS(chimara_player_parent_class)->dispose(object);
101 chimara_player_finalize(GObject *object)
103 g_object_unref(CHIMARA_PLAYER(object)->glk);
106 G_OBJECT_CLASS(chimara_player_parent_class)->finalize(object);
110 chimara_player_class_init(ChimaraPlayerClass *klass)
112 /* Override methods of parent classes */
113 GObjectClass *object_class = G_OBJECT_CLASS(klass);
114 object_class->dispose = chimara_player_dispose;
115 object_class->finalize = chimara_player_finalize;
118 g_type_class_add_private(klass, sizeof(ChimaraPlayerPrivate));
122 chimara_player_init(ChimaraPlayer *self)
124 GError *error = NULL;
125 ChimaraApp *theapp = chimara_app_get();
127 /* Set parent properties */
129 "title", _("Chimara"),
130 "default-width", 600,
131 "default-height", 800,
134 /* Construct user interface */
135 char *object_ids[] = {
140 GtkBuilder *builder = new_builder_with_objects(object_ids);
142 GtkActionGroup *actiongroup = GTK_ACTION_GROUP(load_object(builder, "actiongroup"));
144 /* Set the default value of the "View/Toolbar" menu item upon creation of a
145 new window to the "show-toolbar-default" setting, but bind the setting
146 one-way only - we don't want toolbars to disappear suddenly */
147 GtkToggleAction *toolbar_action = GTK_TOGGLE_ACTION(load_object(builder, "toolbar"));
148 gtk_toggle_action_set_active(toolbar_action, g_settings_get_boolean(theapp->state_settings, "show-toolbar-default"));
149 g_settings_bind(theapp->state_settings, "show-toolbar-default", toolbar_action, "active", G_SETTINGS_BIND_SET);
151 self->glk = chimara_if_new();
152 g_object_set(self->glk,
153 "ignore-errors", TRUE,
154 /*"interpreter-number", CHIMARA_IF_ZMACHINE_TANDY_COLOR,*/
157 /* Set the CSS styles for the interpreter */
158 char *default_css = get_data_file_path("style.css");
159 if( !chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), default_css, &error) ) {
160 error_dialog(GTK_WINDOW(self), error, "Couldn't open default CSS file: ");
163 on_css_changed(theapp->prefs_settings, "css-file", self);
165 /* DON'T UNCOMMENT THIS your eyes will burn
166 but it is a good test of programmatically altering just one style
167 chimara_glk_set_css_from_string(CHIMARA_GLK(glk),
168 "buffer.normal { font-family: 'Comic Sans MS'; }");*/
170 GtkUIManager *uimanager = new_ui_manager("player.menus");
171 gtk_ui_manager_insert_action_group(uimanager, actiongroup, 0);
172 gtk_ui_manager_insert_action_group(uimanager, chimara_app_get_action_group(theapp), 1);
173 GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/player_menu");
174 self->toolbar = gtk_ui_manager_get_widget(uimanager, "/player_toolbar");
175 gtk_widget_set_no_show_all(self->toolbar, TRUE);
176 if(gtk_toggle_action_get_active(toolbar_action))
177 gtk_widget_show(self->toolbar);
179 gtk_widget_hide(self->toolbar);
181 /* Connect the accelerators */
182 GtkAccelGroup *accels = gtk_ui_manager_get_accel_group(uimanager);
183 gtk_window_add_accel_group(GTK_WINDOW(self), accels);
185 GtkBox *vbox = GTK_BOX(load_object(builder, "player-vbox"));
186 gtk_box_pack_end(vbox, self->glk, TRUE, TRUE, 0);
187 g_object_ref(self->glk); /* add an extra reference to keep it alive while
188 the Glk program shuts down */
189 gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
190 gtk_box_pack_start(vbox, self->toolbar, FALSE, FALSE, 0);
191 gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(vbox));
193 gtk_builder_connect_signals(builder, self);
194 g_signal_connect(self->glk, "notify::program-name", G_CALLBACK(change_window_title), self);
195 g_signal_connect(self->glk, "notify::story-name", G_CALLBACK(change_window_title), self);
196 g_signal_connect(theapp->prefs_settings, "changed::css-file", G_CALLBACK(on_css_changed), self);
198 g_object_unref(builder);
199 g_object_unref(uimanager);
202 /* PUBLIC FUNCTIONS */
205 chimara_player_new(void)
207 return GTK_WIDGET(g_object_new(CHIMARA_TYPE_PLAYER,
208 "type", GTK_WINDOW_TOPLEVEL,
213 chimara_player_set_user_css_file(ChimaraPlayer *self, const char *filename)
215 chimara_glk_set_css_to_default(CHIMARA_GLK(self->glk));
216 chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), filename, NULL);
219 /* GLADE CALLBACKS */
222 /* If a game is running in @glk, warn the user that they will quit the currently
223 running game if they open a new one. Returns TRUE if no game was running.
224 Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
225 game if the user wishes to continue. */
227 confirm_open_new_game(ChimaraGlk *glk)
229 g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
231 GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
233 if(chimara_glk_get_running(glk)) {
234 GtkWidget *dialog = gtk_message_dialog_new(window,
235 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
238 _("Are you sure you want to open a new game?"));
239 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
240 _("If you open a new game, you will quit the one you are currently playing."));
241 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
242 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
243 gtk_widget_destroy(dialog);
245 if(response != GTK_RESPONSE_OK)
248 chimara_glk_stop(glk);
249 chimara_glk_wait(glk);
256 on_stop_activate(GtkAction *action, ChimaraPlayer *player)
258 chimara_glk_stop(CHIMARA_GLK(player->glk));
262 on_copy_activate(GtkAction *action, ChimaraPlayer *player)
264 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
265 /* Call "copy clipboard" on any widget that defines it */
266 if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
267 g_signal_emit_by_name(focus, "copy-clipboard");
271 on_paste_activate(GtkAction *action, ChimaraPlayer *player)
273 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
274 /* Call "paste clipboard" on any widget that defines it */
275 if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
276 g_signal_emit_by_name(focus, "paste-clipboard");
280 on_toolbar_toggled(GtkToggleAction *action, ChimaraPlayer *player)
282 if(gtk_toggle_action_get_active(action))
283 gtk_widget_show(player->toolbar);
285 gtk_widget_hide(player->toolbar);
289 on_undo_activate(GtkAction *action, ChimaraPlayer *player)
291 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "undo");
295 on_save_activate(GtkAction *action, ChimaraPlayer *player)
297 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "save");
301 on_restore_activate(GtkAction *action, ChimaraPlayer *player)
303 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restore");
307 on_restart_activate(GtkAction *action, ChimaraPlayer *player)
309 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restart");
313 on_quit_activate(GtkAction *action, ChimaraPlayer *player)
315 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "quit");