Mercurial > MadButterfly
view src/cons_supp.c @ 1214:e55499f7505a
Fix the issues with multiple framelines
- For multiple framelines, user move mouse from one frameline to
another, the frame is not showed correctly.
- Old implementation always draw normal frame on the frameline
where mouse just leaving.
- It is fixed by detecting leave-notify event and removing hover
mark.
- When user active a frame on a frameline that is not what old active
frame is at, the old active frame is not deactivated.
- It is fixed by calling frameline.deactive() of a frameline when a
frame is activated on another frameline.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Wed, 05 Jan 2011 17:56:14 +0800 |
parents | 17cbb862a8c6 |
children |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #include "mb_graph_engine.h" #include "mb_redraw_man.h" #include "mb_timer.h" #include "mb_cons_supp.h" #include "mb_backend.h" #include "mb_backend_utils.h" #include "config.h" #define ERR -1 #define OK 0 #define FALSE 0 #define TRUE 1 #define ASSERT(x) #define ONLY_MOUSE_MOVE_RAW 1 typedef int keysym; static mb_timer_factory_t *_timer_factory = &tman_timer_factory; /*! \ingroup console_kb * @{ */ struct _cons_kb_info { int kb_fd; int keycode_min, keycode_max; int ksym_per_code; keysym *syms; subject_t *kbevents; observer_factory_t *observer_factory; }; typedef struct _cons_kb_info cons_kb_info_t; /* @} */ struct _cons_supp_runtime { MB_DISPLAY display; MB_WINDOW win; mbe_surface_t *surface; mbe_t *cr; redraw_man_t *rdman; mb_img_ldr_t *img_ldr; int w, h; cons_kb_info_t kbinfo; mb_IO_man_t *io_man; mb_timer_man_t *timer_man; #ifndef ONLY_MOUSE_MOVE_RAW /* States */ shape_t *last; #endif /* For handle connection */ int io_hdl; /* * Following variables are used by handle_single_cons_event() */ int last_evt_type; /* Type of last event */ int ex1, ey1, ex2, ey2; /* Aggregate expose events */ int mx, my; /* Position of last motion event */ int mbut_state; /* Button state of last motion event */ }; typedef struct _cons_supp_runtime cons_supp_runtime_t; static void _cons_supp_handle_cons_event(cons_supp_runtime_t *rt); /*! \defgroup cons_supp_io IO manager for console. * @{ */ #define MAX_MONITORS 200 typedef struct { int type; int fd; mb_IO_cb_t cb; void *data; } monitor_t; struct _cons_supp_IO_man { mb_IO_man_t io_man; monitor_t monitors[MAX_MONITORS]; int n_monitor; }; static int _cons_supp_io_man_reg(struct _mb_IO_man *io_man, int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data); static void _cons_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl); static mb_IO_man_t *_cons_supp_io_man_new(void); static void _cons_supp_io_man_free(mb_IO_man_t *io_man); static mb_IO_factory_t _cons_supp_default_io_factory = { _cons_supp_io_man_new, _cons_supp_io_man_free }; static mb_IO_factory_t *_io_factory = &_cons_supp_default_io_factory; static struct _cons_supp_IO_man _default_io_man = { {_cons_supp_io_man_reg, _cons_supp_io_man_unreg}, {}, /* monitors */ 0 /* n_monitor */ }; static mb_IO_man_t * _cons_supp_io_man_new(void) { return (mb_IO_man_t *)&_default_io_man; } static void _cons_supp_io_man_free(mb_IO_man_t *io_man) { } static int _cons_supp_io_man_reg(struct _mb_IO_man *io_man, int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data) { struct _cons_supp_IO_man *cmb_io_man = (struct _cons_supp_IO_man *)io_man; int i; for(i = 0; i < cmb_io_man->n_monitor; i++) { if (cmb_io_man->monitors[i].type == MB_IO_DUMMY) break; } if (i == MAX_MONITORS) return ERR; cmb_io_man->monitors[i].type = type; cmb_io_man->monitors[i].fd = fd; cmb_io_man->monitors[i].cb = cb; cmb_io_man->monitors[i].data = data; i++; if(i > cmb_io_man->n_monitor) cmb_io_man->n_monitor = i; return i - 1; } static void _cons_supp_io_man_unreg(struct _mb_IO_man *io_man, int io_hdl) { struct _cons_supp_IO_man *cmb_io_man = (struct _cons_supp_IO_man *)io_man; ASSERT(io_hdl < cmb_io_man->n_monitor); cmb_io_man->monitors[io_hdl].type = MB_IO_DUMMY; } /*! \brief Handle connection coming data and timeout of timers. * */ static void _cons_supp_event_loop(mb_rt_t *rt) { struct _cons_supp_runtime *cmb_rt = (struct _cons_supp_runtime *)rt; struct _cons_supp_IO_man *io_man = (struct _cons_supp_IO_man *)cmb_rt->io_man; mb_timer_man_t *timer_man = (mb_timer_man_t *)cmb_rt->timer_man; redraw_man_t *rdman; mb_tman_t *tman = tman_timer_man_get_tman(timer_man); mb_timeval_t now, tmo; struct timeval tv; fd_set rfds, wfds; int nfds = 0; int r, r1,i; rdman = mb_runtime_rdman(rt); rdman_redraw_all(rdman); _cons_supp_handle_cons_event(cmb_rt); while(1) { FD_ZERO(&rfds); FD_ZERO(&wfds); for(i = 0; i < io_man->n_monitor; i++) { if(io_man->monitors[i].type == MB_IO_R || io_man->monitors[i].type == MB_IO_RW) { FD_SET(io_man->monitors[i].fd, &rfds); nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); } if(io_man->monitors[i].type == MB_IO_W || io_man->monitors[i].type == MB_IO_RW) { FD_SET(io_man->monitors[i].fd, &wfds); nfds = MB_MAX(nfds, io_man->monitors[i].fd + 1); } } get_now(&now); r = mb_tman_next_timeout(tman, &now, &tmo); if(r == 0) { tv.tv_sec = MB_TIMEVAL_SEC(&tmo); tv.tv_usec = MB_TIMEVAL_USEC(&tmo); r1 = select(nfds, &rfds, NULL, NULL, &tv); } else r1 = select(nfds, &rfds, NULL, NULL, NULL); if(r1 == -1) { perror("select"); break; } if(r1 == 0) { get_now(&now); mb_tman_handle_timeout(tman, &now); rdman_redraw_changed(rdman); } else { for(i = 0; i < io_man->n_monitor; i++) { if(io_man->monitors[i].type == MB_IO_R || io_man->monitors[i].type == MB_IO_RW) { if(FD_ISSET(io_man->monitors[i].fd, &rfds)) io_man->monitors[i].cb(i, io_man->monitors[i].fd, MB_IO_R, io_man->monitors[i].data); } if(io_man->monitors[i].type == MB_IO_W || io_man->monitors[i].type == MB_IO_RW) { if(FD_ISSET(io_man->monitors[i].fd, &wfds)) io_man->monitors[i].cb(i, io_man->monitors[i].fd, MB_IO_W, io_man->monitors[i].data); } } } } } /* @} */ /*! \defgroup console_kb Console Keyboard Handling * * Accept keyboard events from console and delivery it to * application through observer pattern. There is a subject, * per X-connection, for that. * @{ */ static int keycode2sym(cons_kb_info_t *kbinfo, unsigned int keycode) { /* TODO: implement keycode to key symbol translation */ return 0; } static int cons_kb_init(cons_kb_info_t *kbinfo, MB_DISPLAY display, redraw_man_t *rdman) { int n_syms; observer_factory_t *factory; int r; /* TODO: set keycode_min, keycode_max and syms */ if((int)display != -1) kbinfo->kb_fd = (int)display; else kbinfo->kb_fd = STDIN_FILENO; factory = rdman_get_observer_factory(rdman); kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB); if(kbinfo->kbevents == NULL) return ERR; /*! \todo Make sure observer_factory is still need. */ kbinfo->observer_factory = factory; return OK; } static void cons_kb_destroy(cons_kb_info_t *kbinfo) { subject_free(kbinfo->kbevents); } /* @} */ /*! \brief Notify observers of the shape at specified * position for mouse event. * * Observers of parent shapes may be called if the subject is not * with SUBF_STOP_PROPAGATE flag. The subject of mouse event * for a shape is returned by sh_get_mouse_event_subject(). */ static void notify_coord_or_shape(redraw_man_t *rdman, mb_obj_t *obj, co_aix x, co_aix y, int etype, unsigned int state, unsigned int button) { mouse_event_t mouse_event; subject_t *subject; mouse_event.event.type = etype; mouse_event.x = x; mouse_event.y = y; mouse_event.but_state = state; mouse_event.button = button; if(IS_MBO_SHAPES(obj)) subject = sh_get_mouse_event_subject((shape_t *)obj); else subject = coord_get_mouse_event((coord_t *)obj); subject_notify(subject, (event_t *)&mouse_event); } /*! \brief Handle keyboard event and maintain internal states. * * It keeps internal state in rt to improve performance. */ static void handle_single_cons_event(cons_supp_runtime_t *rt) { /* TODO: handle keyboard and mouse events. */ printf("handle_single_cons_event() will be implemented later\n"); } /*! \brief Call when no more event in an event iteration. * * No more event means event queue is emplty. This function will * perform some actions according current internal state. */ static void no_more_event(cons_supp_runtime_t *rt) { } /*! \brief Dispatch all console events in the queue. */ static void _cons_supp_handle_cons_event(cons_supp_runtime_t *cmb_rt) { int console_fd = (int)cmb_rt->display; struct pollfd pfd = {console_fd, POLLIN, 0}; int r; while((r = poll(&pfd, 1, 0)) > 0) { handle_single_cons_event(cmb_rt); } no_more_event(cmb_rt); } static void _cons_supp_handle_connection(int hdl, int fd, MB_IO_TYPE type, void *data) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *)data; _cons_supp_handle_cons_event(cmb_rt); } /*! \brief Initialize a MadButterfy runtime for Xlib. * * This one is very like _cons_supp_init(), except it accepts a * cons_supp_runtime_t object initialized with a display connected to a X * server and an opened window. * * Following field of the cons_supp_runtime_t object should be initialized. * - w, h * - win * - display * - visual */ static int _cons_supp_init_with_win_internal(cons_supp_runtime_t *cmb_rt) { mb_img_ldr_t *img_ldr; int w, h; int console_fd; w = cmb_rt->w; h = cmb_rt->h; mbe_init(); cmb_rt->surface = mbe_win_surface_create(cmb_rt->display, cmb_rt->win, MB_IFMT_ARGB32, w, h); cmb_rt->cr = mbe_create(cmb_rt->surface); cmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t)); redraw_man_init(cmb_rt->rdman, cmb_rt->cr, NULL); cmb_rt->rdman->w = w; cmb_rt->rdman->h = h; /* FIXME: This is a wired loopback reference. This is inly * required when we need to get the cmb_rt->tman for the * animation. We should relocate the tman to the * redraw_man_t instead. */ cmb_rt->rdman->rt = cmb_rt; cmb_rt->io_man = mb_io_man_new(_io_factory); cmb_rt->timer_man = mb_timer_man_new(_timer_factory); img_ldr = simple_mb_img_ldr_new(""); cmb_rt->img_ldr = img_ldr; /*! \todo Remove rdman_set_img_ldr() */ rdman_set_img_ldr(cmb_rt->rdman, img_ldr); /* this is ncessary? */ #ifndef ONLY_MOUSE_MOVE_RAW cmb_rt->last = NULL; #endif cons_kb_init(&cmb_rt->kbinfo, cmb_rt->display, cmb_rt->rdman); console_fd = (int)cmb_rt->display; cmb_rt->io_hdl = mb_io_man_reg(cmb_rt->io_man, console_fd, MB_IO_R, _cons_supp_handle_connection, cmb_rt); return OK; } /*! \brief Initialize a MadButterfy runtime for console. * * It setups a runtime environment to run MadButterfly with console. * Users should specify width and height of the opening window. * * \param display_name is actually the path to the console/input device. */ static int _cons_supp_init(cons_supp_runtime_t *cmb_rt, const char *display_name, int w, int h) { int r; int console_fd; memset(cmb_rt, 0, sizeof(cons_supp_runtime_t)); if(display_name == NULL || strlen(display_name) == 0) console_fd = STDIN_FILENO; else { console_fd = open(display_name, O_RDONLY); if(console_fd == -1) return ERR; } cmb_rt->display = (MB_DISPLAY)console_fd; cmb_rt->win = NULL; cmb_rt->w = w; cmb_rt->h = h; r = _cons_supp_init_with_win_internal(cmb_rt); return r; } /*! \brief Initialize a MadButterfly runtime for a window of console. * * This function is equivalent to _cons_supp_init() with fixed width * and height. Since, there is no window for console. * * Runtimes initialized with this function should be destroyed with * cons_supp_destroy_keep_win(). * * \param display is actually a file descriptor of console (input device). */ static int _cons_supp_init_with_win(cons_supp_runtime_t *cmb_rt, MB_DISPLAY display, MB_WINDOW win) { int r; memset(cmb_rt, 0, sizeof(cons_supp_runtime_t)); cmb_rt->display = display; cmb_rt->w = 800; cmb_rt->h = 600; r = _cons_supp_init_with_win_internal(cmb_rt); return r; } static void cons_supp_destroy_keep_win(cons_supp_runtime_t *cmb_rt); static void cons_supp_destroy(cons_supp_runtime_t *cmb_rt) { int console_fd = cmb_rt = (int)cmb_rt->display; close(console_fd); cons_supp_destroy_keep_win(cmb_rt); } /*! \brief Destroy a MadButterfly runtime initialized with * _cons_supp_init_with_win(). * * Destroying a runtime with this function prevent the window and * display associated with the runtime being closed. */ static void cons_supp_destroy_keep_win(cons_supp_runtime_t *cmb_rt) { if(cmb_rt->rdman) { redraw_man_destroy(cmb_rt->rdman); free(cmb_rt->rdman); } if(cmb_rt->io_hdl) mb_io_man_unreg(cmb_rt->io_man, cmb_rt->io_hdl); if(cmb_rt->io_man) mb_io_man_free(_io_factory, cmb_rt->io_man); if(cmb_rt->timer_man) mb_timer_man_free(_timer_factory, cmb_rt->timer_man); if(cmb_rt->img_ldr) MB_IMG_LDR_FREE(cmb_rt->img_ldr); if(cmb_rt->cr) mbe_destroy(cmb_rt->cr); if(cmb_rt->surface) mbe_surface_destroy(cmb_rt->surface); cons_kb_destroy(&cmb_rt->kbinfo); } static mb_rt_t * _cons_supp_new(const char *display_name, int w, int h) { cons_supp_runtime_t *rt; int r; rt = O_ALLOC(cons_supp_runtime_t); if(rt == NULL) return NULL; r = _cons_supp_init(rt, display_name, w, h); if(r != OK) { free(rt); return NULL; } return (mb_rt_t *)rt; } /*! \brief Create a new runtime for existed window for console. * * The object returned by this function must be free with * _cons_supp_free_keep_win() to prevent the window from closed. */ static mb_rt_t * _cons_supp_new_with_win(MB_DISPLAY display, MB_WINDOW win) { cons_supp_runtime_t *rt; int r; rt = O_ALLOC(cons_supp_runtime_t); if(rt == NULL) return NULL; r = _cons_supp_init_with_win(rt, display, win); if(r != OK) { free(rt); return NULL; } return (mb_rt_t *)rt; } static void _cons_supp_free(mb_rt_t *rt) { cons_supp_destroy((cons_supp_runtime_t *) rt); free(rt); } /*! \brief Free runtime created with _cons_supp_new_with_win(). */ static void _cons_supp_free_keep_win(mb_rt_t *rt) { cons_supp_destroy_keep_win((cons_supp_runtime_t *) rt); free(rt); } static subject_t * _cons_supp_kbevents(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; return cmb_rt->kbinfo.kbevents; } static redraw_man_t * _cons_supp_rdman(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; return cmb_rt->rdman; } static mb_timer_man_t * _cons_supp_timer_man(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; return cmb_rt->timer_man; } static observer_factory_t * _cons_supp_observer_factory(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; observer_factory_t *factory; factory = rdman_get_observer_factory(cmb_rt->rdman); return factory; } static mb_img_ldr_t * _cons_supp_img_ldr(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; mb_img_ldr_t *img_ldr; img_ldr = cmb_rt->img_ldr; return img_ldr; } static int _cons_supp_add_event(mb_rt_t *rt, int fd, MB_IO_TYPE type, mb_IO_cb_t cb, void *data) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; mb_IO_man_t *io_man = cmb_rt->io_man; int hdl; hdl = mb_io_man_reg(io_man, fd, type, cb, data); return hdl; } static void _cons_supp_remove_event(mb_rt_t *rt, int hdl) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *) rt; mb_IO_man_t *io_man = cmb_rt->io_man; mb_io_man_unreg(io_man, hdl); } static int _cons_supp_flush(mb_rt_t *rt) { cons_supp_runtime_t *cmb_rt = (cons_supp_runtime_t *)rt; mbe_flush(cmb_rt->cr); return OK; } static void _cons_supp_reg_IO_factory(mb_IO_factory_t *io_factory) { _io_factory = io_factory; } static void _cons_supp_reg_timer_factory(mb_timer_factory_t *timer_factory) { _timer_factory = timer_factory; } mb_backend_t mb_dfl_backend = { _cons_supp_new, _cons_supp_new_with_win, _cons_supp_free, _cons_supp_free_keep_win, _cons_supp_add_event, _cons_supp_remove_event, _cons_supp_event_loop, _cons_supp_flush, _cons_supp_kbevents, _cons_supp_rdman, _cons_supp_timer_man, _cons_supp_observer_factory, _cons_supp_img_ldr, _cons_supp_reg_IO_factory, _cons_supp_reg_timer_factory, }; /* * Local Variables: * indent-tabs-mode: t * tab-width: 8 * c-basic-offset: 4 * c-file-style:"stroustrup" * fill-column:79 * End: */ // vim: sw=4:ts=8:sts=4:textwidth=79