1 /* licensing and copyright information here */
4 #include <glib/gi18n.h>
5 #include "chimara-glk.h"
6 #include "chimara-glk-private.h"
10 #define CHIMARA_GLK_MIN_WIDTH 0
11 #define CHIMARA_GLK_MIN_HEIGHT 0
26 static guint chimara_glk_signals[LAST_SIGNAL] = { 0 };
28 G_DEFINE_TYPE(ChimaraGlk, chimara_glk, GTK_TYPE_CONTAINER);
31 chimara_glk_init(ChimaraGlk *self)
33 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(self), GTK_NO_WINDOW);
35 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(self);
38 priv->interactive = TRUE;
39 priv->protect = FALSE;
41 priv->event_queue = NULL;
42 priv->event_lock = NULL;
43 priv->event_queue_not_empty = NULL;
44 priv->event_queue_not_full = NULL;
45 priv->abort_lock = NULL;
46 priv->abort_signalled = FALSE;
47 priv->interrupt_handler = NULL;
48 priv->root_window = NULL;
49 priv->fileref_list = NULL;
50 priv->current_stream = NULL;
51 priv->stream_list = NULL;
55 chimara_glk_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
57 ChimaraGlk *glk = CHIMARA_GLK(object);
61 case PROP_INTERACTIVE:
62 chimara_glk_set_interactive(glk, g_value_get_boolean(value));
65 chimara_glk_set_protect(glk, g_value_get_boolean(value));
68 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
73 chimara_glk_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
75 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(object);
79 case PROP_INTERACTIVE:
80 g_value_set_boolean(value, priv->interactive);
83 g_value_set_boolean(value, priv->protect);
86 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
91 chimara_glk_finalize(GObject *object)
93 ChimaraGlk *self = CHIMARA_GLK(object);
94 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(self);
96 /* Free the event queue */
97 g_mutex_lock(priv->event_lock);
98 g_queue_foreach(priv->event_queue, (GFunc)g_free, NULL);
99 g_queue_free(priv->event_queue);
100 g_cond_free(priv->event_queue_not_empty);
101 g_cond_free(priv->event_queue_not_full);
102 priv->event_queue = NULL;
103 g_mutex_unlock(priv->event_lock);
104 g_mutex_free(priv->event_lock);
106 /* Free the abort signalling mechanism */
107 g_mutex_lock(priv->abort_lock);
108 /* Make sure no other thread is busy with this */
109 g_mutex_unlock(priv->abort_lock);
110 g_mutex_free(priv->abort_lock);
111 priv->abort_lock = NULL;
113 G_OBJECT_CLASS(chimara_glk_parent_class)->finalize(object);
117 chimara_glk_size_request(GtkWidget *widget, GtkRequisition *requisition)
119 g_return_if_fail(widget);
120 g_return_if_fail(requisition);
121 g_return_if_fail(CHIMARA_IS_GLK(widget));
123 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(widget);
125 /* For now, just pass the size request on to the root Glk window */
126 if(priv->root_window) {
127 GtkWidget *child = ((winid_t)(priv->root_window->data))->frame;
128 if(GTK_WIDGET_VISIBLE(child))
129 gtk_widget_size_request(child, requisition);
131 requisition->width = CHIMARA_GLK_MIN_WIDTH;
132 requisition->height = CHIMARA_GLK_MIN_HEIGHT;
137 chimara_glk_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
139 g_return_if_fail(widget);
140 g_return_if_fail(allocation);
141 g_return_if_fail(CHIMARA_IS_GLK(widget));
143 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(widget);
145 widget->allocation = *allocation;
147 if(priv->root_window) {
148 GtkWidget *child = ((winid_t)(priv->root_window->data))->frame;
149 if(GTK_WIDGET_VISIBLE(child))
150 gtk_widget_size_allocate(child, allocation);
155 chimara_glk_forall(GtkContainer *container, gboolean include_internals,
156 GtkCallback callback, gpointer callback_data)
158 g_return_if_fail(container);
159 g_return_if_fail(CHIMARA_IS_GLK(container));
161 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(container);
163 if(priv->root_window) {
164 GtkWidget *child = ((winid_t)(priv->root_window->data))->frame;
165 (*callback)(child, callback_data);
170 chimara_glk_stopped(ChimaraGlk *self)
172 /* TODO: Add default signal handler implementation here */
176 chimara_glk_started(ChimaraGlk *self)
178 /* TODO: Add default signal handler implementation here */
182 chimara_glk_class_init(ChimaraGlkClass *klass)
184 /* Override methods of parent classes */
185 GObjectClass *object_class = G_OBJECT_CLASS(klass);
186 object_class->set_property = chimara_glk_set_property;
187 object_class->get_property = chimara_glk_get_property;
188 object_class->finalize = chimara_glk_finalize;
190 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
191 widget_class->size_request = chimara_glk_size_request;
192 widget_class->size_allocate = chimara_glk_size_allocate;
194 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass);
195 container_class->forall = chimara_glk_forall;
198 klass->stopped = chimara_glk_stopped;
199 klass->started = chimara_glk_started;
200 chimara_glk_signals[STOPPED] = g_signal_new("stopped",
201 G_OBJECT_CLASS_TYPE(klass), 0,
202 G_STRUCT_OFFSET(ChimaraGlkClass, stopped), NULL, NULL,
203 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
204 chimara_glk_signals[STARTED] = g_signal_new ("started",
205 G_OBJECT_CLASS_TYPE (klass), 0,
206 G_STRUCT_OFFSET(ChimaraGlkClass, started), NULL, NULL,
207 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
211 pspec = g_param_spec_boolean("interactive", _("Interactive"),
212 _("Whether user input is expected in the Glk program"),
214 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_LAX_VALIDATION |
215 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
216 g_object_class_install_property(object_class, PROP_INTERACTIVE, pspec);
217 pspec = g_param_spec_boolean("protect", _("Protected"),
218 _("Whether the Glk program is barred from doing file operations"),
220 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_LAX_VALIDATION |
221 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
222 g_object_class_install_property(object_class, PROP_PROTECT, pspec);
225 g_type_class_add_private(klass, sizeof(ChimaraGlkPrivate));
228 /* PUBLIC FUNCTIONS */
231 chimara_glk_new(void)
233 ChimaraGlk *self = CHIMARA_GLK(g_object_new(CHIMARA_TYPE_GLK, NULL));
234 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(self);
236 priv->event_queue = g_queue_new();
237 priv->event_lock = g_mutex_new();
238 priv->event_queue_not_empty = g_cond_new();
239 priv->event_queue_not_full = g_cond_new();
240 priv->abort_lock = g_mutex_new();
242 return GTK_WIDGET(self);
246 chimara_glk_set_interactive(ChimaraGlk *glk, gboolean interactive)
248 g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
250 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
251 priv->interactive = interactive;
255 chimara_glk_get_interactive(ChimaraGlk *glk)
257 g_return_val_if_fail(glk || CHIMARA_IS_GLK(glk), FALSE);
259 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
260 return priv->interactive;
264 chimara_glk_set_protect(ChimaraGlk *glk, gboolean protect)
266 g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
268 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
269 priv->protect = protect;
273 chimara_glk_get_protect(ChimaraGlk *glk)
275 g_return_val_if_fail(glk || CHIMARA_IS_GLK(glk), FALSE);
277 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
278 return priv->protect;
281 /* glk_enter() is called to create a new thread in which glk_main() runs. */
283 glk_enter(gpointer glk)
285 extern ChimaraGlkPrivate *glk_data;
287 glk_data = CHIMARA_GLK_PRIVATE((ChimaraGlk *)glk);
293 chimara_glk_run(ChimaraGlk *glk, GError **error)
295 g_return_val_if_fail(glk || CHIMARA_IS_GLK(glk), FALSE);
297 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
298 /* Run in a separate thread */
299 priv->thread = g_thread_create(glk_enter, glk, TRUE, error);
300 return !(priv->thread == NULL);
304 chimara_glk_stop(ChimaraGlk *glk)
306 g_return_if_fail(glk || CHIMARA_IS_GLK(glk));
312 chimara_glk_wait(ChimaraGlk *glk)
314 ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk);
315 g_thread_join(priv->thread);