0d8d629d016dfe407cf458c20f4ddec889a27e74
[projects/chimara/chimara.git] / player / player.c
1 #include <glib-object.h>
2 #include <glib/gi18n.h>
3 #include <libchimara/chimara-glk.h>
4 #include <libchimara/chimara-if.h>
5 #include "player.h"
6 #include "error.h"
7 #include "app.h"
8
9 typedef struct _ChimaraPlayerPrivate {
10         int dummy;
11 } ChimaraPlayerPrivate;
12
13 #define CHIMARA_PLAYER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_PLAYER, ChimaraPlayerPrivate))
14 #define CHIMARA_PLAYER_USE_PRIVATE ChimaraPlayerPrivate *priv = CHIMARA_PLAYER_PRIVATE(self)
15
16 G_DEFINE_TYPE(ChimaraPlayer, chimara_player, GTK_TYPE_WINDOW);
17
18 static GObject *
19 load_object(GtkBuilder *builder, const gchar *name)
20 {
21         GObject *retval;
22         if( (retval = gtk_builder_get_object(builder, name)) == NULL) {
23                 error_dialog(NULL, NULL, "Error while getting object '%s'", name);
24                 g_error("Error while getting object '%s'", name);
25         }
26         return retval;
27 }
28
29 static void
30 change_window_title(ChimaraGlk *glk, GParamSpec *pspec, GtkWindow *window)
31 {
32         gchar *program_name, *story_name, *title;
33         g_object_get(glk, "program-name", &program_name, "story-name", &story_name, NULL);
34         if(!program_name) {
35                 gtk_window_set_title(window, "Chimara");
36                 return;
37         }
38         else if(!story_name)
39                 title = g_strdup_printf("%s - Chimara", program_name);
40         else
41                 title = g_strdup_printf("%s - %s - Chimara", program_name, story_name);
42         
43         g_free(program_name);
44         g_free(story_name);
45         gtk_window_set_title(window, title);
46         g_free(title);
47 }
48
49 static void
50 chimara_player_dispose(GObject *object)
51 {
52         ChimaraPlayer *self = CHIMARA_PLAYER(object);
53         if(chimara_glk_get_running(CHIMARA_GLK(self->glk))) {
54                 chimara_glk_stop(CHIMARA_GLK(self->glk));
55                 g_printerr("Stopping...\n");
56                 chimara_glk_wait(CHIMARA_GLK(self->glk));
57                 g_printerr("Done Waiting\n");
58         }
59         
60         /* Chain up */
61         G_OBJECT_CLASS(chimara_player_parent_class)->dispose(object);
62 }
63
64 static void
65 chimara_player_finalize(GObject *object)
66 {
67         g_printerr("Unreffing\n");
68         g_object_unref(CHIMARA_PLAYER(object)->glk);
69         
70         /* Chain up */
71         G_OBJECT_CLASS(chimara_player_parent_class)->finalize(object);
72 }
73
74 static void
75 chimara_player_class_init(ChimaraPlayerClass *klass)
76 {
77         /* Override methods of parent classes */
78         GObjectClass *object_class = G_OBJECT_CLASS(klass);
79         //object_class->set_property = chimara_if_set_property;
80         //object_class->get_property = chimara_if_get_property;
81         object_class->dispose = chimara_player_dispose;
82         object_class->finalize = chimara_player_finalize;
83         
84         /* Signals */
85
86         /* Properties */
87
88         /* Private data */
89         g_type_class_add_private(klass, sizeof(ChimaraPlayerPrivate));
90 }
91
92 static void
93 chimara_player_init(ChimaraPlayer *self)
94 {       
95         GError *error = NULL;
96
97         /* Set parent properties */
98         g_object_set(self,
99                 "title", _("Chimara"),
100                 "default-width", 600,
101                 "default-height", 800,
102                 NULL);
103
104         /* Construct user interface */
105         GtkBuilder *builder = gtk_builder_new();
106         char *object_ids[] = {
107                 "actiongroup",
108                 "player-vbox",
109                 NULL
110         };
111         
112         if( !gtk_builder_add_objects_from_file(builder, PACKAGE_DATA_DIR "/chimara.ui", object_ids, &error) ) {
113 #ifdef DEBUG
114                 g_error_free(error);
115                 error = NULL;
116                 if( !gtk_builder_add_objects_from_file(builder, PACKAGE_SRC_DIR "/chimara.ui", object_ids, &error) ) {
117 #endif /* DEBUG */
118                         error_dialog(NULL, error, "Error while building interface: ");  
119                         return;
120 #ifdef DEBUG
121                 }
122 #endif /* DEBUG */
123         }
124         
125         GtkActionGroup *actiongroup = GTK_ACTION_GROUP(load_object(builder, "actiongroup"));
126         
127         /* Set the default value of the "View/Toolbar" menu item upon creation of a
128          new window to the "show-toolbar-default" setting, but bind the setting
129          one-way only - we don't want toolbars to disappear suddenly */
130         GtkToggleAction *toolbar_action = GTK_TOGGLE_ACTION(load_object(builder, "toolbar"));
131         //gtk_toggle_action_set_active(toolbar_action, g_settings_get_boolean(state_settings, "show-toolbar-default"));
132         //g_settings_bind(state_settings, "show-toolbar-default", toolbar_action, "active", G_SETTINGS_BIND_SET);
133                 
134         GtkUIManager *uimanager = gtk_ui_manager_new();
135         if( !gtk_ui_manager_add_ui_from_file(uimanager, PACKAGE_DATA_DIR "/chimara.menus", &error) ) {
136 #ifdef DEBUG
137                 g_error_free(error);
138                 error = NULL;
139                 if( !gtk_ui_manager_add_ui_from_file(uimanager, PACKAGE_SRC_DIR "/chimara.menus", &error) ) {
140 #endif /* DEBUG */
141                         error_dialog(NULL, error, "Error while building interface: ");
142                         return;
143 #ifdef DEBUG
144                 }
145 #endif /* DEBUG */
146         }
147         
148         self->glk = chimara_if_new();
149         g_object_set(self->glk,
150                                  "ignore-errors", TRUE,
151                                  /*"interpreter-number", CHIMARA_IF_ZMACHINE_TANDY_COLOR,*/
152                                  NULL);
153         if( !chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), PACKAGE_DATA_DIR "/style.css", &error) ) {
154 #ifdef DEBUG
155                 g_error_free(error);
156                 error = NULL;
157                 if( !chimara_glk_set_css_from_file(CHIMARA_GLK(self->glk), PACKAGE_SRC_DIR "/style.css", &error) ) {
158 #endif /* DEBUG */
159                         error_dialog(NULL, error, "Couldn't open CSS file: ");
160                         return;
161 #ifdef DEBUG
162                 }
163 #endif /* DEBUG */
164         }
165         
166         /* DON'T UNCOMMENT THIS your eyes will burn
167          but it is a good test of programmatically altering just one style
168          chimara_glk_set_css_from_string(CHIMARA_GLK(glk),
169          "buffer.normal { font-family: 'Comic Sans MS'; }");*/
170         
171         GtkBox *vbox = GTK_BOX(load_object(builder, "player-vbox"));    
172
173         ChimaraApp *theapp = chimara_app_get();
174
175         gtk_ui_manager_insert_action_group(uimanager, actiongroup, 0);
176         gtk_ui_manager_insert_action_group(uimanager, chimara_app_get_action_group(theapp), 1);
177         GtkWidget *menubar = gtk_ui_manager_get_widget(uimanager, "/player_menu");
178         self->toolbar = gtk_ui_manager_get_widget(uimanager, "/player_toolbar");
179         gtk_widget_set_no_show_all(self->toolbar, TRUE);
180         if(gtk_toggle_action_get_active(toolbar_action))
181                 gtk_widget_show(self->toolbar);
182         else
183                 gtk_widget_hide(self->toolbar);
184         
185         /* Connect the accelerators */
186         GtkAccelGroup *accels = gtk_ui_manager_get_accel_group(uimanager);
187         gtk_window_add_accel_group(GTK_WINDOW(self), accels);
188         
189         gtk_box_pack_end(vbox, self->glk, TRUE, TRUE, 0);
190         g_object_ref(self->glk); /* add an extra reference to keep it alive while
191                                                           the Glk program shuts down */
192         gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
193         gtk_box_pack_start(vbox, self->toolbar, FALSE, FALSE, 0);
194         gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(vbox));
195         
196         gtk_builder_connect_signals(builder, self);
197         g_signal_connect(self->glk, "notify::program-name", G_CALLBACK(change_window_title), self);
198         g_signal_connect(self->glk, "notify::story-name", G_CALLBACK(change_window_title), self);
199
200         g_object_unref( G_OBJECT(builder) );
201         g_object_unref( G_OBJECT(uimanager) );
202 }
203
204 /* PUBLIC FUNCTIONS */
205
206 GtkWidget *
207 chimara_player_new(void)
208 {
209     return GTK_WIDGET(g_object_new(CHIMARA_TYPE_PLAYER,
210                 "type", GTK_WINDOW_TOPLEVEL,
211                 NULL));
212 }
213
214 /* GLADE CALLBACKS */
215
216 #if 0
217 /* If a game is running in @glk, warn the user that they will quit the currently
218 running game if they open a new one. Returns TRUE if no game was running.
219 Returns FALSE if the user cancelled. Returns TRUE and shuts down the running
220 game if the user wishes to continue. */
221 static gboolean
222 confirm_open_new_game(ChimaraGlk *glk)
223 {
224         g_return_val_if_fail(glk && CHIMARA_IS_GLK(glk), FALSE);
225         
226         GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(glk)));
227         
228         if(chimara_glk_get_running(glk)) {
229                 GtkWidget *dialog = gtk_message_dialog_new(window,
230                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
231                     GTK_MESSAGE_WARNING,
232                     GTK_BUTTONS_CANCEL,
233                     _("Are you sure you want to open a new game?"));
234                 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
235                     _("If you open a new game, you will quit the one you are currently playing."));
236                 gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK);
237                 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
238                 gtk_widget_destroy(dialog);
239                 
240                 if(response != GTK_RESPONSE_OK)
241                         return FALSE;
242
243                 chimara_glk_stop(glk);
244                 chimara_glk_wait(glk);
245         }
246         return TRUE;
247 }
248 #endif
249
250 void
251 on_stop_activate(GtkAction *action, ChimaraPlayer *player)
252 {
253         chimara_glk_stop(CHIMARA_GLK(player->glk));
254 }
255
256 void
257 on_copy_activate(GtkAction *action, ChimaraPlayer *player)
258 {
259         GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
260         /* Call "copy clipboard" on any widget that defines it */
261         if(GTK_IS_LABEL(focus) || GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
262                 g_signal_emit_by_name(focus, "copy-clipboard");
263 }
264
265 void
266 on_paste_activate(GtkAction *action, ChimaraPlayer *player)
267 {
268         GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(player));
269         /* Call "paste clipboard" on any widget that defines it */
270         if(GTK_IS_ENTRY(focus) || GTK_IS_TEXT_VIEW(focus))
271                 g_signal_emit_by_name(focus, "paste-clipboard");
272 }
273
274 void
275 on_toolbar_toggled(GtkToggleAction *action, ChimaraPlayer *player)
276 {
277         if(gtk_toggle_action_get_active(action))
278                 gtk_widget_show(player->toolbar);
279         else
280                 gtk_widget_hide(player->toolbar);
281 }
282
283 void
284 on_undo_activate(GtkAction *action, ChimaraPlayer *player)
285 {
286         chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "undo");
287 }
288
289 void 
290 on_save_activate(GtkAction *action, ChimaraPlayer *player)
291 {
292         chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "save");
293 }
294
295 void 
296 on_restore_activate(GtkAction *action, ChimaraPlayer *player)
297 {
298         chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restore");
299 }
300
301 void 
302 on_restart_activate(GtkAction *action, ChimaraPlayer *player)
303 {
304         chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "restart");
305 }
306
307 void 
308 on_quit_activate(GtkAction *action, ChimaraPlayer *player)
309 {
310         chimara_glk_feed_line_input(CHIMARA_GLK(player->glk), "quit");
311 }
312