diff src/redraw_man.c @ 224:29e1b2bffe4c

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.
author Thinker K.F. Li <thinker@branda.to>
date Mon, 15 Dec 2008 10:13:03 +0800
parents c234ee745ceb
children 2637519e2bd7
line wrap: on
line diff
--- 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;