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 chimara_player_dispose(GObject *object)
75 ChimaraPlayer *self = CHIMARA_PLAYER(object);
76 if(chimara_glk_get_running(CHIMARA_GLK(self->glk))) {
77 chimara_glk_stop(CHIMARA_GLK(self->glk));
78 chimara_glk_wait(CHIMARA_GLK(self->glk));
82 G_OBJECT_CLASS(chimara_player_parent_class)->dispose(object);
86 chimara_player_finalize(GObject *object)
88 g_object_unref(CHIMARA_PLAYER(object)->glk);
91 G_OBJECT_CLASS(chimara_player_parent_class)->finalize(object);
95 chimara_player_class_init(ChimaraPlayerClass *klass)
97 /* Override methods of parent classes */
98 GObjectClass *object_class = G_OBJECT_CLASS(klass);
99 object_class->dispose = chimara_player_dispose;
100 object_class->finalize = chimara_player_finalize;
103 g_type_class_add_private(klass, sizeof(ChimaraPlayerPrivate));
107 chimara_player_init(ChimaraPlayer *self)
109 GError *error = NULL;
110 ChimaraApp *theapp = chimara_app_get();
112 /* Set parent properties */
114 "title", _("Chimara"),
115 "default-width", 600,
116 "default-height", 800,
119 /* Construct user interface */
120 char *object_ids[] = {
125 GtkBuilder *builder = new_builder_with_objects(object_ids);
127 GtkActionGroup *actiongroup = GTK_ACTION_GROUP(load_object(builder, "actiongroup"));
129 /* Set the default value of the "View/Toolbar" menu item upon creation of a
130 new window to the "show-toolbar-default" setting, but bind the setting
131 one-way only - we don't want toolbars to disappear suddenly */
132 GtkToggleAction *toolbar_action = GTK_TOGGLE_ACTION(load_object(builder, "toolbar"));
133 gtk_toggle_action_set_active(toolbar_action, g_settings_get_boolean(theapp->state_settings, "show-toolbar-default"));
134 g_settings_bind(theapp->state_settings, "show-toolbar-default", toolbar_action, "active", G_SETTINGS_BIND_SET);
136 self->glk = chimara_if_new();
137 g_object_set(self->glk,
138 "ignore-errors", TRUE,
139 /*"interpreter-number", CHIMARA_IF_ZMACHINE_TANDY_COLOR,*/
141 char *default_css = get_data_file_path("style.css");
142 if( !chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), default_css, &error) ) {
143 error_dialog(GTK_WINDOW(self), error, "Couldn't open default CSS file: ");
146 /* DON'T UNCOMMENT THIS your eyes will burn
147 but it is a good test of programmatically altering just one style
148 chimara_glk_set_css_from_string(CHIMARA_GLK(glk),
149 "buffer.normal { font-family: 'Comic Sans MS'; }");*/
151 GtkUIManager *uimanager = new_ui_manager("player.menus");
152 gtk_ui_manager_insert_action_group(uimanager, actiongroup, 0);
153 gtk_ui_manager_insert_action_group(uimanager, chimara_app_get_action_group(theapp), 1);
154 GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/player_menu");
155 self->toolbar = gtk_ui_manager_get_widget(uimanager, "/player_toolbar");
156 gtk_widget_set_no_show_all(self->toolbar, TRUE);
157 if(gtk_toggle_action_get_active(toolbar_action))
158 gtk_widget_show(self->toolbar);
160 gtk_widget_hide(self->toolbar);
162 /* Connect the accelerators */
163 GtkAccelGroup *accels = gtk_ui_manager_get_accel_group(uimanager);
164 gtk_window_add_accel_group(GTK_WINDOW(self), accels);
166 GtkBox *vbox = GTK_BOX(load_object(builder, "player-vbox"));
167 gtk_box_pack_end(vbox, self->glk, TRUE, TRUE, 0);
168 g_object_ref(self->glk); /* add an extra reference to keep it alive while
169 the Glk program shuts down */
170 gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
171 gtk_box_pack_start(vbox, self->toolbar, FALSE, FALSE, 0);
172 gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(vbox));
174 gtk_builder_connect_signals(builder, self);
175 g_signal_connect(self->glk, "notify::program-name", G_CALLBACK(change_window_title), self);
176 g_signal_connect(self->glk, "notify::story-name", G_CALLBACK(change_window_title), self);
178 g_object_unref(builder);
179 g_object_unref(uimanager);
182 /* PUBLIC FUNCTIONS */
185 chimara_player_new(void)
187 return GTK_WIDGET(g_object_new(CHIMARA_TYPE_PLAYER,
188 "type", GTK_WINDOW_TOPLEVEL,
192 /* GLADE CALLBACKS */
195 /* If a game is running in @glk, warn the user that they will quit the currently
196 running game if they open a new one. Returns TRUE if no game was running.
197 Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
198 game if the user wishes to continue. */
200 confirm_open_new_game(ChimaraGlk *glk)
202 g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
204 GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
206 if(chimara_glk_get_running(glk)) {
207 GtkWidget *dialog = gtk_message_dialog_new(window,
208 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
211 _("Are you sure you want to open a new game?"));
212 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
213 _("If you open a new game, you will quit the one you are currently playing."));
214 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
215 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
216 gtk_widget_destroy(dialog);
218 if(response != GTK_RESPONSE_OK)
221 chimara_glk_stop(glk);
222 chimara_glk_wait(glk);
229 on_stop_activate(GtkAction *action, ChimaraPlayer *player)
231 chimara_glk_stop(CHIMARA_GLK(player->glk));
235 on_copy_activate(GtkAction *action, ChimaraPlayer *player)
237 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
238 /* Call "copy clipboard" on any widget that defines it */
239 if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
240 g_signal_emit_by_name(focus, "copy-clipboard");
244 on_paste_activate(GtkAction *action, ChimaraPlayer *player)
246 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
247 /* Call "paste clipboard" on any widget that defines it */
248 if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
249 g_signal_emit_by_name(focus, "paste-clipboard");
253 on_toolbar_toggled(GtkToggleAction *action, ChimaraPlayer *player)
255 if(gtk_toggle_action_get_active(action))
256 gtk_widget_show(player->toolbar);
258 gtk_widget_hide(player->toolbar);
262 on_undo_activate(GtkAction *action, ChimaraPlayer *player)
264 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "undo");
268 on_save_activate(GtkAction *action, ChimaraPlayer *player)
270 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "save");
274 on_restore_activate(GtkAction *action, ChimaraPlayer *player)
276 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restore");
280 on_restart_activate(GtkAction *action, ChimaraPlayer *player)
282 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restart");
286 on_quit_activate(GtkAction *action, ChimaraPlayer *player)
288 chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "quit");