Finished implementing garglk_set_zcolors()
[projects/chimara/chimara.git] / libchimara / garglk.c
1 #include <glib/gi18n.h>
2 #include <libchimara/glk.h>
3 #include "chimara-glk-private.h"
4 #include "stream.h"
5 #include "fileref.h"
6 #include "style.h"
7 #include "garglk.h"
8
9 extern GPrivate *glk_data_key;
10
11 /**
12  * garglk_fileref_get_name:
13  * @fref: A file reference.
14  *
15  * Gets the actual disk filename that @fref refers to, in the platform's
16  * native filename encoding. The string is owned by @fref and must not be
17  * changed or freed.
18  *
19  * Returns: a string in filename encoding.
20  */
21 char * 
22 garglk_fileref_get_name(frefid_t fref)
23 {
24         VALID_FILEREF(fref, return NULL);
25         return fref->filename;
26 }
27
28 /**
29  * garglk_set_program_name:
30  * @name: Name of the Glk program that is running.
31  *
32  * This function is used to let the library know the name of the currently
33  * running Glk program, in case it wants to display this information somewhere
34  * &mdash; for example, in the title bar of a window. A typical use of this
35  * function would be:
36  * |[ garglk_set_program_name("SuperGlkFrotz 0.1"); ]|
37  */
38 void 
39 garglk_set_program_name(const char *name)
40 {
41         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
42         glk_data->program_name = g_strdup(name);
43         g_object_notify(G_OBJECT(glk_data->self), "program-name");
44 }
45
46 /**
47  * garglk_set_program_info:
48  * @info: Information about the Glk program that is running.
49  *
50  * This function is used to provide the library with additional information
51  * about the currently running Glk program, in case it wants to display this
52  * information somewhere &mdash; for example, in an About box. A typical use of
53  * this function would be:
54  * |[ 
55  * garglk_set_program_info("SuperGlkFrotz, version 0.1\n"
56  *     "Original Frotz by Stefan Jokisch\n"
57  *     "Unix port by Jim Dunleavy and David Griffith\n"
58  *     "Glk port by Tor Andersson\n"
59  *     "Animation, networking, and evil AI by Sven Metcalfe");
60  * ]|
61  */
62 void 
63 garglk_set_program_info(const char *info)
64 {
65         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
66         glk_data->program_info = g_strdup(info);
67         g_object_notify(G_OBJECT(glk_data->self), "program-info");
68 }
69
70 /**
71  * garglk_set_story_name:
72  * @name: Name of the story that the Glk program is currently interpreting.
73  *
74  * If the Glk program running is an interactive fiction interpreter, then this
75  * function can be used to let the library know the name of the story currently
76  * loaded in the interpreter, in case it wants to display this information
77  * anywhere &mdash; for example, in the title bar of a window. A typical use of
78  * this function would be:
79  * |[ garglk_set_story_name("Lighan Ses Lion, el Zarf"); ]|
80  */
81 void 
82 garglk_set_story_name(const char *name)
83 {
84         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
85         glk_data->story_name = g_strdup(name);
86         g_object_notify(G_OBJECT(glk_data->self), "story-name");
87 }
88
89 /**
90  * garglk_set_line_terminators:
91  * @win: A window.
92  * @keycodes: An array of <code>keycode_</code> constants.
93  * @numkeycodes: The length of @keycodes.
94  *
95  * Amends the current line input request of @win to include terminating key
96  * codes. Any of the specified key codes will terminate the line input request 
97  * (without printing a newline). 
98  *
99  * Usually, in the event structure returned from a line input request, @val2 is
100  * zero, but if garglk_set_line_terminators() has been called during that input
101  * request, @val2 will be filled in with the key code that terminated the input
102  * request.
103  *
104  * This function only applies to one input request; any subsequent line input
105  * requests on that window are treated normally.
106  *
107  * If @numkeycodes is zero, then any previous call to 
108  * garglk_set_line_terminators() is cancelled and the input request is treated
109  * normally.
110  *
111  * <warning><para>This function is not currently implemented.</para></warning>
112  */
113 void 
114 garglk_set_line_terminators(winid_t win, const glui32 *keycodes, glui32 numkeycodes)
115 {
116         VALID_WINDOW(win, return);
117         g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
118         
119         if(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE) {
120                 ILLEGAL(_("Tried to set the line terminators on a window without a line input request."));
121                 return;
122         }
123
124         WARNING(_("Not implemented"));
125 }
126
127 /**
128  * garglk_unput_string:
129  * @str: a null-terminated string.
130  *
131  * Removes @str from the end of the current stream, if indeed it is there. The
132  * stream's write count is decreased accordingly, and the stream's echo stream
133  * is also modified, if it has one.
134  *
135  * <warning><para>This function is not currently implemented.</para></warning>
136  */
137 void 
138 garglk_unput_string(char *str)
139 {
140         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
141         g_return_if_fail(glk_data->current_stream != NULL);
142
143         WARNING(_("Not implemented"));
144 }
145
146 /**
147  * garglk_unput_string_uni:
148  * @str: a zero-terminated array of Unicode code points.
149  *
150  * Like garglk_unput_string(), but for Unicode streams.
151  *
152  * <warning><para>This function is not currently implemented.</para></warning>
153  */
154 void 
155 garglk_unput_string_uni(glui32 *str)
156 {
157         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
158         g_return_if_fail(glk_data->current_stream != NULL);
159         
160         WARNING(_("Not implemented"));
161 }
162
163 /* TODO document */
164 void
165 garglk_set_zcolors_stream(strid_t str, glui32 fg, glui32 bg)
166 {
167         VALID_STREAM(str, return);
168         g_return_if_fail(str->window != NULL);
169
170         if (fg == zcolor_Transparent && fg == zcolor_Cursor) {
171                 WARNING(_("zcolor_Transparent and zcolor_Cursor not implemented"));
172                 return;
173         }
174
175         winid_t window = str->window;
176
177         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(window->widget) );
178         GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
179         GdkColor fore, back;
180         glkcolor_to_gdkcolor(fg, &fore);
181         glkcolor_to_gdkcolor(bg, &back);
182
183         char *name = g_strdup_printf("zcolor:#%02X%02X%02X/#%02X%02X%02x",
184                 ((fg & 0xff0000) >> 16),
185                 ((fg & 0x00ff00) >> 8),
186                 (fg & 0x0000ff),
187                 ((bg & 0xff0000) >> 16),
188                 ((bg & 0x00ff00) >> 8),
189                 (bg & 0x0000ff)
190         );
191
192         if(fg == zcolor_Default) {
193                 window->zcolor = NULL;
194         } else {
195                 GtkTextTag *tag = gtk_text_tag_table_lookup(tags, name);
196                 if(tag == NULL) {
197                         tag = gtk_text_buffer_create_tag(
198                                 buffer,
199                                 name,
200                                 "foreground-gdk", &fore,
201                                 "foreground-set", TRUE,
202                                 "background-gdk", &back,
203                                 "background-set", TRUE,
204                                 NULL
205                         );
206                 }
207
208                 window->zcolor = tag;
209         }
210 }
211
212 /**
213  * garglk_set_zcolors:
214  * @fg: one of the <code>zcolor_</code> constants.
215  * @bg: one of the <code>zcolor_</code> constants.
216  *
217  * Glk works with styles, not specific colors. This is not quite compatible with
218  * the Z-machine, so this Glk extension implements Z-machine style colors.
219  *
220  * This function changes the foreground color of the current stream to @fg and 
221  * the background color to @bg.
222  *
223  * <warning><para>This function is not currently implemented.</para></warning>
224  */
225 void 
226 garglk_set_zcolors(glui32 fg, glui32 bg)
227 {
228         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
229         g_return_if_fail(glk_data->current_stream != NULL);
230
231         garglk_set_zcolors_stream(glk_data->current_stream, fg, bg);
232 }
233
234 static void
235 apply_reverse_color(GtkTextTag *tag, gpointer data)
236 {
237         const gchar *tag_name;
238         g_object_get(tag, "name", &tag_name, NULL);
239
240         if( g_str_has_prefix(tag_name, "glk-") )
241                 g_object_set_data( G_OBJECT(tag), "reverse_color", data );
242 }
243
244 /* TODO document */
245 void
246 garglk_set_reversevideo_stream(strid_t str, glui32 reverse)
247 {
248         VALID_STREAM(str, return);
249         
250         GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(str->window->widget) );
251         GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
252         gtk_text_tag_table_foreach( tags, apply_reverse_color, GINT_TO_POINTER(reverse) );
253 }
254
255 /**
256  * garglk_set_reversevideo:
257  * @reverse: nonzero for reverse colors, zero for normal colors.
258  *
259  * If @reverse is not zero, uses the foreground color of the current stream as
260  * its background and vice versa. If @reverse is zero, changes the colors of the
261  * current stream back to normal.
262  */
263 void 
264 garglk_set_reversevideo(glui32 reverse)
265 {
266         ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
267         g_return_if_fail(glk_data->current_stream != NULL);
268         g_return_if_fail(glk_data->current_stream->window != NULL);
269
270         garglk_set_reversevideo_stream(glk_data->current_stream, reverse);
271 }