source: mainline/uspace/srv/hid/console/gcons.c@ c223ee2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c223ee2 was 306061a, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Display mouse pointer even in lower resolution. Still be careful not
to divide by zero if gcons has not been initialized yet.

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
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/** @addtogroup console
30 * @{
31 */
32/** @file
33 */
34
35#include <ipc/fb.h>
36#include <async.h>
37#include <stdio.h>
38#include <sys/mman.h>
39#include <str.h>
40#include <align.h>
41#include <bool.h>
42
43#include "console.h"
44#include "gcons.h"
45
46#define CONSOLE_TOP 66
47#define CONSOLE_MARGIN 6
48
49#define STATUS_START 110
50#define STATUS_TOP 8
51#define STATUS_SPACE 4
52#define STATUS_WIDTH 48
53#define STATUS_HEIGHT 48
54
55#define COLOR_MAIN 0xffffff
56#define COLOR_FOREGROUND 0x202020
57#define COLOR_BACKGROUND 0xffffff
58
59extern char _binary_gfx_helenos_ppm_start[0];
60extern int _binary_gfx_helenos_ppm_size;
61extern char _binary_gfx_nameic_ppm_start[0];
62extern int _binary_gfx_nameic_ppm_size;
63
64extern char _binary_gfx_anim_1_ppm_start[0];
65extern int _binary_gfx_anim_1_ppm_size;
66extern char _binary_gfx_anim_2_ppm_start[0];
67extern int _binary_gfx_anim_2_ppm_size;
68extern char _binary_gfx_anim_3_ppm_start[0];
69extern int _binary_gfx_anim_3_ppm_size;
70extern char _binary_gfx_anim_4_ppm_start[0];
71extern int _binary_gfx_anim_4_ppm_size;
72
73extern char _binary_gfx_cons_selected_ppm_start[0];
74extern int _binary_gfx_cons_selected_ppm_size;
75extern char _binary_gfx_cons_idle_ppm_start[0];
76extern int _binary_gfx_cons_idle_ppm_size;
77extern char _binary_gfx_cons_has_data_ppm_start[0];
78extern int _binary_gfx_cons_has_data_ppm_size;
79extern char _binary_gfx_cons_kernel_ppm_start[0];
80extern int _binary_gfx_cons_kernel_ppm_size;
81
82static bool use_gcons = false;
83static sysarg_t xres;
84static sysarg_t yres;
85
86enum butstate {
87 CONS_DISCONNECTED = 0,
88 CONS_SELECTED,
89 CONS_IDLE,
90 CONS_HAS_DATA,
91 CONS_KERNEL,
92 CONS_DISCONNECTED_SEL,
93 CONS_LAST
94};
95
96static int console_vp;
97static int cstatus_vp[CONSOLE_COUNT];
98static enum butstate console_state[CONSOLE_COUNT];
99
100static int fbphone;
101
102/** List of pixmaps identifying these icons */
103static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1};
104static int animation = -1;
105
106static size_t active_console = 0;
107
108static sysarg_t mouse_x = 0;
109static sysarg_t mouse_y= 0;
110
111static bool btn_pressed = false;
112static sysarg_t btn_x = 0;
113static sysarg_t btn_y = 0;
114
115static void vp_switch(int vp)
116{
117 async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
118}
119
120/** Create view port */
121static int vp_create(sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
122{
123 return async_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
124 (width << 16) | height);
125}
126
127static void clear(void)
128{
129 async_msg_0(fbphone, FB_CLEAR);
130}
131
132static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
133{
134 async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
135}
136
137/** Transparent putchar */
138static void tran_putch(wchar_t ch, sysarg_t col, sysarg_t row)
139{
140 async_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
141}
142
143/** Redraw the button showing state of a given console */
144static void redraw_state(size_t index)
145{
146 vp_switch(cstatus_vp[index]);
147
148 enum butstate state = console_state[index];
149
150 if (ic_pixmaps[state] != -1)
151 async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
152 ic_pixmaps[state]);
153
154 if ((state != CONS_DISCONNECTED) && (state != CONS_KERNEL)
155 && (state != CONS_DISCONNECTED_SEL)) {
156
157 char data[5];
158 snprintf(data, 5, "%zu", index + 1);
159
160 size_t i;
161 for (i = 0; data[i] != 0; i++)
162 tran_putch(data[i], 2 + i, 1);
163 }
164}
165
166/** Notification run on changing console (except kernel console) */
167void gcons_change_console(size_t index)
168{
169 if (!use_gcons)
170 return;
171
172 if (active_console == KERNEL_CONSOLE) {
173 size_t i;
174
175 for (i = 0; i < CONSOLE_COUNT; i++)
176 redraw_state(i);
177
178 if (animation != -1)
179 async_msg_1(fbphone, FB_ANIM_START, animation);
180 } else {
181 if (console_state[active_console] == CONS_DISCONNECTED_SEL)
182 console_state[active_console] = CONS_DISCONNECTED;
183 else
184 console_state[active_console] = CONS_IDLE;
185
186 redraw_state(active_console);
187 }
188
189 active_console = index;
190
191 if ((console_state[index] == CONS_DISCONNECTED)
192 || (console_state[index] == CONS_DISCONNECTED_SEL))
193 console_state[index] = CONS_DISCONNECTED_SEL;
194 else
195 console_state[index] = CONS_SELECTED;
196
197 redraw_state(index);
198 vp_switch(console_vp);
199}
200
201/** Notification function that gets called on new output to virtual console */
202void gcons_notify_char(size_t index)
203{
204 if (!use_gcons)
205 return;
206
207 if ((index == active_console)
208 || (console_state[index] == CONS_HAS_DATA))
209 return;
210
211 console_state[index] = CONS_HAS_DATA;
212
213 if (active_console == KERNEL_CONSOLE)
214 return;
215
216 redraw_state(index);
217 vp_switch(console_vp);
218}
219
220/** Notification function called on service disconnect from console */
221void gcons_notify_disconnect(size_t index)
222{
223 if (!use_gcons)
224 return;
225
226 if (index == active_console)
227 console_state[index] = CONS_DISCONNECTED_SEL;
228 else
229 console_state[index] = CONS_DISCONNECTED;
230
231 if (active_console == KERNEL_CONSOLE)
232 return;
233
234 redraw_state(index);
235 vp_switch(console_vp);
236}
237
238/** Notification function called on console connect */
239void gcons_notify_connect(size_t index)
240{
241 if (!use_gcons)
242 return;
243
244 if (index == active_console)
245 console_state[index] = CONS_SELECTED;
246 else
247 console_state[index] = CONS_IDLE;
248
249 if (active_console == KERNEL_CONSOLE)
250 return;
251
252 redraw_state(index);
253 vp_switch(console_vp);
254}
255
256/** Change to kernel console */
257void gcons_in_kernel(void)
258{
259 if (animation != -1)
260 async_msg_1(fbphone, FB_ANIM_STOP, animation);
261
262 active_console = KERNEL_CONSOLE;
263 vp_switch(0);
264}
265
266/** Return x, where left <= x <= right && |a-x| == min(|a-x|) is smallest */
267static inline ssize_t limit(ssize_t a, ssize_t left, ssize_t right)
268{
269 if (a < left)
270 a = left;
271
272 if (a >= right)
273 a = right - 1;
274
275 return a;
276}
277
278/** Handle mouse move
279 *
280 * @param dx Delta X of mouse move
281 * @param dy Delta Y of mouse move
282 */
283void gcons_mouse_move(ssize_t dx, ssize_t dy)
284{
285 ssize_t nx = (ssize_t) mouse_x + dx;
286 ssize_t ny = (ssize_t) mouse_y + dy;
287
288 /* Until gcons is initalized we don't have the screen resolution */
289 if (xres == 0 || yres == 0)
290 return;
291
292 mouse_x = (size_t) limit(nx, 0, xres);
293 mouse_y = (size_t) limit(ny, 0, yres);
294
295 if (active_console != KERNEL_CONSOLE)
296 async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
297}
298
299static int gcons_find_conbut(sysarg_t x, sysarg_t y)
300{
301 sysarg_t status_start = STATUS_START + (xres - 800) / 2;
302
303 if ((y < STATUS_TOP) || (y >= STATUS_TOP + STATUS_HEIGHT))
304 return -1;
305
306 if (x < status_start)
307 return -1;
308
309 if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT)
310 return -1;
311
312 if (((x - status_start) % (STATUS_WIDTH + STATUS_SPACE)) < STATUS_SPACE)
313 return -1;
314
315 sysarg_t btn = (x - status_start) / (STATUS_WIDTH + STATUS_SPACE);
316
317 if (btn < CONSOLE_COUNT)
318 return btn;
319
320 return -1;
321}
322
323/** Handle mouse click
324 *
325 * @param state New state (true - pressed, false - depressed)
326 *
327 */
328int gcons_mouse_btn(bool state)
329{
330 /* Ignore mouse clicks if no buttons
331 are drawn at all */
332 if (xres < 800)
333 return -1;
334
335 if (state) {
336 int conbut = gcons_find_conbut(mouse_x, mouse_y);
337 if (conbut != -1) {
338 btn_pressed = true;
339 btn_x = mouse_x;
340 btn_y = mouse_y;
341 }
342 return -1;
343 }
344
345 if ((!state) && (!btn_pressed))
346 return -1;
347
348 btn_pressed = false;
349
350 int conbut = gcons_find_conbut(mouse_x, mouse_y);
351 if (conbut == gcons_find_conbut(btn_x, btn_y))
352 return conbut;
353
354 return -1;
355}
356
357/** Draw a PPM pixmap to framebuffer
358 *
359 * @param logo Pointer to PPM data
360 * @param size Size of PPM data
361 * @param x Coordinate of upper left corner
362 * @param y Coordinate of upper left corner
363 *
364 */
365static void draw_pixmap(char *logo, size_t size, sysarg_t x, sysarg_t y)
366{
367 /* Create area */
368 char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
369 MAP_ANONYMOUS, 0, 0);
370 if (shm == MAP_FAILED)
371 return;
372
373 memcpy(shm, logo, size);
374
375 /* Send area */
376 int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
377 if (rc)
378 goto exit;
379
380 rc = async_share_out_start(fbphone, shm, PROTO_READ);
381 if (rc)
382 goto drop;
383
384 /* Draw logo */
385 async_msg_2(fbphone, FB_DRAW_PPM, x, y);
386
387drop:
388 /* Drop area */
389 async_msg_0(fbphone, FB_DROP_SHM);
390
391exit:
392 /* Remove area */
393 munmap(shm, size);
394}
395
396/** Redraws console graphics */
397void gcons_redraw_console(void)
398{
399 if (!use_gcons)
400 return;
401
402 vp_switch(0);
403 set_rgb_color(COLOR_MAIN, COLOR_MAIN);
404 clear();
405 draw_pixmap(_binary_gfx_helenos_ppm_start,
406 (size_t) &_binary_gfx_helenos_ppm_size, xres - 66, 2);
407 draw_pixmap(_binary_gfx_nameic_ppm_start,
408 (size_t) &_binary_gfx_nameic_ppm_size, 5, 17);
409
410 unsigned int i;
411 for (i = 0; i < CONSOLE_COUNT; i++)
412 redraw_state(i);
413
414 vp_switch(console_vp);
415}
416
417/** Creates a pixmap on framebuffer
418 *
419 * @param data PPM data
420 * @param size PPM data size
421 *
422 * @return Pixmap identification
423 *
424 */
425static int make_pixmap(char *data, size_t size)
426{
427 /* Create area */
428 char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
429 MAP_ANONYMOUS, 0, 0);
430 if (shm == MAP_FAILED)
431 return -1;
432
433 memcpy(shm, data, size);
434
435 int pxid = -1;
436
437 /* Send area */
438 int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
439 if (rc)
440 goto exit;
441
442 rc = async_share_out_start(fbphone, shm, PROTO_READ);
443 if (rc)
444 goto drop;
445
446 /* Obtain pixmap */
447 rc = async_req_0_0(fbphone, FB_SHM2PIXMAP);
448 if (rc < 0)
449 goto drop;
450
451 pxid = rc;
452
453drop:
454 /* Drop area */
455 async_msg_0(fbphone, FB_DROP_SHM);
456
457exit:
458 /* Remove area */
459 munmap(shm, size);
460
461 return pxid;
462}
463
464static void make_anim(void)
465{
466 int an = async_req_1_0(fbphone, FB_ANIM_CREATE,
467 cstatus_vp[KERNEL_CONSOLE]);
468 if (an < 0)
469 return;
470
471 int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
472 (size_t) &_binary_gfx_anim_1_ppm_size);
473 async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
474
475 pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
476 (size_t) &_binary_gfx_anim_2_ppm_size);
477 async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
478
479 pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
480 (size_t) &_binary_gfx_anim_3_ppm_size);
481 async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
482
483 pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
484 (size_t) &_binary_gfx_anim_4_ppm_size);
485 async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
486
487 async_msg_1(fbphone, FB_ANIM_START, an);
488
489 animation = an;
490}
491
492/** Initialize nice graphical console environment */
493void gcons_init(int phone)
494{
495 fbphone = phone;
496
497 int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
498 if (rc)
499 return;
500
501 if ((xres < 800) || (yres < 600))
502 return;
503
504 /* Create console viewport */
505
506 /* Align width & height to character size */
507 console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP,
508 ALIGN_DOWN(xres - 2 * CONSOLE_MARGIN, 8),
509 ALIGN_DOWN(yres - (CONSOLE_TOP + CONSOLE_MARGIN), 16));
510
511 if (console_vp < 0)
512 return;
513
514 /* Create status buttons */
515 sysarg_t status_start = STATUS_START + (xres - 800) / 2;
516 size_t i;
517 for (i = 0; i < CONSOLE_COUNT; i++) {
518 cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN +
519 i * (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP,
520 STATUS_WIDTH, STATUS_HEIGHT);
521
522 if (cstatus_vp[i] < 0)
523 return;
524
525 vp_switch(cstatus_vp[i]);
526 set_rgb_color(COLOR_FOREGROUND, COLOR_BACKGROUND);
527 }
528
529 /* Initialize icons */
530 ic_pixmaps[CONS_SELECTED] =
531 make_pixmap(_binary_gfx_cons_selected_ppm_start,
532 (size_t) &_binary_gfx_cons_selected_ppm_size);
533 ic_pixmaps[CONS_IDLE] =
534 make_pixmap(_binary_gfx_cons_idle_ppm_start,
535 (size_t) &_binary_gfx_cons_idle_ppm_size);
536 ic_pixmaps[CONS_HAS_DATA] =
537 make_pixmap(_binary_gfx_cons_has_data_ppm_start,
538 (size_t) &_binary_gfx_cons_has_data_ppm_size);
539 ic_pixmaps[CONS_DISCONNECTED] =
540 make_pixmap(_binary_gfx_cons_idle_ppm_start,
541 (size_t) &_binary_gfx_cons_idle_ppm_size);
542 ic_pixmaps[CONS_KERNEL] =
543 make_pixmap(_binary_gfx_cons_kernel_ppm_start,
544 (size_t) &_binary_gfx_cons_kernel_ppm_size);
545 ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
546
547 make_anim();
548
549 use_gcons = true;
550 console_state[0] = CONS_DISCONNECTED_SEL;
551 console_state[KERNEL_CONSOLE] = CONS_KERNEL;
552
553 vp_switch(console_vp);
554}
555
556/** @}
557 */
Note: See TracBrowser for help on using the repository browser.