# HG changeset patch # User Thinker K.F. Li # Date 1229307183 -28800 # Node ID 29e1b2bffe4ce4180d04230d5ea6a2a48f2e3e89 # Parent 8be36a0d4239cb2fc7a2c986a0b3acdc326ad92f X backend only sent EVT_MOUSE_MOVE_RAW to MadButterfly. - backend does not interpret mouse events (over/out/move), now. - redraw manager, now, interpret mouse events to make it backend independent. - The task (interpret mouse events) should be moved to somewhere in futhure. - backend only sent MotionNotify as EVT_MOUSE_MOVE_RAW. - EVT_MOUSE_MOVE_RAW is interpreted by backend independent code. diff -r 8be36a0d4239 -r 29e1b2bffe4c examples/drag/main.c --- a/examples/drag/main.c Sun Dec 14 12:53:45 2008 +0800 +++ b/examples/drag/main.c Mon Dec 15 10:13:03 2008 +0800 @@ -49,13 +49,6 @@ #define COORD_HIDE(group) coord_hide(group);rdman_coord_changed(X_MB_rdman(ex_rt->rt), group) -void coord_move(coord_t *c, co_aix x, co_aix y) -{ - c->matrix[2] = x; - c->matrix[5] = y; -} - - static void cursor_press_handler(event_t *evt, void *arg) { engine_t *en = (engine_t *) arg; mouse_event_t *mev = (mouse_event_t *) evt; diff -r 8be36a0d4239 -r 29e1b2bffe4c examples/dynamic/main.c --- a/examples/dynamic/main.c Sun Dec 14 12:53:45 2008 +0800 +++ b/examples/dynamic/main.c Mon Dec 15 10:13:03 2008 +0800 @@ -55,12 +55,10 @@ printf("Mouse move\n"); COORD_SHOW(btn->active); - COORD_HIDE(btn->normal); +#if 0 rdman_coord_changed(btn->en->rdman,btn->root); +#endif rdman_redraw_changed(btn->en->rdman); - subject_remove_observer(CMOUSE(btn->normal), btn->obs_move); - btn->obs_press = subject_add_event_observer(CMOUSE(btn->active), EVT_MOUSE_BUT_PRESS, mb_button_pressed,btn); - btn->obs_out = subject_add_event_observer(CMOUSE(btn->active), EVT_MOUSE_OUT, mb_button_out,btn); } static void mb_button_out(event_t *evt, void *arg) { @@ -69,12 +67,10 @@ printf("mouse out\n"); COORD_HIDE(btn->active); - COORD_SHOW(btn->normal); +#if 0 rdman_coord_changed(btn->en->rdman,btn->root); +#endif rdman_redraw_changed(btn->en->rdman); - subject_remove_observer(CMOUSE(btn->active), btn->obs_press); - subject_remove_observer(CMOUSE(btn->active), btn->obs_out); - btn->obs_move = subject_add_event_observer(CMOUSE(btn->normal), EVT_MOUSE_MOVE, mb_button_move,btn); } void mb_button_show_active(event_t *evt, void *arg) @@ -82,33 +78,34 @@ mb_button_t *btn = (mb_button_t *) arg; engine_t *en = btn->en; - COORD_HIDE(btn->click); COORD_SHOW(btn->active); rdman_coord_changed(btn->en->rdman,btn->root); rdman_redraw_changed(btn->en->rdman); - subject_remove_observer(CMOUSE(btn->click), btn->obs_press); - btn->obs_press = subject_add_event_observer(CMOUSE(btn->active), EVT_MOUSE_BUT_PRESS, mb_button_pressed,btn); - btn->obs_out = subject_add_event_observer(CMOUSE(btn->active), EVT_MOUSE_OUT, mb_button_out,btn); } void mb_button_pressed(event_t *evt, void *arg) { mb_button_t *btn = (mb_button_t *) arg; engine_t *en = btn->en; - mb_timeval_t now,to; + mb_timeval_t start, playing, now; + mb_progm_t *progm; + mb_word_t *word; printf("Pressed\n"); COORD_SHOW(btn->click); COORD_HIDE(btn->active); rdman_coord_changed(en->rdman,en->button->root_coord); rdman_redraw_changed(en->rdman); + + progm = mb_progm_new(1, en->rdman); + MB_TIMEVAL_SET(&start, 0, 500000); + MB_TIMEVAL_SET(&playing, 0, 0); + word = mb_progm_next_word(progm, &start, &playing); + mb_visibility_new(VIS_HIDDEN, btn->click, word); + mb_visibility_new(VIS_VISIBLE, btn->active, word); + mb_progm_free_completed(progm); get_now(&now); - MB_TIMEVAL_SET(&to, 0, 500); - MB_TIMEVAL_ADD(&to,&now); - subject_remove_observer(CMOUSE(btn->active), btn->obs_press); - subject_remove_observer(CMOUSE(btn->active), btn->obs_out); - btn->obs_press = subject_add_event_observer(CMOUSE(btn->click), EVT_MOUSE_BUT_RELEASE, mb_button_show_active,btn); - btn->obs_out = NULL; + mb_progm_start(progm, X_MB_tman(en->rt), &now); } mb_button_t *mb_button_new(engine_t *en,mb_sprite_t *sp, char *name) { @@ -144,10 +141,9 @@ btn->click->matrix[2] = 200; btn->click->matrix[5] = 200; btn->en = en; - btn->obs_move = subject_add_event_observer(CMOUSE(btn->normal), EVT_MOUSE_MOVE, mb_button_move,btn); - btn->obs_out = NULL; - btn->obs_press = NULL; - rdman_coord_changed(en->rdman,en->button->root_coord); + btn->obs_move = subject_add_event_observer(CMOUSE(btn->root), EVT_MOUSE_MOVE, mb_button_move,btn); + btn->obs_press = subject_add_event_observer(CMOUSE(btn->root), EVT_MOUSE_BUT_PRESS, mb_button_pressed,btn); + btn->obs_out = subject_add_event_observer(CMOUSE(btn->root), EVT_MOUSE_OUT, mb_button_out,btn); rdman_redraw_changed(en->rdman); return btn; } @@ -188,15 +184,6 @@ } - -void coord_move(coord_t *c, co_aix x, co_aix y) -{ - c->matrix[2] = x; - c->matrix[5] = y; -} - - - static void add_rect_move(event_t *evt, void *arg) { engine_t *en = (engine_t *) arg; diff -r 8be36a0d4239 -r 29e1b2bffe4c include/Makefile.am --- a/include/Makefile.am Sun Dec 14 12:53:45 2008 +0800 +++ b/include/Makefile.am Mon Dec 15 10:13:03 2008 +0800 @@ -8,4 +8,5 @@ mb_redraw_man.h \ mb_shapes.h \ mb_tools.h \ + mb_prop.h \ mb_X_supp.h diff -r 8be36a0d4239 -r 29e1b2bffe4c include/mb_observer.h --- a/include/mb_observer.h Sun Dec 14 12:53:45 2008 +0800 +++ b/include/mb_observer.h Mon Dec 15 10:13:03 2008 +0800 @@ -7,14 +7,25 @@ typedef struct _observer observer_t; typedef struct _subject subject_t; typedef struct _mouse_event mouse_event_t; +typedef struct _monitor_event monitor_event_t; typedef struct _ob_factory ob_factory_t; typedef void (*evt_handler)(event_t *event, void *arg); struct _event { - int type; /*!< event type (a.k.a. EVT_* */ + int type; /*!< event type (a.k.a. EVT_*) */ subject_t *tgt, *cur_tgt; + int flags; }; +/*! \brief Observer mark event with EVTF_STOP_PROPAGATE flag + * to stop propagation. + */ +#define EVTF_STOP_PROPAGATE 0x1 +/*! \brief Observer mark event with EVTF_STOP_NOTIFY flag to stop + * stop notification the event immediately. + */ +#define EVTF_STOP_NOTIFY 0x2 + /*! \brief Observer of observer pattern. * * A target for receiving events. @@ -31,15 +42,21 @@ * Observer is a pattern to decouple caller and callee, * especial for multiple callee. * \see http://en.wikipedia.org/wiki/Observer_pattern + * + * This implementation add a monitor facility to monitor adding/removing + * observers from subjects. Monitor is another subject that monitor events + * will be sent to if it is existed. */ struct _subject { int obj_type; /*!< \brief type of object (a.k.a. OBJT_*). */ void *obj; /*!< \brief the object this subject for. */ int flags; + subject_t *monitor_sub; /*!< \brief Monitor adding/removing + * obervers on this subject. */ ob_factory_t *factory; STAILQ(observer_t) observers; }; -/*! \brief Flag that make a subject to propagate events to parents. */ +/*! \brief Flag that make a subject to stop propagate events to parents. */ #define SUBF_STOP_PROPAGATE 0x1 #define SUBF_BUSY 0x2 /*!< \brief in subject_notify() */ #define SUBF_FREE 0x4 /*!< \brief in postponding subject_free() */ @@ -57,6 +74,12 @@ #define MOUSE_BUT2 0x2 #define MOUSE_BUT3 0x4 +struct _monitor_event { + event_t event; + subject_t *subject; /*!< \brief Subject been monitored. */ + observer_t *observer; /*!< \brief Observer been added or removed. */ +}; + /*! \brief Observer factory. * * It provides functions for allocation of subject and observer objects, @@ -75,18 +98,39 @@ enum {EVT_ANY,EVT_MOUSE_OVER, EVT_MOUSE_OUT, EVT_MOUSE_MOVE, EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE, EVT_KB_PRESS, EVT_KB_RELEASE, EVT_PROGM_COMPLETE, - EVT_RDMAN_REDRAW }; + EVT_RDMAN_REDRAW, + EVT_MONITOR_ADD, EVT_MONITOR_REMOVE, EVT_MONITOR_FREE, + EVT_MOUSE_MOVE_RAW +}; extern subject_t *subject_new(ob_factory_t *factory, void *obj, int obj_type); extern void subject_free(subject_t *subject); extern void subject_notify(subject_t *subject, event_t *evt); -extern observer_t *subject_add_observer(subject_t *subject, - evt_handler hdr, void *arg); extern observer_t *subject_add_event_observer(subject_t *subject, int type, evt_handler hdr, void *arg); +/*! \brief Add an observer for any type of events. */ +#define subject_add_observer(s, h, a) \ + subject_add_event_observer(s, EVT_ANY, h, a) +extern observer_t *subject_add_event_observer_head(subject_t *subject, + int type, + evt_handler hdr, + void *arg); +/*! \brief Add an observer for any type of events at head. */ +#define subject_add_observer_head(s, h, a) \ + subject_add_event_observer_head(s, EVT_ANY, h, a) extern void subject_remove_observer(subject_t *subject, observer_t *observer); +#define subject_get_object(s) ((s)->obj) +/*! \brief Set monitor for the subject. + * + * Monitor of a subject is another subject that would be notified when + * add/remove a observer to/from the subject. It can be used to efficiently + * implement translator to translate events. + */ +#define subject_set_monitor(subject, monitor) \ + do { (subject)->monitor_sub = monitor; } while(0) +#define subject_monitor(subject) ((subject)->monitor_sub) #endif /* __OBSERVER_H_ */ diff -r 8be36a0d4239 -r 29e1b2bffe4c include/mb_prop.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/mb_prop.h Mon Dec 15 10:13:03 2008 +0800 @@ -0,0 +1,53 @@ +#ifndef __MB_PROP_H_ +#define __MB_PROP_H_ + +#include "mb_tools.h" + +/*! \defgroup mb_prop_grp Property + * \brief A way the modules can set up their own properties on objects. + * + * Properties are key-value pairs that are associated with objects. + * MadButterfly associate a property store for each object (coord or shape) + * to keep property values. Every property is identified by a ID; an + * integer. Programmer can use a ID to set/get value to/from a property + * store. The ID should be unique in a property store. + * @{ + */ + +typedef struct _mb_prop_entry mb_prop_entry_t; +typedef struct _mb_prop_store mb_prop_store_t; + +struct _mb_prop_entry { + int id; + void *value; + mb_prop_entry_t *next; +}; + +/*! \brief Property IDs. */ +enum { + PROP_DUMMY, + PROP_MEVT_OB_CNT, + PROP_MEVT_OBSERVER, + PROP_LAST +}; + +struct _mb_prop_store { + elmpool_t *entry_pool; + STAILQ(mb_prop_entry_t) entries; +}; + +#define mb_prop_store_init(prop_store, pent_pool) \ + do { \ + (prop_store)->entry_pool = pent_pool; \ + STAILQ_INIT((prop_store)->entries); \ + } while(0) + +void mb_prop_store_destroy(mb_prop_store_t *prop_store); +void *mb_prop_set(mb_prop_store_t *prop_store, int id, void *value); +void *mb_prop_get(mb_prop_store_t *prop_store, int id); +void mb_prop_del(mb_prop_store_t *prop_store, int id); +int mb_prop_has(mb_prop_store_t *prop_store, int id); + +/* @} */ + +#endif /* __MB_PROP_H_ */ diff -r 8be36a0d4239 -r 29e1b2bffe4c include/mb_redraw_man.h --- a/include/mb_redraw_man.h Sun Dec 14 12:53:45 2008 +0800 +++ b/include/mb_redraw_man.h Mon Dec 15 10:13:03 2008 +0800 @@ -50,6 +50,7 @@ elmpool_t *observer_pool; elmpool_t *subject_pool; elmpool_t *paint_color_pool; + elmpool_t *pent_pool; coords_t dirty_coords; geos_t dirty_geos; @@ -68,6 +69,10 @@ ob_factory_t ob_factory; subject_t *redraw; /*!< \brief Notified after redrawing. */ + subject_t *addrm_monitor; /*!< \brief Monitor adding/removing observers + * to/from mouse event subjects. + */ + mb_obj_t *last_mouse_over; }; extern int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, @@ -79,8 +84,14 @@ extern int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord); /*! \brief Make a shape been managed by a redraw manager. */ -#define rdman_shape_man(rdman, shape) \ - STAILQ_INS_TAIL(rdman->shapes, shape_t, sh_next, shape) +#define rdman_shape_man(rdman, shape) \ + do { \ + mb_prop_store_init(&((mb_obj_t *)(shape))->props, \ + (rdman)->pent_pool); \ + STAILQ_INS_TAIL(rdman->shapes, shape_t, sh_next, shape); \ + if(rdman->last_mouse_over == (mb_obj_t *)(shape)) \ + rdman->last_mouse_over = NULL; \ + } while(0) extern int rdman_shape_free(redraw_man_t *rdman, shape_t *shape); #define rdman_paint_man(rdman, paint) \ @@ -155,6 +166,7 @@ co_aix x, co_aix y, int *in_stroke); #define rdman_get_ob_factory(rdman) (&(rdman)->ob_factory) #define rdman_get_redraw_subject(rdman) ((rdman)->redraw) +#define rdman_get_root(rdman) ((rdman)->root_coord) #endif /* __REDRAW_MAN_H_ */ diff -r 8be36a0d4239 -r 29e1b2bffe4c include/mb_types.h --- a/include/mb_types.h Sun Dec 14 12:53:45 2008 +0800 +++ b/include/mb_types.h Mon Dec 15 10:13:03 2008 +0800 @@ -4,6 +4,7 @@ #include #include "mb_tools.h" #include "mb_observer.h" +#include "mb_prop.h" typedef float co_aix; typedef struct _shape shape_t; @@ -16,21 +17,27 @@ struct _redraw_man; +/* \defgroup mb_obj_grp Object type + * @{ + */ /*! \brief MadButterfly object. * * All objects (coord and shapes) should have mb_obj_t as first member * variable. obj_type is used to identify type of an object. Please, * use MBO_TYPE() to return this value. MBO_TYPE() will type-casting the - * object to mb_obj_t and return obj_type. MBO_TYPE() is a left-side - * value. + * object to mb_obj_t and return obj_type. + * + * mb_obj_t should be initialized with mb_obj_init() and destroied with + * mb_obj_destroy(). */ struct _mb_obj { int obj_type; /*!< \brief Type of a MadButterfly object. */ + mb_prop_store_t props; /*!< Initialized by rdman. */ }; enum { MBO_DUMMY, MBO_COORD, - MBO_SHAPES=0x1000, + MBO_SHAPES=0x1000, /*! \note Don't touch this. */ MBO_PATH, MBO_TEXT, MBO_RECT @@ -40,7 +47,15 @@ /*! \brief Return type of a MadBufferly object. */ #define MBO_TYPE(x) (((mb_obj_t *)(x))->obj_type) #define IS_MBO_SHAPES(obj) (MBO_CLASS(obj) == MBO_SHAPES) -#define IS_MBO_COORD(obj) (MBO_TYPE(obj) == MB_COORD) +#define IS_MBO_COORD(obj) (MBO_TYPE(obj) == MBO_COORD) +#define mb_obj_init(obj, type) \ + do { \ + ((mb_obj_t *)(obj))->obj_type = type; \ + } while(0) +#define mb_obj_destroy(obj) +#define mb_obj_prop_store(obj) (&(obj)->props) + +/* @} */ /*! \brief Base of paint types. * diff -r 8be36a0d4239 -r 29e1b2bffe4c src/Makefile.am --- a/src/Makefile.am Sun Dec 14 12:53:45 2008 +0800 +++ b/src/Makefile.am Mon Dec 15 10:13:03 2008 +0800 @@ -7,7 +7,7 @@ libmbfly_la_SOURCES = animate.c chgcolor.c coord.c event.c geo.c \ observer.c paint.c redraw_man.c rotate.c shape_path.c \ shape_rect.c shape_text.c shift.c subtree_free.c timer.c \ - timertool.c tools.c visibility.c X_supp.c + timertool.c tools.c visibility.c X_supp.c prop.c libmbfly_la_CPPFLAGS = @cairo_CFLAGS@ libmbfly_la_LDFLAGS = @cairo_LIBS@ diff -r 8be36a0d4239 -r 29e1b2bffe4c src/Makefile.pmake --- a/src/Makefile.pmake Sun Dec 14 12:53:45 2008 +0800 +++ b/src/Makefile.pmake Mon Dec 15 10:13:03 2008 +0800 @@ -1,10 +1,11 @@ SRCS = coord.c geo.c shape_path.c shape_text.c shape_rect.c \ redraw_man.c timer.c animate.c paint.c event.c observer.c \ X_supp.c timertool.c tools.c shift.c chgcolor.c \ - visibility.c rotate.c + visibility.c rotate.c prop.c OBJS = ${SRCS:C/(.*)\.c/\1.o/g} TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g} -CFLAGS+= -Wall -I/usr/local/include `pkg-config --cflags cairo` +CFLAGS+= -Wall -I../include -I/usr/local/include \ + `pkg-config --cflags cairo` LDFLAGS = `pkg-config --libs cairo` BINS = libmbfly.a X_main PREFIX?=/usr/local/ diff -r 8be36a0d4239 -r 29e1b2bffe4c src/X_supp.c --- a/src/X_supp.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/X_supp.c Mon Dec 15 10:13:03 2008 +0800 @@ -12,6 +12,8 @@ #define ERR -1 #define OK 0 +#define ONLY_MOUSE_MOVE_RAW 1 + /*! \ingroup xkb * @{ */ @@ -37,8 +39,10 @@ X_kb_info_t kbinfo; +#ifndef ONLY_MOUSE_MOVE_RAW /* States */ shape_t *last; +#endif }; /*! \defgroup xkb X Keyboard Handling @@ -145,11 +149,11 @@ * with SUBF_STOP_PROPAGATE flag. The subject of mouse event * for a shape is returned by sh_get_mouse_event_subject(). */ -static void notify_shapes(redraw_man_t *rdman, - shape_t *shape, - co_aix x, co_aix y, int etype, - unsigned int state, - unsigned int button) { +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; @@ -159,7 +163,10 @@ mouse_event.but_state = state; mouse_event.button = button; - subject = sh_get_mouse_event_subject(shape); + 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); } @@ -180,6 +187,7 @@ int ex1=0, ey1=0, ex2=0, ey2=0; shape_t *shape; + coord_t *root; unsigned int state, button; int in_stroke; @@ -201,8 +209,9 @@ shape = find_shape_at_pos(rdman, x, y, &in_stroke); if(shape) - notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_PRESS, - state, button); + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_BUT_PRESS, + state, button); break; case ButtonRelease: @@ -215,7 +224,8 @@ shape = find_shape_at_pos(rdman, x, y, &in_stroke); if(shape) - notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_RELEASE, + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_BUT_RELEASE, state, button); break; @@ -227,24 +237,35 @@ shape = find_shape_at_pos(rdman, x, y, &in_stroke); +#ifdef ONLY_MOUSE_MOVE_RAW + if(shape != NULL) { + notify_coord_or_shape(rdman, (mb_obj_t *)shape, + x, y, EVT_MOUSE_MOVE_RAW, state, 0); + } else { + root = rdman_get_root(rdman); + notify_coord_or_shape(rdman, (mb_obj_t *)root, + x, y, EVT_MOUSE_MOVE_RAW, state, 0); + } +#else if(shape != NULL) { if(rt->last != shape) { if(rt->last) - notify_shapes(rdman, rt->last, x, y, + notify_coord_or_shape(rdman, rt->last, x, y, EVT_MOUSE_OUT, state, 0); - notify_shapes(rdman, shape, x, y, + notify_coord_or_shape(rdman, shape, x, y, EVT_MOUSE_OVER, state, 0); rt->last = shape; } else - notify_shapes(rdman, shape, x, y, + notify_coord_or_shape(rdman, shape, x, y, EVT_MOUSE_MOVE, state, 0); } else { if(rt->last) { - notify_shapes(rdman, rt->last, x, y, + notify_coord_or_shape(rdman, rt->last, x, y, EVT_MOUSE_OUT, state, 0); rt->last = NULL; } } +#endif break; case KeyPress: @@ -424,7 +445,9 @@ xmb_rt->tman = mb_tman_new(); +#ifndef ONLY_MOUSE_MOVE_RAW xmb_rt->last = NULL; +#endif X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman); diff -r 8be36a0d4239 -r 29e1b2bffe4c src/coord.c --- a/src/coord.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/coord.c Mon Dec 15 10:13:03 2008 +0800 @@ -90,7 +90,7 @@ co->parent = parent; STAILQ_INS_TAIL(parent->children, coord_t, sibling, co); } - MBO_TYPE(co) = MBO_COORD; + mb_obj_init(co, MBO_COORD); co->matrix[0] = 1; co->matrix[4] = 1; co->aggr_matrix[0] = 1; diff -r 8be36a0d4239 -r 29e1b2bffe4c src/observer.c --- a/src/observer.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/observer.c Mon Dec 15 10:13:03 2008 +0800 @@ -17,6 +17,7 @@ subject->obj = obj; subject->obj_type = obj_type; subject->flags = 0; + subject->monitor_sub = NULL; STAILQ_INIT(subject->observers); subject->factory = factory; @@ -30,6 +31,7 @@ void subject_free(subject_t *subject) { ob_factory_t *factory = subject->factory; observer_t *observer; + monitor_event_t mevt; ASSERT(!(subject->flags & SUBF_FREE)); if(subject->flags & SUBF_BUSY) { @@ -39,7 +41,14 @@ subject->flags |= SUBF_FREE; return; } - + + if(subject->monitor_sub) { + mevt.event.type = EVT_MONITOR_FREE; + mevt.subject = subject; + mevt.observer = NULL; + subject_notify(subject->monitor_sub, (event_t *)&mevt); + } + while((observer = STAILQ_HEAD(subject->observers))) { STAILQ_REMOVE(subject->observers, observer_t, next, observer); factory->observer_free(factory, observer); @@ -52,62 +61,60 @@ ob_factory_t *factory = subject->factory; observer_t *observer; subject_t *old_subject; + int stop_propagate = 0; + int old_busy; evt->tgt = subject; + evt->flags = 0; while(subject) { /*! * \note What is happend when the subject is freed by observer? * Postponding the request of free until notification * been finished. (\ref SUBF_BUSY / \ref SUBF_FREE) */ + old_busy = subject->flags & SUBF_BUSY; subject->flags |= SUBF_BUSY; - evt->cur_tgt = subject->obj; + evt->cur_tgt = subject; for(observer = STAILQ_HEAD(subject->observers); observer != NULL; observer = STAILQ_NEXT(observer_t, next, observer)) { - if (observer->type == EVT_ANY || observer->type == evt->type) - observer->hdr(evt, observer->arg); + if (observer->type == EVT_ANY || observer->type == evt->type) { + observer->hdr(evt, observer->arg); + + if(evt->flags & EVTF_STOP_NOTIFY) { + stop_propagate = 1; + break; + } + if(evt->flags & EVTF_STOP_PROPAGATE) + stop_propagate = 1; + } } - subject->flags &= ~SUBF_BUSY; + if(!old_busy) + subject->flags &= ~SUBF_BUSY; old_subject = subject; subject = factory->get_parent_subject(factory, subject); + if(old_subject->flags & SUBF_STOP_PROPAGATE) + stop_propagate = 1; + if(old_subject->flags & SUBF_FREE) subject_free(old_subject); - if(old_subject->flags & SUBF_STOP_PROPAGATE) + if(stop_propagate) break; } } -/*! \brief Add an observer for any type of events. - */ -observer_t *subject_add_observer(subject_t *subject, - evt_handler hdr, void *arg) { - ob_factory_t *factory = subject->factory; - observer_t *observer; - - observer = factory->observer_alloc(factory); - if(observer == NULL) - return NULL; - observer->hdr = hdr; - observer->arg = arg; - observer->type = EVT_ANY; - - STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); - - return observer; -} - /*! \brief Add an observer for specified type of events. */ observer_t *subject_add_event_observer(subject_t *subject, int type, evt_handler hdr, void *arg) { ob_factory_t *factory = subject->factory; observer_t *observer; + monitor_event_t mevt; observer = factory->observer_alloc(factory); if(observer == NULL) @@ -118,14 +125,57 @@ STAILQ_INS_TAIL(subject->observers, observer_t, next, observer); + if(subject->monitor_sub) { + mevt.event.type = EVT_MONITOR_ADD; + mevt.subject = subject; + mevt.observer = observer; + subject_notify(subject->monitor_sub, (event_t *)&mevt); + } + + return observer; +} + +/*! \brief Add an observer for specified type of events at head. + */ +observer_t *subject_add_event_observer_head(subject_t *subject, int type, + evt_handler hdr, void *arg) { + ob_factory_t *factory = subject->factory; + observer_t *observer; + monitor_event_t mevt; + + observer = factory->observer_alloc(factory); + if(observer == NULL) + return NULL; + observer->hdr = hdr; + observer->arg = arg; + observer->type = type; + + STAILQ_INS(subject->observers, observer_t, next, observer); + + if(subject->monitor_sub) { + mevt.event.type = EVT_MONITOR_ADD; + mevt.subject = subject; + mevt.observer = observer; + subject_notify(subject->monitor_sub, (event_t *)&mevt); + } + return observer; } void subject_remove_observer(subject_t *subject, observer_t *observer) { ob_factory_t *factory = subject->factory; + monitor_event_t mevt; STAILQ_REMOVE(subject->observers, observer_t, next, observer); + + if(subject->monitor_sub) { + mevt.event.type = EVT_MONITOR_REMOVE; + mevt.subject = subject; + mevt.observer = observer; + subject_notify(subject->monitor_sub, (event_t *)&mevt); + } + factory->observer_free(factory, observer); } @@ -176,7 +226,7 @@ (*cnt)++; } -void test_observer(void) { +static void test_observer(void) { subject_t *subject; observer_t *observer[2]; event_t evt; @@ -198,11 +248,41 @@ subject_free(subject); } +static void monitor_handler(event_t *evt, void *arg) { + int *cnt = (int *)arg; + + (*cnt)++; +} + +static void test_monitor(void) { + subject_t *subject, *monitor; + observer_t *observer[2]; + int cnt = 0; + + subject = subject_new(&test_factory, NULL, 0); + monitor = subject_new(&test_factory, NULL, 0); + subject_set_monitor(subject, monitor); + + observer[0] = subject_add_observer(monitor, monitor_handler, &cnt); + observer[1] = subject_add_observer(subject, NULL, NULL); + CU_ASSERT(cnt == 1); + + subject_remove_observer(subject, observer[1]); + CU_ASSERT(cnt == 2); + + subject_free(subject); + CU_ASSERT(cnt == 3); + + subject_remove_observer(monitor, observer[0]); + subject_free(monitor); +} + CU_pSuite get_observer_suite(void) { CU_pSuite suite; suite = CU_add_suite("Suite_observer", NULL, NULL); CU_ADD_TEST(suite, test_observer); + CU_ADD_TEST(suite, test_monitor); return suite; } diff -r 8be36a0d4239 -r 29e1b2bffe4c src/prop.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/prop.c Mon Dec 15 10:13:03 2008 +0800 @@ -0,0 +1,84 @@ +#include "mb_prop.h" + +#define ASSERT(x) + + +static +mb_prop_entry_t *_mb_prop_find(mb_prop_store_t *prop_store, int id) { + mb_prop_entry_t *entry; + + for(entry = STAILQ_HEAD(prop_store->entries); + entry != NULL; + entry = STAILQ_NEXT(mb_prop_entry_t, next, entry)) { + if(entry->id == id) + return entry; + } + + return NULL; +} + +void mb_prop_store_destroy(mb_prop_store_t *prop_store) { + mb_prop_entry_t *entry, *last; + + last = STAILQ_HEAD(prop_store->entries); + if(last == NULL) + return; + + for(entry = STAILQ_NEXT(mb_prop_entry_t, next, entry); + entry != NULL; + entry = STAILQ_NEXT(mb_prop_entry_t, next, entry)) { + STAILQ_REMOVE(prop_store->entries, mb_prop_entry_t, next, last); + elmpool_elm_free(prop_store->entry_pool, last); + last = entry; + } + STAILQ_REMOVE(prop_store->entries, mb_prop_entry_t, next, last); + elmpool_elm_free(prop_store->entry_pool, last); +} + +void *mb_prop_set(mb_prop_store_t *prop_store, int id, void *value) { + mb_prop_entry_t *entry; + void *old; + + entry = _mb_prop_find(prop_store, id); + if(entry) { + old = entry->value; + entry->value = value; + return old; + } + + entry = elmpool_elm_alloc(prop_store->entry_pool); + ASSERT(entry != NULL); + entry->id = id; + entry->value = value; + STAILQ_INS(prop_store->entries, mb_prop_entry_t, next, entry); + + return NULL; +} + +void *mb_prop_get(mb_prop_store_t *prop_store, int id) { + mb_prop_entry_t *entry; + + entry = _mb_prop_find(prop_store, id); + if(entry) + return entry->value; + + return NULL; +} + +void mb_prop_del(mb_prop_store_t *prop_store, int id) { + mb_prop_entry_t *entry; + + entry = _mb_prop_find(prop_store, id); + if(entry) + STAILQ_REMOVE(prop_store->entries, mb_prop_entry_t, next, entry); +} + +int mb_prop_has(mb_prop_store_t *prop_store, int id) { + mb_prop_entry_t *entry; + + entry = _mb_prop_find(prop_store, id); + if(entry) + return 1; + + return 0; +} diff -r 8be36a0d4239 -r 29e1b2bffe4c src/redraw_man.c --- a/src/redraw_man.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/redraw_man.c Mon Dec 15 10:13:03 2008 +0800 @@ -7,7 +7,11 @@ #include "mb_tools.h" #include "mb_redraw_man.h" #include "mb_observer.h" +#include "mb_prop.h" +#ifndef ASSERT +#define ASSERT(x) +#endif /* NOTE: bounding box should also consider width of stroke. */ @@ -235,55 +239,116 @@ coord->num_members--; } +static void mouse_event_root_dummy(event_t *evt, void *arg) { +} + +static void mouse_event_interpreter(event_t *evt, void *arg) { + mouse_event_t *mevt = (mouse_event_t *)evt; + redraw_man_t *rdman = (redraw_man_t *)arg; + mb_obj_t *obj; + mouse_event_t new_evt; + coord_t *coord; + shape_t *shape; + + ASSERT(evt->type == EVT_MOUSE_MOVE_RAW); + + obj = (mb_obj_t *)subject_get_object(evt->cur_tgt); + if(rdman->last_mouse_over == obj) { + evt->type = EVT_MOUSE_MOVE; + return; + } + + new_evt.x = mevt->x; + new_evt.y = mevt->y; + new_evt.but_state = mevt->but_state; + new_evt.button = mevt->button; + + if(rdman->last_mouse_over != NULL) { + new_evt.event.type = EVT_MOUSE_OUT; + if(IS_MBO_COORD(rdman->last_mouse_over)) { + coord = (coord_t *)rdman->last_mouse_over; + subject_notify(coord->mouse_event, (event_t *)&new_evt); + } else if(IS_MBO_SHAPES(rdman->last_mouse_over)) { + shape = (shape_t *)rdman->last_mouse_over; + ASSERT(shape->geo != NULL); + subject_notify(shape->geo->mouse_event, (event_t *)&new_evt); + } + } + + new_evt.event.type = EVT_MOUSE_OVER; + subject_notify(evt->cur_tgt, (event_t *)&new_evt); + rdman->last_mouse_over = obj; + + evt->flags |= EVTF_STOP_NOTIFY; +} + +static void addrm_monitor_hdlr(event_t *evt, void *arg) { + monitor_event_t *mevt; + redraw_man_t *rdman; + mb_obj_t *obj; + mb_prop_store_t *props; + observer_t *observer; + int cnt = 0; + + mevt = (monitor_event_t *)evt; + rdman = (redraw_man_t *)evt->tgt; + obj = (mb_obj_t *)subject_get_object(mevt->subject); + props = mb_obj_prop_store(obj); + + switch(evt->type) { + case EVT_MONITOR_ADD: + if(!mb_prop_has(props, PROP_MEVT_OB_CNT)) + cnt = 0; + else + cnt = (int)mb_prop_get(props, PROP_MEVT_OB_CNT); + + cnt++; + mb_prop_set(props, PROP_MEVT_OB_CNT, (void *)cnt); + if(cnt == 1) { + observer = + subject_add_event_observer_head(mevt->subject, + EVT_MOUSE_MOVE_RAW, + mouse_event_interpreter, + rdman); + ASSERT(observer != NULL); + mb_prop_set(props, PROP_MEVT_OBSERVER, observer); + } + break; + + case EVT_MONITOR_REMOVE: + cnt = (int)mb_prop_get(props, PROP_MEVT_OB_CNT); + cnt--; + mb_prop_set(props, PROP_MEVT_OB_CNT, (void *)cnt); + if(cnt == 1) { + observer = (observer_t *)mb_prop_get(props, PROP_MEVT_OBSERVER); + subject_remove_observer(mevt->subject, observer); + mb_prop_del(props, PROP_MEVT_OBSERVER); + } + break; + + case EVT_MONITOR_FREE: + break; + } +} + int redraw_man_init(redraw_man_t *rdman, cairo_t *cr, cairo_t *backend) { extern void redraw_man_destroy(redraw_man_t *rdman); extern int _paint_color_size; + observer_t *addrm_ob; memset(rdman, 0, sizeof(redraw_man_t)); rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); - if(rdman->geo_pool == NULL) - return ERR; - rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); - if(rdman->coord_pool == NULL) { - elmpool_free(rdman->geo_pool); - return ERR; - } - rdman->shnode_pool = elmpool_new(sizeof(shnode_t), 16); - if(rdman->shnode_pool == NULL) { - elmpool_free(rdman->geo_pool); - elmpool_free(rdman->coord_pool); - return ERR; - } - rdman->observer_pool = elmpool_new(sizeof(observer_t), 32); - if(rdman->observer_pool == NULL) { - elmpool_free(rdman->geo_pool); - elmpool_free(rdman->coord_pool); - elmpool_free(rdman->shnode_pool); - return ERR; - } - rdman->subject_pool = elmpool_new(sizeof(subject_t), 32); - if(rdman->subject_pool == NULL) { - elmpool_free(rdman->geo_pool); - elmpool_free(rdman->coord_pool); - elmpool_free(rdman->shnode_pool); - elmpool_free(rdman->observer_pool); - return ERR; - } - rdman->paint_color_pool = elmpool_new(_paint_color_size, 64); - if(rdman->subject_pool == NULL) { - elmpool_free(rdman->geo_pool); - elmpool_free(rdman->coord_pool); - elmpool_free(rdman->shnode_pool); - elmpool_free(rdman->observer_pool); - elmpool_free(rdman->subject_pool); - return ERR; - } + rdman->pent_pool = elmpool_new(sizeof(mb_prop_entry_t), 128); + if(!(rdman->geo_pool && rdman->coord_pool && rdman->shnode_pool && + rdman->observer_pool && rdman->subject_pool && + rdman->paint_color_pool)) + goto err; rdman->ob_factory.subject_alloc = ob_subject_alloc; rdman->ob_factory.subject_free = ob_subject_free; @@ -293,12 +358,24 @@ rdman->redraw = subject_new(&rdman->ob_factory, rdman, OBJT_RDMAN); + rdman->addrm_monitor = + subject_new(&rdman->ob_factory, rdman, OBJT_RDMAN); + if(!(rdman->redraw && rdman->addrm_monitor)) + goto err; + + addrm_ob = subject_add_observer(rdman->addrm_monitor, + addrm_monitor_hdlr, NULL); + if(addrm_ob == NULL) + goto err; + + rdman->last_mouse_over = NULL; rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); if(rdman->root_coord == NULL) redraw_man_destroy(rdman); rdman->n_coords = 1; coord_init(rdman->root_coord, NULL); + mb_prop_store_init(&rdman->root_coord->obj.props, rdman->pent_pool); rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory, rdman->root_coord, OBJT_COORD); @@ -311,8 +388,33 @@ STAILQ_INIT(rdman->shapes); STAILQ_INIT(rdman->paints); + + /* \note To make root coord always have at leat one observer. + * It triggers mouse interpreter to be installed on root. + */ + subject_set_monitor(rdman->root_coord->mouse_event, + rdman->addrm_monitor); + subject_add_observer(rdman->root_coord->mouse_event, + mouse_event_root_dummy, NULL); return OK; + + err: + if(rdman->geo_pool) + elmpool_free(rdman->geo_pool); + if(rdman->coord_pool) + elmpool_free(rdman->coord_pool); + if(rdman->shnode_pool) + elmpool_free(rdman->shnode_pool); + if(rdman->observer_pool) + elmpool_free(rdman->observer_pool); + if(rdman->subject_pool) + elmpool_free(rdman->subject_pool); + if(rdman->paint_color_pool) + elmpool_free(rdman->paint_color_pool); + if(rdman->pent_pool) + elmpool_free(rdman->pent_pool); + return ERR; } void redraw_man_destroy(redraw_man_t *rdman) { @@ -332,9 +434,11 @@ } rdman_coord_free(rdman, saved_coord); } +#if 0 FORMEMBERS(saved_coord, member) { rdman_shape_free(rdman, member->shape); } +#endif /* Resources of root_coord is free by elmpool_free() or * caller; for canvas */ @@ -356,6 +460,7 @@ elmpool_free(rdman->observer_pool); elmpool_free(rdman->subject_pool); elmpool_free(rdman->paint_color_pool); + elmpool_free(rdman->pent_pool); DARRAY_DESTROY(&rdman->dirty_coords); DARRAY_DESTROY(&rdman->dirty_geos); @@ -397,6 +502,7 @@ geo_init(geo); geo->mouse_event = subject_new(&rdman->ob_factory, geo, OBJT_GEO); + subject_set_monitor(geo->mouse_event, rdman->addrm_monitor); geo_attach_coord(geo, coord); @@ -442,14 +548,18 @@ } if(geo != NULL) { + subject_free(geo->mouse_event); geo_detach_coord(geo, shape->coord); sh_detach_coord(shape); sh_detach_geo(shape); - subject_free(geo->mouse_event); elmpool_elm_free(rdman->geo_pool, geo); } STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, shape); shape->free(shape); + + if(rdman->last_mouse_over == (mb_obj_t *)shape) + rdman->last_mouse_over = NULL; + return OK; } @@ -517,9 +627,11 @@ return NULL; coord_init(coord, parent); + mb_prop_store_init(&coord->obj.props, rdman->pent_pool); coord->mouse_event = subject_new(&rdman->ob_factory, coord, OBJT_COORD); + subject_set_monitor(coord->mouse_event, rdman->addrm_monitor); /*! \note default opacity == 1 */ coord->opacity = 1; if(parent) @@ -613,7 +725,7 @@ return OK; } -static _rdman_coord_free_members(redraw_man_t *rdman, coord_t *coord) { +static int _rdman_coord_free_members(redraw_man_t *rdman, coord_t *coord) { geo_t *member; shape_t *shape; int r; @@ -1468,7 +1580,7 @@ dummy->trans_cnt = 0; dummy->draw_cnt = 0; dummy->shape.free = sh_dummy_free; - + rdman_shape_man(rdman, (shape_t *)dummy); return (shape_t *)dummy; diff -r 8be36a0d4239 -r 29e1b2bffe4c src/shape_path.c --- a/src/shape_path.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/shape_path.c Mon Dec 15 10:13:03 2008 +0800 @@ -682,7 +682,7 @@ path = (sh_path_t *)malloc(sizeof(sh_path_t)); /*! \todo Remove this memset()? */ memset(&path->shape, 0, sizeof(shape_t)); - MBO_TYPE(path) = MBO_PATH; + mb_obj_init(path, MBO_PATH); path->cmd_len = cmd_cnt; path->arg_len = arg_cnt; path->fix_arg_len = fix_arg_cnt; @@ -722,7 +722,7 @@ path = (sh_path_t *)malloc(sizeof(sh_path_t)); /*! \todo Remove this memset()? */ memset(&path->shape, 0, sizeof(shape_t)); - MBO_TYPE(path) = MBO_PATH; + mb_obj_init(path, MBO_PATH); path->cmd_len = strlen(commands); path->arg_len = arg_cnt; path->fix_arg_len = fix_arg_cnt; diff -r 8be36a0d4239 -r 29e1b2bffe4c src/shape_rect.c --- a/src/shape_rect.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/shape_rect.c Mon Dec 15 10:13:03 2008 +0800 @@ -27,7 +27,7 @@ memset(rect, 0, sizeof(sh_rect_t)); - MBO_TYPE(rect) = MBO_RECT; + mb_obj_init(rect, MBO_RECT); rect->x = x; rect->y = y; rect->w = w; diff -r 8be36a0d4239 -r 29e1b2bffe4c src/shape_text.c --- a/src/shape_text.c Sun Dec 14 12:53:45 2008 +0800 +++ b/src/shape_text.c Mon Dec 15 10:13:03 2008 +0800 @@ -42,7 +42,7 @@ return NULL; memset(text, 0, sizeof(sh_text_t)); - MBO_TYPE(text) = MBO_TEXT; + mb_obj_init(text, MBO_TEXT); text->data = strdup(txt); if(text->data == NULL) { free(text);