Adjust all code to use new kmscon_symbol_t
[platform/upstream/kmscon.git] / src / terminal.c
1 /*
2  * kmscon - Terminal
3  *
4  * Copyright (c) 2011 David Herrmann <dh.herrmann@googlemail.com>
5  * Copyright (c) 2011 University of Tuebingen
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files
9  * (the "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 /*
28  * Terminal
29  * A terminal gets assigned an input stream and several output objects and then
30  * runs a fully functional terminal emulation on it.
31  */
32
33 #include <errno.h>
34 #include <GL/gl.h>
35 #include <GL/glext.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "console.h"
40 #include "eloop.h"
41 #include "log.h"
42 #include "terminal.h"
43 #include "unicode.h"
44 #include "vte.h"
45
46 struct term_out {
47         struct term_out *next;
48         struct kmscon_output *output;
49 };
50
51 struct kmscon_terminal {
52         unsigned long ref;
53         struct kmscon_eloop *eloop;
54
55         struct term_out *outputs;
56         unsigned int max_height;
57
58         struct kmscon_console *console;
59         struct kmscon_idle *redraw;
60         struct kmscon_vte *vte;
61 };
62
63 static void draw_all(struct kmscon_idle *idle, void *data)
64 {
65         struct kmscon_terminal *term = data;
66         struct term_out *iter;
67         struct kmscon_output *output;
68         int ret;
69
70         kmscon_eloop_rm_idle(idle);
71         kmscon_console_draw(term->console);
72
73         iter = term->outputs;
74         for (; iter; iter = iter->next) {
75                 output = iter->output;
76                 if (!kmscon_output_is_awake(output))
77                         continue;
78
79                 ret = kmscon_output_use(output);
80                 if (ret)
81                         continue;
82
83                 glClearColor(0.0, 0.0, 0.0, 1.0);
84                 glClear(GL_COLOR_BUFFER_BIT);
85
86                 kmscon_console_map(term->console);
87                 kmscon_output_swap(output);
88         }
89 }
90
91 static void schedule_redraw(struct kmscon_terminal *term)
92 {
93         int ret;
94
95         if (!term || !term->eloop)
96                 return;
97
98         ret = kmscon_eloop_add_idle(term->eloop, term->redraw, draw_all, term);
99         if (ret && ret != -EALREADY)
100                 log_warning("terminal: cannot schedule redraw\n");
101 }
102
103 static const char help_text[] =
104 "terminal subsystem - KMS based console test\n"
105 "This is some default text to test the drawing operations.\n\n";
106
107 static void print_help(struct kmscon_terminal *term)
108 {
109         unsigned int i, len;
110         kmscon_symbol_t ch;
111
112         len = sizeof(help_text) - 1;
113         for (i = 0; i < len; ++i) {
114                 ch = kmscon_symbol_make(help_text[i]);
115                 kmscon_terminal_input(term, ch);
116         }
117 }
118
119 int kmscon_terminal_new(struct kmscon_terminal **out,
120                                                 struct kmscon_symbol_table *st)
121 {
122         struct kmscon_terminal *term;
123         int ret;
124
125         if (!out)
126                 return -EINVAL;
127
128         log_debug("terminal: new terminal object\n");
129
130         term = malloc(sizeof(*term));
131         if (!term)
132                 return -ENOMEM;
133
134         memset(term, 0, sizeof(*term));
135         term->ref = 1;
136
137         ret = kmscon_idle_new(&term->redraw);
138         if (ret)
139                 goto err_free;
140
141         ret = kmscon_console_new(&term->console, st);
142         if (ret)
143                 goto err_idle;
144
145         ret = kmscon_vte_new(&term->vte);
146         if (ret)
147                 goto err_con;
148         kmscon_vte_bind(term->vte, term->console);
149         print_help(term);
150
151         *out = term;
152         return 0;
153
154 err_con:
155         kmscon_console_unref(term->console);
156 err_idle:
157         kmscon_idle_unref(term->redraw);
158 err_free:
159         free(term);
160         return ret;
161 }
162
163 void kmscon_terminal_ref(struct kmscon_terminal *term)
164 {
165         if (!term)
166                 return;
167
168         term->ref++;
169 }
170
171 void kmscon_terminal_unref(struct kmscon_terminal *term)
172 {
173         if (!term || !term->ref)
174                 return;
175
176         if (--term->ref)
177                 return;
178
179         kmscon_terminal_rm_all_outputs(term);
180         kmscon_vte_unref(term->vte);
181         kmscon_console_unref(term->console);
182         kmscon_terminal_disconnect_eloop(term);
183         free(term);
184         log_debug("terminal: destroying terminal object\n");
185 }
186
187 int kmscon_terminal_connect_eloop(struct kmscon_terminal *term,
188                                                 struct kmscon_eloop *eloop)
189 {
190         if (!term || !eloop)
191                 return -EINVAL;
192
193         if (term->eloop)
194                 return -EALREADY;
195
196         kmscon_eloop_ref(eloop);
197         term->eloop = eloop;
198
199         return 0;
200 }
201
202 void kmscon_terminal_disconnect_eloop(struct kmscon_terminal *term)
203 {
204         if (!term)
205                 return;
206
207         kmscon_eloop_unref(term->eloop);
208         term->eloop = NULL;
209 }
210
211 int kmscon_terminal_add_output(struct kmscon_terminal *term,
212                                                 struct kmscon_output *output)
213 {
214         struct term_out *out;
215         unsigned int height;
216         struct kmscon_mode *mode;
217
218         if (!term || !output)
219                 return -EINVAL;
220
221         mode = kmscon_output_get_current(output);
222         if (!mode) {
223                 log_warning("terminal: invalid output added to terminal\n");
224                 return -EINVAL;
225         }
226
227         out = malloc(sizeof(*out));
228         if (!out)
229                 return -ENOMEM;
230
231         memset(out, 0, sizeof(*out));
232         kmscon_output_ref(output);
233         out->output = output;
234         out->next = term->outputs;
235         term->outputs = out;
236
237         height = kmscon_mode_get_height(mode);
238         if (term->max_height < height) {
239                 term->max_height = height;
240                 kmscon_console_resize(term->console, 0, 0, term->max_height);
241         }
242
243         schedule_redraw(term);
244
245         return 0;
246 }
247
248 void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term)
249 {
250         struct term_out *tmp;
251
252         if (!term)
253                 return;
254
255         while (term->outputs) {
256                 tmp = term->outputs;
257                 term->outputs = tmp->next;
258                 kmscon_output_unref(tmp->output);
259                 free(tmp);
260         }
261 }
262
263 void kmscon_terminal_input(struct kmscon_terminal *term, kmscon_symbol_t ch)
264 {
265         kmscon_vte_input(term->vte, ch);
266         schedule_redraw(term);
267 }