comparison src/cons_supp.c @ 1116:9163eefa0039

console backend
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 08 Dec 2010 23:41:15 +0800
parents
children 1de8bb740c46
comparison
equal deleted inserted replaced
1115:673978a8bc4b 1116:9163eefa0039
1 // -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*-
2 // vim: sw=4:ts=8:sts=4
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <poll.h>
9 #include "mb_graph_engine.h"
10 #include "mb_redraw_man.h"
11 #include "mb_timer.h"
12 #include "mb_cons_supp.h"
13 #include "mb_backend.h"
14 #include "mb_backend_utils.h"
15 #include "config.h"
16
17 #define ERR -1
18 #define OK 0
19
20 #define FALSE 0
21 #define TRUE 1
22
23 #define ASSERT(x)
24
25 #define ONLY_MOUSE_MOVE_RAW 1
26
27 typedef int keysym;
28
29 static mb_timer_factory_t *_timer_factory = &tman_timer_factory;
30
31 /*! \ingroup console_kb
32 * @{
33 */
34 struct _cons_kb_info {
35 int kb_fd;
36
37 int keycode_min, keycode_max;
38 int ksym_per_code;
39 keysym *syms;
40 subject_t *kbevents;
41 observer_factory_t *observer_factory;
42 };
43 typedef struct _cons_kb_info cons_kb_info_t;
44
45 /* @} */
46
47 struct _cons_supp_runtime {
48 MB_DISPLAY display;
49
50 mbe_surface_t *surface;
51 mbe_t *cr;
52 redraw_man_t *rdman;
53 mb_img_ldr_t *img_ldr;
54 int w, h;
55
56 cons_kb_info_t kbinfo;
57 mb_IO_man_t *io_man;
58 mb_timer_man_t *timer_man;
59
60 #ifndef ONLY_MOUSE_MOVE_RAW
61 /* States */
62 shape_t *last;
63 #endif
64
65 /* For handle connection */
66 int io_hdl;
67
68 /*
69 * Following variables are used by handle_single_cons_event()
70 */
71 int last_evt_type; /* Type of last event */
72 int ex1, ey1, ex2, ey2; /* Aggregate expose events */
73 int mx, my; /* Position of last motion event */
74 int mbut_state; /* Button state of last motion event */
75 };
76 typedef struct _cons_supp_runtime cons_supp_runtime_t;
77
78 static void _cons_supp_handle_cons_event(cons_supp_runtime_t *rt);
79
80 /*! \defgroup cons_supp_io IO manager for console.
81 * @{
82 */
83 #define MAX_MONITORS 200
84
85 typedef struct {
86 int type;
87 int fd;
88 mb_IO_cb_t cb;
89 void *data;
90 } monitor_t;
91
92 struct _cons_supp_IO_man {
93 mb_IO_man_t io_man;
94 monitor_t monitors[MAX_MONITORS];
95 int n_monitor;
96 };
97
98 static int _cons_supp_io_man_reg(struct _mb_IO_man *io_man,
99 int fd, MB_IO_TYPE type,
100 mb_IO_cb_t cb, void *data);
101 static void _cons_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl);
102 static mb_IO_man_t *_cons_supp_io_man_new(void);
103 static void _cons_supp_io_man_free(mb_IO_man_t *io_man);
104
105 static mb_IO_factory_t _cons_supp_default_io_factory = {
106 _cons_supp_io_man_new,
107 _cons_supp_io_man_free
108 };
109 static mb_IO_factory_t *_io_factory = &_cons_supp_default_io_factory;
110
111 static struct _cons_supp_IO_man _default_io_man = {
112 {_cons_supp_io_man_reg, _cons_supp_io_man_unreg},
113 {}, /* monitors */
114 0 /* n_monitor */
115 };
116
117 static mb_IO_man_t *
118 _cons_supp_io_man_new(void) {
119 return (mb_IO_man_t *)&_default_io_man;
120 }
121
122 static void
123 _cons_supp_io_man_free(mb_IO_man_t *io_man) {
124 }
125
126 static int
127 _cons_supp_io_man_reg(struct _mb_IO_man *io_man,
128 int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data) {
129 struct _cons_supp_IO_man *cmb_io_man = (struct _cons_supp_IO_man *)io_man;
130 int i;
131
132 for(i = 0; i < cmb_io_man->n_monitor; i++) {
133 if (cmb_io_man->monitors[i].type == MB_IO_DUMMY)
134 break;
135 }
136 if (i == MAX_MONITORS)
137 return ERR;
138
139 cmb_io_man->monitors[i].type = type;
140 cmb_io_man->monitors[i].fd = fd;
141 cmb_io_man->monitors[i].cb = cb;
142 cmb_io_man->monitors[i].data = data;
143 i++;
144 if(i > cmb_io_man->n_monitor)
145 cmb_io_man->n_monitor = i;
146 return i - 1;
147 }
148
149 static void
150 _cons_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl) {
151 struct _cons_supp_IO_man *cmb_io_man = (struct _cons_supp_IO_man *)io_man;
152
153 ASSERT(io_hdl < cmb_io_man->n_monitor);
154 cmb_io_man->monitors[io_hdl].type = MB_IO_DUMMY;
155 }
156
157 /*! \brief Handle connection coming data and timeout of timers.
158 *
159 */
160 static void
161 _cons_supp_event_loop(mb_rt_t *rt) {
162 struct _cons_supp_runtime *cmb_rt = (struct _cons_supp_runtime *)rt;
163 struct _cons_supp_IO_man *io_man =
164 (struct _cons_supp_IO_man *)cmb_rt->io_man;
165 mb_timer_man_t *timer_man = (mb_timer_man_t *)cmb_rt->timer_man;
166 redraw_man_t *rdman;
167 mb_tman_t *tman = tman_timer_man_get_tman(timer_man);
168 mb_timeval_t now, tmo;
169 struct timeval tv;
170 fd_set rfds, wfds;
171 int nfds = 0;
172 int r, r1,i;
173
174 rdman = mb_runtime_rdman(rt);
175 rdman_redraw_all(rdman);
176
177 _cons_supp_handle_cons_event(cmb_rt);
178
179 while(1) {
180 FD_ZERO(&rfds);
181 FD_ZERO(&wfds);
182 for(i = 0; i < io_man->n_monitor; i++) {
183 if(io_man->monitors[i].type == MB_IO_R ||
184 io_man->monitors[i].type == MB_IO_RW) {
185 FD_SET(io_man->monitors[i].fd, &rfds);
186 nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1);
187 }
188 if(io_man->monitors[i].type == MB_IO_W ||
189 io_man->monitors[i].type == MB_IO_RW) {
190 FD_SET(io_man->monitors[i].fd, &wfds);
191 nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1);
192 }
193 }
194
195 get_now(&now);
196 r = mb_tman_next_timeout(tman, &now, &tmo);
197
198 if(r == 0) {
199 tv.tv_sec = MB_TIMEVAL_SEC(&tmo);
200 tv.tv_usec = MB_TIMEVAL_USEC(&tmo);
201 r1 = select(nfds, &rfds, NULL, NULL, &tv);
202 } else
203 r1 = select(nfds, &rfds, NULL, NULL, NULL);
204
205 if(r1 == -1) {
206 perror("select");
207 break;
208 }
209
210 if(r1 == 0) {
211 get_now(&now);
212 mb_tman_handle_timeout(tman, &now);
213 rdman_redraw_changed(rdman);
214 } else {
215 for(i = 0; i < io_man->n_monitor; i++) {
216 if(io_man->monitors[i].type == MB_IO_R ||
217 io_man->monitors[i].type == MB_IO_RW) {
218 if(FD_ISSET(io_man->monitors[i].fd, &rfds))
219 io_man->monitors[i].cb(i, io_man->monitors[i].fd,
220 MB_IO_R,
221 io_man->monitors[i].data);
222 }
223 if(io_man->monitors[i].type == MB_IO_W ||
224 io_man->monitors[i].type == MB_IO_RW) {
225 if(FD_ISSET(io_man->monitors[i].fd, &wfds))
226 io_man->monitors[i].cb(i, io_man->monitors[i].fd,
227 MB_IO_W,
228 io_man->monitors[i].data);
229 }
230 }
231 }
232 }
233 }
234
235 /* @} */
236
237 /*! \defgroup console_kb Console Keyboard Handling
238 *
239 * Accept keyboard events from console and delivery it to
240 * application through observer pattern. There is a subject,
241 * per X-connection, for that.
242 * @{
243 */
244 static int keycode2sym(cons_kb_info_t *kbinfo, unsigned int keycode) {
245 /* TODO: implement keycode to key symbol translation */
246 return 0;
247 }
248
249 static int cons_kb_init(cons_kb_info_t *kbinfo, MB_DISPLAY display,
250 redraw_man_t *rdman) {
251 int n_syms;
252 observer_factory_t *factory;
253 int r;
254
255 /* TODO: set keycode_min, keycode_max and syms */
256 if((int)display != -1)
257 kbinfo->kb_fd = (int)display;
258 else
259 kbinfo->kb_fd = STDIN_FILENO;
260
261 factory = rdman_get_observer_factory(rdman);
262 kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB);
263 if(kbinfo->kbevents == NULL)
264 return ERR;
265 /*! \todo Make sure observer_factory is still need. */
266 kbinfo->observer_factory = factory;
267
268 return OK;
269 }
270
271 static void cons_kb_destroy(cons_kb_info_t *kbinfo) {
272 subject_free(kbinfo->kbevents);
273 }
274 /* @} */
275
276 /*! \brief Notify observers of the shape at specified
277 * position for mouse event.
278 *
279 * Observers of parent shapes may be called if the subject is not
280 * with SUBF_STOP_PROPAGATE flag. The subject of mouse event
281 * for a shape is returned by sh_get_mouse_event_subject().
282 */
283 static void notify_coord_or_shape(redraw_man_t *rdman,
284 mb_obj_t *obj,
285 co_aix x, co_aix y, int etype,
286 unsigned int state,
287 unsigned int button) {
288 mouse_event_t mouse_event;
289 subject_t *subject;
290
291 mouse_event.event.type = etype;
292 mouse_event.x = x;
293 mouse_event.y = y;
294 mouse_event.but_state = state;
295 mouse_event.button = button;
296
297 if(IS_MBO_SHAPES(obj))
298 subject = sh_get_mouse_event_subject((shape_t *)obj);
299 else
300 subject = coord_get_mouse_event((coord_t *)obj);
301
302 subject_notify(subject, (event_t *)&mouse_event);
303 }
304
305 /*! \brief Handle keyboard event and maintain internal states.
306 *
307 * It keeps internal state in rt to improve performance.
308 */
309 static void
310 handle_single_cons_event(cons_supp_runtime_t *rt) {
311 /* TODO: handle keyboard and mouse events. */
312 printf("handle_single_cons_event() will be implemented later\n");
313 }
314
315 /*! \brief Call when no more event in an event iteration.
316 *
317 * No more event means event queue is emplty. This function will
318 * perform some actions according current internal state.
319 */
320 static void
321 no_more_event(cons_supp_runtime_t *rt) {
322 }
323
324 /*! \brief Dispatch all console events in the queue.
325 */
326 static void _cons_supp_handle_cons_event(cons_supp_runtime_t *cmb_rt) {
327 int console_fd = (int)cmb_rt->display;
328 struct pollfd pfd = {console_fd, POLLIN, 0};
329 int r;
330
331 while((r = poll(&pfd, 1, 0)) > 0) {
332 handle_single_cons_event(cmb_rt);
333 }
334 no_more_event(cmb_rt);
335 }
336
337 static void
338 _cons_supp_handle_connection(int hdl, int fd, MB_IO_TYPE type, void *data) {
339 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *)data;
340
341 _cons_supp_handle_cons_event(cmb_rt);
342 }
343
344 /*! \brief Initialize a MadButterfy runtime for Xlib.
345 *
346 * This one is very like _cons_supp_init(), except it accepts a
347 * cons_supp_runtime_t object initialized with a display connected to a X
348 * server and an opened window.
349 *
350 * Following field of the cons_supp_runtime_t object should be initialized.
351 * - w, h
352 * - win
353 * - display
354 * - visual
355 */
356 static int
357 _cons_supp_init_with_win_internal(cons_supp_runtime_t *cmb_rt) {
358 mb_img_ldr_t *img_ldr;
359 int w, h;
360 int console_fd;
361
362 w = cmb_rt->w;
363 h = cmb_rt->h;
364
365 mbe_init();
366
367 cmb_rt->surface =
368 mbe_win_surface_create(cmb_rt->display, NULL,
369 MB_IFMT_ARGB32, w, h);
370
371 cmb_rt->cr = mbe_create(cmb_rt->surface);
372
373 cmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
374 redraw_man_init(cmb_rt->rdman, cmb_rt->cr, NULL);
375 cmb_rt->rdman->w = w;
376 cmb_rt->rdman->h = h;
377 /* FIXME: This is a wired loopback reference. This is inly
378 * required when we need to get the cmb_rt->tman for the
379 * animation. We should relocate the tman to the
380 * redraw_man_t instead.
381 */
382 cmb_rt->rdman->rt = cmb_rt;
383
384 cmb_rt->io_man = mb_io_man_new(_io_factory);
385 cmb_rt->timer_man = mb_timer_man_new(_timer_factory);
386
387 img_ldr = simple_mb_img_ldr_new("");
388 cmb_rt->img_ldr = img_ldr;
389 /*! \todo Remove rdman_set_img_ldr() */
390 rdman_set_img_ldr(cmb_rt->rdman, img_ldr); /* this is ncessary? */
391
392 #ifndef ONLY_MOUSE_MOVE_RAW
393 cmb_rt->last = NULL;
394 #endif
395
396 cons_kb_init(&cmb_rt->kbinfo, cmb_rt->display, cmb_rt->rdman);
397
398 console_fd = (int)cmb_rt->display;
399 cmb_rt->io_hdl = mb_io_man_reg(cmb_rt->io_man, console_fd,
400 MB_IO_R,
401 _cons_supp_handle_connection,
402 cmb_rt);
403
404 return OK;
405 }
406
407 /*! \brief Initialize a MadButterfy runtime for console.
408 *
409 * It setups a runtime environment to run MadButterfly with console.
410 * Users should specify width and height of the opening window.
411 *
412 * \param display_name is actually the path to the console/input device.
413 */
414 static int _cons_supp_init(cons_supp_runtime_t *cmb_rt,
415 const char *display_name,
416 int w, int h) {
417 int r;
418 int console_fd;
419
420 memset(cmb_rt, 0, sizeof(cons_supp_runtime_t));
421
422 if(display_name == NULL || strlen(display_name) == 0)
423 console_fd = STDIN_FILENO;
424 else {
425 console_fd = open(display_name, O_RDONLY);
426 if(console_fd == -1)
427 return ERR;
428 }
429
430 cmb_rt->display = (MB_DISPLAY)console_fd;
431 cmb_rt->w = w;
432 cmb_rt->h = h;
433
434 r = _cons_supp_init_with_win_internal(cmb_rt);
435
436 return r;
437 }
438
439 /*! \brief Initialize a MadButterfly runtime for a window of console.
440 *
441 * This function is equivalent to _cons_supp_init() with fixed width
442 * and height. Since, there is no window for console.
443 *
444 * Runtimes initialized with this function should be destroyed with
445 * cons_supp_destroy_keep_win().
446 *
447 * \param display is actually a file descriptor of console (input device).
448 */
449 static int
450 _cons_supp_init_with_win(cons_supp_runtime_t *cmb_rt,
451 MB_DISPLAY display, MB_WINDOW win) {
452 int r;
453
454 memset(cmb_rt, 0, sizeof(cons_supp_runtime_t));
455
456 cmb_rt->display = display;
457 cmb_rt->w = 800;
458 cmb_rt->h = 600;
459
460 r = _cons_supp_init_with_win_internal(cmb_rt);
461
462 return r;
463 }
464
465 static void cons_supp_destroy_keep_win(cons_supp_runtime_t *cmb_rt);
466
467 static void cons_supp_destroy(cons_supp_runtime_t *cmb_rt) {
468 int console_fd = cmb_rt = (int)cmb_rt->display;
469
470 close(console_fd);
471 cons_supp_destroy_keep_win(cmb_rt);
472 }
473
474 /*! \brief Destroy a MadButterfly runtime initialized with
475 * _cons_supp_init_with_win().
476 *
477 * Destroying a runtime with this function prevent the window and
478 * display associated with the runtime being closed.
479 */
480 static void
481 cons_supp_destroy_keep_win(cons_supp_runtime_t *cmb_rt) {
482 if(cmb_rt->rdman) {
483 redraw_man_destroy(cmb_rt->rdman);
484 free(cmb_rt->rdman);
485 }
486
487 if(cmb_rt->io_hdl)
488 mb_io_man_unreg(cmb_rt->io_man, cmb_rt->io_hdl);
489
490 if(cmb_rt->io_man)
491 mb_io_man_free(_io_factory, cmb_rt->io_man);
492 if(cmb_rt->timer_man)
493 mb_timer_man_free(_timer_factory, cmb_rt->timer_man);
494
495 if(cmb_rt->img_ldr)
496 MB_IMG_LDR_FREE(cmb_rt->img_ldr);
497
498 if(cmb_rt->cr)
499 mbe_destroy(cmb_rt->cr);
500
501 if(cmb_rt->surface)
502 mbe_surface_destroy(cmb_rt->surface);
503
504 cons_kb_destroy(&cmb_rt->kbinfo);
505 }
506
507 static mb_rt_t *
508 _cons_supp_new(const char *display_name, int w, int h) {
509 cons_supp_runtime_t *rt;
510 int r;
511
512 rt = O_ALLOC(cons_supp_runtime_t);
513 if(rt == NULL)
514 return NULL;
515
516 r = _cons_supp_init(rt, display_name, w, h);
517 if(r != OK) {
518 free(rt);
519 return NULL;
520 }
521
522 return (mb_rt_t *)rt;
523 }
524
525 /*! \brief Create a new runtime for existed window for X.
526 *
527 * The object returned by this function must be free with
528 * _cons_supp_free_keep_win() to prevent the window from closed.
529 */
530 static mb_rt_t *
531 _cons_supp_new_with_win(MB_DISPLAY display, MB_WINDOW win) {
532 cons_supp_runtime_t *rt;
533 int r;
534
535 rt = O_ALLOC(cons_supp_runtime_t);
536 if(rt == NULL)
537 return NULL;
538
539 r = _cons_supp_init_with_win(rt, display, win);
540 if(r != OK) {
541 free(rt);
542 return NULL;
543 }
544
545 return (mb_rt_t *)rt;
546 }
547
548 static void
549 _cons_supp_free(mb_rt_t *rt) {
550 cons_supp_destroy((cons_supp_runtime_t *) rt);
551 free(rt);
552 }
553
554 /*! \brief Free runtime created with _cons_supp_new_with_win().
555 */
556 static void
557 _cons_supp_free_keep_win(mb_rt_t *rt) {
558 cons_supp_destroy_keep_win((cons_supp_runtime_t *) rt);
559 free(rt);
560 }
561
562 static subject_t *
563 _cons_supp_kbevents(mb_rt_t *rt) {
564 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
565 return cmb_rt->kbinfo.kbevents;
566 }
567
568 static redraw_man_t *
569 _cons_supp_rdman(mb_rt_t *rt) {
570 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
571 return cmb_rt->rdman;
572 }
573
574 static mb_timer_man_t *
575 _cons_supp_timer_man(mb_rt_t *rt) {
576 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
577 return cmb_rt->timer_man;
578 }
579
580 static observer_factory_t *
581 _cons_supp_observer_factory(mb_rt_t *rt) {
582 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
583 observer_factory_t *factory;
584
585 factory = rdman_get_observer_factory(cmb_rt->rdman);
586 return factory;
587 }
588
589 static mb_img_ldr_t *
590 _cons_supp_img_ldr(mb_rt_t *rt) {
591 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
592 mb_img_ldr_t *img_ldr;
593
594 img_ldr = cmb_rt->img_ldr;
595
596 return img_ldr;
597 }
598
599 static int
600 _cons_supp_add_event(mb_rt_t *rt, int fd, MB_IO_TYPE type,
601 mb_IO_cb_t cb, void *data)
602 {
603 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
604 mb_IO_man_t *io_man = cmb_rt->io_man;
605 int hdl;
606
607 hdl = mb_io_man_reg(io_man, fd, type, cb, data);
608 return hdl;
609 }
610
611 static void
612 _cons_supp_remove_event(mb_rt_t *rt, int hdl)
613 {
614 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt;
615 mb_IO_man_t *io_man = cmb_rt->io_man;
616
617 mb_io_man_unreg(io_man, hdl);
618 }
619
620 static int
621 _cons_supp_flush(mb_rt_t *rt) {
622 cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *)rt;
623
624 mbe_flush(cmb_rt->cr);
625 return OK;
626 }
627
628 static void
629 _cons_supp_reg_IO_factory(mb_IO_factory_t *io_factory) {
630 _io_factory = io_factory;
631 }
632
633 static void
634 _cons_supp_reg_timer_factory(mb_timer_factory_t *timer_factory) {
635 _timer_factory = timer_factory;
636 }
637
638 mb_backend_t mb_dfl_backend = { _cons_supp_new,
639 _cons_supp_new_with_win,
640
641 _cons_supp_free,
642 _cons_supp_free_keep_win,
643 _cons_supp_add_event,
644 _cons_supp_remove_event,
645 _cons_supp_event_loop,
646 _cons_supp_flush,
647
648 _cons_supp_kbevents,
649 _cons_supp_rdman,
650 _cons_supp_timer_man,
651 _cons_supp_observer_factory,
652 _cons_supp_img_ldr,
653
654 _cons_supp_reg_IO_factory,
655 _cons_supp_reg_timer_factory,
656 };