source: mainline/uspace/srv/hid/output/output.c@ 192565b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 192565b was 6d5e378, checked in by Martin Decky <martin@…>, 13 years ago

cherrypick GUI implementation (originally by Petr Koupy), with several major changes

  • for character-oriented devices a new output server and output protocol was created based on the original fb server
  • DDF visualizer drivers are pixel-oriented only
  • console and compositor can coexist in the same build
  • terminal widget is self-sufficient, no strange console nesting is needed
  • Property mode set to 100644
File size: 11.7 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/types.h>
30#include <errno.h>
31#include <malloc.h>
32#include <macros.h>
33#include <as.h>
34#include <ipc/output.h>
35#include "port/ega.h"
36#include "port/kchar.h"
37#include "port/niagara.h"
38#include "port/ski.h"
39#include "output.h"
40
41#define MAX_COLS 128
42#define MAX_ROWS 128
43
44typedef struct {
45 link_t link;
46
47 size_t size;
48 unsigned int flags;
49 void *data;
50} frontbuf_t;
51
52static LIST_INITIALIZE(outdevs);
53static LIST_INITIALIZE(frontbufs);
54
55outdev_t *outdev_register(outdev_ops_t *ops, void *data)
56{
57 assert(ops->get_dimensions);
58
59 outdev_t *dev = (outdev_t *) malloc(sizeof(outdev_t));
60 if (dev == NULL)
61 return NULL;
62
63 link_initialize(&dev->link);
64
65 dev->ops = *ops;
66 dev->data = data;
67
68 ops->get_dimensions(dev, &dev->cols, &dev->rows);
69 dev->backbuf = chargrid_create(dev->cols, dev->rows,
70 CHARGRID_FLAG_NONE);
71 if (dev->backbuf == NULL) {
72 free(dev);
73 return NULL;
74 }
75
76 list_append(&dev->link, &outdevs);
77 return dev;
78}
79
80static void srv_yield(ipc_callid_t iid, ipc_call_t *icall)
81{
82 int ret = EOK;
83
84 list_foreach(outdevs, link) {
85 outdev_t *dev = list_get_instance(link, outdev_t, link);
86
87 assert(dev->ops.yield);
88
89 int rc = dev->ops.yield(dev);
90 if (rc != EOK)
91 ret = rc;
92 }
93
94 async_answer_0(iid, ret);
95}
96
97static void srv_claim(ipc_callid_t iid, ipc_call_t *icall)
98{
99 int ret = EOK;
100
101 list_foreach(outdevs, link) {
102 outdev_t *dev = list_get_instance(link, outdev_t, link);
103
104 assert(dev->ops.claim);
105
106 int rc = dev->ops.claim(dev);
107 if (rc != EOK)
108 ret = rc;
109 }
110
111 async_answer_0(iid, ret);
112}
113
114static void srv_get_dimensions(ipc_callid_t iid, ipc_call_t *icall)
115{
116 sysarg_t cols = MAX_COLS;
117 sysarg_t rows = MAX_ROWS;
118
119 list_foreach(outdevs, link) {
120 outdev_t *dev = list_get_instance(link, outdev_t, link);
121
122 cols = min(cols, dev->cols);
123 rows = min(rows, dev->rows);
124 }
125
126 async_answer_2(iid, EOK, cols, rows);
127}
128
129static void srv_get_caps(ipc_callid_t iid, ipc_call_t *icall)
130{
131 console_caps_t caps = 0;
132
133 list_foreach(outdevs, link) {
134 outdev_t *dev = list_get_instance(link, outdev_t, link);
135
136 assert(dev->ops.get_caps);
137
138 caps |= dev->ops.get_caps(dev);
139 }
140
141 async_answer_1(iid, EOK, caps);
142}
143
144static frontbuf_t *resolve_frontbuf(sysarg_t handle, ipc_callid_t iid)
145{
146 frontbuf_t *frontbuf = NULL;
147 list_foreach(frontbufs, link) {
148 frontbuf_t *cur = list_get_instance(link, frontbuf_t, link);
149 if (cur == (frontbuf_t *) handle) {
150 frontbuf = cur;
151 break;
152 }
153 }
154
155 if (frontbuf == NULL) {
156 async_answer_0(iid, ENOENT);
157 return NULL;
158 }
159
160 return frontbuf;
161}
162
163static void srv_frontbuf_create(ipc_callid_t iid, ipc_call_t *icall)
164{
165 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t));
166 if (frontbuf == NULL) {
167 async_answer_0(iid, ENOMEM);
168 return;
169 }
170
171 link_initialize(&frontbuf->link);
172
173 ipc_callid_t callid;
174 if (!async_share_out_receive(&callid, &frontbuf->size,
175 &frontbuf->flags)) {
176 free(frontbuf);
177 async_answer_0(iid, EINVAL);
178 return;
179 }
180
181 int rc = async_share_out_finalize(callid, &frontbuf->data);
182 if ((rc != EOK) || (frontbuf->data == AS_MAP_FAILED)) {
183 free(frontbuf);
184 async_answer_0(iid, ENOMEM);
185 return;
186 }
187
188 list_append(&frontbuf->link, &frontbufs);
189 async_answer_1(iid, EOK, (sysarg_t) frontbuf);
190}
191
192static void srv_frontbuf_destroy(ipc_callid_t iid, ipc_call_t *icall)
193{
194 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
195 if (frontbuf == NULL)
196 return;
197
198 list_remove(&frontbuf->link);
199 as_area_destroy(frontbuf->data);
200 free(frontbuf);
201
202 async_answer_0(iid, EOK);
203}
204
205static void srv_cursor_update(ipc_callid_t iid, ipc_call_t *icall)
206{
207 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
208 if (frontbuf == NULL)
209 return;
210
211 chargrid_t *buf = (chargrid_t *) frontbuf->data;
212 bool visible = chargrid_get_cursor_visibility(buf);
213
214 sysarg_t col;
215 sysarg_t row;
216 chargrid_get_cursor(buf, &col, &row);
217
218 list_foreach(outdevs, link) {
219 outdev_t *dev = list_get_instance(link, outdev_t, link);
220
221 assert(dev->ops.cursor_update);
222
223 sysarg_t prev_col;
224 sysarg_t prev_row;
225 chargrid_get_cursor(dev->backbuf, &prev_col, &prev_row);
226
227 chargrid_set_cursor(dev->backbuf, col, row);
228 chargrid_set_cursor_visibility(dev->backbuf, visible);
229
230 dev->ops.cursor_update(dev, prev_col, prev_row, col, row,
231 visible);
232 }
233
234 async_answer_0(iid, EOK);
235}
236
237static void srv_set_style(ipc_callid_t iid, ipc_call_t *icall)
238{
239 list_foreach(outdevs, link) {
240 outdev_t *dev = list_get_instance(link, outdev_t, link);
241
242 dev->attrs.type = CHAR_ATTR_STYLE;
243 dev->attrs.val.style =
244 (console_style_t) IPC_GET_ARG1(*icall);
245 }
246
247 async_answer_0(iid, EOK);
248}
249
250static void srv_set_color(ipc_callid_t iid, ipc_call_t *icall)
251{
252 list_foreach(outdevs, link) {
253 outdev_t *dev = list_get_instance(link, outdev_t, link);
254
255 dev->attrs.type = CHAR_ATTR_INDEX;
256 dev->attrs.val.index.bgcolor =
257 (console_color_t) IPC_GET_ARG1(*icall);
258 dev->attrs.val.index.fgcolor =
259 (console_color_t) IPC_GET_ARG2(*icall);
260 dev->attrs.val.index.attr =
261 (console_color_attr_t) IPC_GET_ARG3(*icall);
262 }
263
264 async_answer_0(iid, EOK);
265}
266
267static void srv_set_rgb_color(ipc_callid_t iid, ipc_call_t *icall)
268{
269 list_foreach(outdevs, link) {
270 outdev_t *dev = list_get_instance(link, outdev_t, link);
271
272 dev->attrs.type = CHAR_ATTR_RGB;
273 dev->attrs.val.rgb.bgcolor = IPC_GET_ARG1(*icall);
274 dev->attrs.val.rgb.fgcolor = IPC_GET_ARG2(*icall);
275 }
276
277 async_answer_0(iid, EOK);
278}
279
280static bool srv_update_scroll(outdev_t *dev, chargrid_t *buf)
281{
282 assert(dev->ops.char_update);
283
284 sysarg_t top_row = chargrid_get_top_row(buf);
285
286 if (dev->top_row == top_row)
287 return false;
288
289 dev->top_row = top_row;
290
291 for (sysarg_t y = 0; y < dev->rows; y++) {
292 for (sysarg_t x = 0; x < dev->cols; x++) {
293 charfield_t *front_field =
294 chargrid_charfield_at(buf, x, y);
295 charfield_t *back_field =
296 chargrid_charfield_at(dev->backbuf, x, y);
297 bool update = false;
298
299 if (front_field->ch != back_field->ch) {
300 back_field->ch = front_field->ch;
301 update = true;
302 }
303
304 if (!attrs_same(front_field->attrs, back_field->attrs)) {
305 back_field->attrs = front_field->attrs;
306 update = true;
307 }
308
309 front_field->flags &= ~CHAR_FLAG_DIRTY;
310
311 if (update)
312 dev->ops.char_update(dev, x, y);
313 }
314 }
315
316 return true;
317}
318
319static void srv_update(ipc_callid_t iid, ipc_call_t *icall)
320{
321 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
322 if (frontbuf == NULL)
323 return;
324
325 chargrid_t *buf = (chargrid_t *) frontbuf->data;
326
327 list_foreach(outdevs, link) {
328 outdev_t *dev = list_get_instance(link, outdev_t, link);
329
330 assert(dev->ops.char_update);
331
332 if (srv_update_scroll(dev, buf))
333 continue;
334
335 for (sysarg_t y = 0; y < dev->rows; y++) {
336 for (sysarg_t x = 0; x < dev->cols; x++) {
337 charfield_t *front_field =
338 chargrid_charfield_at(buf, x, y);
339 charfield_t *back_field =
340 chargrid_charfield_at(dev->backbuf, x, y);
341 bool update = false;
342
343 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
344 CHAR_FLAG_DIRTY) {
345 if (front_field->ch != back_field->ch) {
346 back_field->ch = front_field->ch;
347 update = true;
348 }
349
350 if (!attrs_same(front_field->attrs,
351 back_field->attrs)) {
352 back_field->attrs = front_field->attrs;
353 update = true;
354 }
355
356 front_field->flags &= ~CHAR_FLAG_DIRTY;
357 }
358
359 if (update)
360 dev->ops.char_update(dev, x, y);
361 }
362 }
363 }
364
365 async_answer_0(iid, EOK);
366}
367
368static void srv_damage(ipc_callid_t iid, ipc_call_t *icall)
369{
370 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
371 if (frontbuf == NULL)
372 return;
373
374 chargrid_t *buf = (chargrid_t *) frontbuf->data;
375
376 list_foreach(outdevs, link) {
377 outdev_t *dev = list_get_instance(link, outdev_t, link);
378
379 assert(dev->ops.char_update);
380
381 if (srv_update_scroll(dev, buf))
382 continue;
383
384 sysarg_t col = IPC_GET_ARG2(*icall);
385 sysarg_t row = IPC_GET_ARG3(*icall);
386
387 sysarg_t cols = IPC_GET_ARG4(*icall);
388 sysarg_t rows = IPC_GET_ARG5(*icall);
389
390 for (sysarg_t y = 0; y < rows; y++) {
391 for (sysarg_t x = 0; x < cols; x++) {
392 charfield_t *front_field =
393 chargrid_charfield_at(buf, col + x, row + y);
394 charfield_t *back_field =
395 chargrid_charfield_at(dev->backbuf, col + x, row + y);
396
397 back_field->ch = front_field->ch;
398 back_field->attrs = front_field->attrs;
399 front_field->flags &= ~CHAR_FLAG_DIRTY;
400 dev->ops.char_update(dev, col + x, row + y);
401 }
402 }
403 }
404
405 async_answer_0(iid, EOK);
406}
407
408static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
409{
410 /* Accept the connection */
411 async_answer_0(iid, EOK);
412
413 while (true) {
414 ipc_call_t call;
415 ipc_callid_t callid = async_get_call(&call);
416
417 if (!IPC_GET_IMETHOD(call)) {
418 async_answer_0(callid, EOK);
419 break;
420 }
421
422 switch (IPC_GET_IMETHOD(call)) {
423 case OUTPUT_YIELD:
424 srv_yield(callid, &call);
425 break;
426 case OUTPUT_CLAIM:
427 srv_claim(callid, &call);
428 break;
429 case OUTPUT_GET_DIMENSIONS:
430 srv_get_dimensions(callid, &call);
431 break;
432 case OUTPUT_GET_CAPS:
433 srv_get_caps(callid, &call);
434 break;
435
436 case OUTPUT_FRONTBUF_CREATE:
437 srv_frontbuf_create(callid, &call);
438 break;
439 case OUTPUT_FRONTBUF_DESTROY:
440 srv_frontbuf_destroy(callid, &call);
441 break;
442
443 case OUTPUT_CURSOR_UPDATE:
444 srv_cursor_update(callid, &call);
445 break;
446 case OUTPUT_SET_STYLE:
447 srv_set_style(callid, &call);
448 break;
449 case OUTPUT_SET_COLOR:
450 srv_set_color(callid, &call);
451 break;
452 case OUTPUT_SET_RGB_COLOR:
453 srv_set_rgb_color(callid, &call);
454 break;
455
456 case OUTPUT_UPDATE:
457 srv_update(callid, &call);
458 break;
459 case OUTPUT_DAMAGE:
460 srv_damage(callid, &call);
461 break;
462
463 default:
464 async_answer_0(callid, EINVAL);
465 }
466 }
467}
468
469static void usage(char *name)
470{
471 printf("Usage: %s <service_name>\n", name);
472}
473
474int main(int argc, char *argv[])
475{
476 if (argc < 2) {
477 usage(argv[0]);
478 return 1;
479 }
480
481 printf("%s: HelenOS output service\n", NAME);
482
483 /* Register server */
484 async_set_client_connection(client_connection);
485 int rc = loc_server_register(NAME);
486 if (rc != EOK) {
487 printf("%s: Unable to register driver\n", NAME);
488 return rc;
489 }
490
491 service_id_t service_id;
492 rc = loc_service_register(argv[1], &service_id);
493 if (rc != EOK) {
494 printf("%s: Unable to register service %s\n", NAME, argv[1]);
495 return rc;
496 }
497
498 ega_init();
499 kchar_init();
500 niagara_init();
501 ski_init();
502
503 printf("%s: Accepting connections\n", NAME);
504 task_retval(0);
505 async_manager();
506
507 /* Never reached */
508 return 0;
509}
Note: See TracBrowser for help on using the repository browser.