changeset 39:db2aa914e14b

timer for animation
author Thinker K.F. Li <thinker@branda.to>
date Wed, 06 Aug 2008 21:05:11 +0800
parents 8d219ebd729e
children e292beec12d4
files src/Makefile src/X_main.c src/mb_timer.h src/timer.c src/tools.h
diffstat 5 files changed, 255 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile	Wed Aug 06 10:20:34 2008 +0800
+++ b/src/Makefile	Wed Aug 06 21:05:11 2008 +0800
@@ -1,5 +1,5 @@
 SRCS =	coord.c geo.c shape_path.c shape_text.c shape_rect.c \
-	redraw_man.c paint.c event.c tools.c
+	redraw_man.c timer.c paint.c event.c tools.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`
--- a/src/X_main.c	Wed Aug 06 10:20:34 2008 +0800
+++ b/src/X_main.c	Wed Aug 06 21:05:11 2008 +0800
@@ -1,5 +1,7 @@
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/time.h>
+#include <sys/select.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <cairo.h>
@@ -9,10 +11,29 @@
 #include "shapes.h"
 #include "redraw_man.h"
 #include "paint.h"
+#include "mb_timer.h"
+
+#define OK 0
+#define ERR -1
 
 Display *display;
 Window win;
 
+struct test_motion_data {
+    paint_t *text_stroke;
+    redraw_man_t *rdman;
+};
+
+void test_motion(mbsec_t sec, mbusec_t usec,
+		 mbsec_t now_sec, mbusec_t now_usec,
+		 void *arg) {
+    struct test_motion_data *data = (struct test_motion_data *)arg;
+
+    paint_color_set(data->text_stroke, 1, 0.5, 0.5, 0.5);
+    rdman_paint_changed(data->rdman, data->text_stroke);
+    rdman_redraw_changed(data->rdman);
+}
+
 void hint_shape(redraw_man_t *rdman, shape_t *shape) {
     static shape_t *last_shape = NULL;
     if(last_shape != shape) {
@@ -38,8 +59,11 @@
     shape_t *shape = NULL;
     int in_stroke;
 
-    XSelectInput(display, win, PointerMotionMask | ExposureMask);
-    while((r = XNextEvent(display, &evt)) == 0) {
+    while(XEventsQueued(display, QueuedAfterReading) > 0) {
+	r = XNextEvent(display, &evt);
+	if(r == -1)
+	    break;
+
 	switch(evt.type) {
 	case MotionNotify:
 	    mevt = (XMotionEvent *)&evt;
@@ -55,6 +79,56 @@
 	    break;
 	}
     }
+    XFlush(display);
+}
+
+void handle_connection(Display *display, mb_tman_t *tman,
+		       redraw_man_t *rdman, int w, int h) {
+    int xcon;
+    fd_set rds;
+    int nfds;
+    struct timeval tmo;
+    int r;
+
+    XSelectInput(display, win, PointerMotionMask | ExposureMask);
+    XFlush(display);
+
+    xcon = XConnectionNumber(display);
+    nfds = xcon + 1;
+    while(1) {
+	FD_ZERO(&rds);
+	FD_SET(xcon, &rds);
+	r = gettimeofday(&tmo, NULL);
+	if(r == -1) {
+	    perror("gettimeofday");
+	    return;
+	}
+
+	r = mb_tman_next_timeout(tman,
+				 tmo.tv_sec, tmo.tv_usec,
+				 (mbsec_t *)&tmo.tv_sec,
+				 (mbusec_t *)&tmo.tv_usec);
+	if(r != OK)
+	    r = select(nfds, &rds, NULL, NULL, NULL);
+	else
+	    r = select(nfds, &rds, NULL, NULL, &tmo);
+
+	if(r == -1) {
+	    perror("select");
+	    return;
+	}
+	if(r == 0) {
+	    r = gettimeofday(&tmo, NULL);
+	    if(r == -1) {
+		perror("gettimeofday");
+		return;
+	    }
+	    mb_tman_handle_timeout(tman, tmo.tv_sec, tmo.tv_usec);
+	    XFlush(display);
+	} else if(FD_ISSET(xcon, &rds)) {
+	    event_interaction(display, rdman, w, h);
+	}
+    }
 }
 
 void draw_path(cairo_t *cr, int w, int h) {
@@ -68,6 +142,9 @@
     shape_t *text;
     grad_stop_t fill3_stops[3];
     cairo_font_face_t *face;
+    struct test_motion_data mdata;
+    struct timeval tv;
+    mb_tman_t *tman;
     int i;
 
     tmpsuf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
@@ -213,7 +290,18 @@
 	XFlush(display);
     }
 
-    event_interaction(display, &rdman, w, h);
+    tman = mb_tman_new();
+    if(tman) {
+	mdata.text_stroke = text_stroke;
+	mdata.rdman = &rdman;
+	gettimeofday(&tv, NULL);
+	tv.tv_sec += 3;
+	mb_tman_timeout(tman, tv.tv_sec, tv.tv_usec,
+			test_motion, &mdata);
+
+	handle_connection(display, tman, &rdman, w, h);
+	mb_tman_free(tman);
+    }
 
     fill1->free(fill1);
     fill2->free(fill2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mb_timer.h	Wed Aug 06 21:05:11 2008 +0800
@@ -0,0 +1,27 @@
+#ifndef __MB_TIMER_H_
+#define __MB_TIMER_H_
+
+typedef uint32_t mbsec_t;
+typedef uint32_t mbusec_t;
+typedef struct _mb_timer mb_timer_t;
+typedef struct _mb_tman mb_tman_t;
+
+typedef void (*mb_tmo_hdlr)(mbsec_t sec, mbusec_t usec,
+			    mbsec_t now_sec, mbusec_t now_usec,
+			    void *arg);
+
+extern mb_tman_t *mb_tman_new(void);
+extern void mb_tman_free(mb_tman_t *tman);
+extern mb_timer_t *mb_tman_timeout(mb_tman_t *tman,
+				   mbsec_t sec, mbusec_t usec,
+				   mb_tmo_hdlr hdlr, void *arg);
+extern int mb_tman_remove(mb_tman_t *tman, mb_timer_t *timer);
+extern int mb_tman_next_timeout(mb_tman_t *tman,
+				mbsec_t now_sec, mbusec_t now_usec,
+				mbsec_t *after_sec, mbusec_t *after_usec);
+extern int mb_tman_handle_timeout(mb_tman_t *tman,
+				  mbsec_t now_sec, mbusec_t now_usec);
+
+
+
+#endif /* __MB_TIMER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/timer.c	Wed Aug 06 21:05:11 2008 +0800
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "mb_timer.h"
+#include "tools.h"
+
+
+#define OK 0
+#define ERR -1
+
+struct _mb_timer {
+    mbsec_t sec;
+    mbusec_t usec;
+    mb_tmo_hdlr hdlr;
+    void *arg;
+    mb_timer_t *next;
+};
+
+struct _mb_tman {
+    STAILQ(mb_timer_t) timers;
+    elmpool_t *timer_pool;
+};
+
+mb_tman_t *mb_tman_new(void) {
+    mb_tman_t *tman;
+    
+    tman = (mb_tman_t *)malloc(sizeof(mb_tman_t));
+    if(tman == NULL)
+	return NULL;
+
+    tman->timer_pool = elmpool_new(sizeof(mb_timer_t), 32);
+    if(tman->timer_pool == NULL) {
+	free(tman);
+	return NULL;
+    }
+
+    STAILQ_INIT(tman->timers);
+
+    return tman;
+}
+
+void mb_tman_free(mb_tman_t *tman) {
+    elmpool_free(tman->timer_pool);
+    free(tman);
+}
+
+mb_timer_t *mb_tman_timeout(mb_tman_t *tman,
+			    mbsec_t sec, mbusec_t usec,
+			    mb_tmo_hdlr hdlr, void *arg) {
+    mb_timer_t *timer, *visit, *last;
+
+    timer = elmpool_elm_alloc(tman->timer_pool);
+    if(timer == NULL)
+	return NULL;
+
+    timer->sec = sec;
+    timer->usec = usec;
+    timer->hdlr = hdlr;
+    timer->arg = arg;
+
+    last = NULL;
+    for(visit = STAILQ_HEAD(tman->timers);
+	visit != NULL;
+	visit = STAILQ_NEXT(mb_timer_t, next, visit)) {
+	if(sec < visit->sec)
+	    break;
+	if(sec == visit->sec && usec < visit->usec)
+	    break;
+	last = visit;
+    }
+
+    if(last == NULL)
+	STAILQ_INS(tman->timers, mb_timer_t, next, timer);
+    else if(visit == NULL)
+	STAILQ_INS_TAIL(tman->timers, mb_timer_t, next, timer);
+    else
+	STAILQ_INS_AFTER(mb_timer_t, next, timer, last);
+
+    return timer;
+}
+			    
+int mb_tman_remove(mb_tman_t *tman, mb_timer_t *timer) {
+    STAILQ_REMOVE(tman->timers, mb_timer_t, next, timer);
+    elmpool_elm_free(tman->timer_pool, timer);
+
+    return OK;
+}
+
+int mb_tman_next_timeout(mb_tman_t *tman,
+			 mbsec_t now_sec, mbusec_t now_usec,
+			 mbsec_t *after_sec, mbusec_t *after_usec) {
+    mb_timer_t *timer;
+
+    timer = STAILQ_HEAD(tman->timers);
+    if(timer == NULL)
+	return ERR;
+
+    if(now_sec > timer->sec ||
+       (now_sec == timer->usec && now_usec >= timer->usec)) {
+	*after_sec = 0;
+	*after_usec = 0;
+	return OK;
+    }
+
+    *after_sec = timer->sec - now_sec;
+    if(now_usec > timer->usec) {
+	--*after_sec;
+	*after_usec = 1000000 + timer->usec - now_usec;
+    } else
+	*after_usec = timer->usec - now_usec;
+
+    return OK;
+}
+
+int mb_tman_handle_timeout(mb_tman_t *tman,
+			   mbsec_t now_sec, mbusec_t now_usec) {
+    mb_timer_t *timer;
+
+    while((timer = STAILQ_HEAD(tman->timers)) != NULL){
+	if(now_sec < timer->sec ||
+	   (now_sec == timer->sec && now_usec < timer->usec))
+	    break;
+	timer->hdlr(timer->sec, timer->usec,
+		    now_sec, now_usec,
+		    timer->arg);
+	STAILQ_REMOVE(tman->timers, mb_timer_t, next, timer);
+	elmpool_elm_free(tman->timer_pool, timer);
+    }
+
+    return OK;
+}
--- a/src/tools.h	Wed Aug 06 10:20:34 2008 +0800
+++ b/src/tools.h	Wed Aug 06 21:05:11 2008 +0800
@@ -39,6 +39,11 @@
 	if((q).head == NULL)			\
 	    (q).head = elm;			\
     } while(0)
+#define STAILQ_INS_AFTER(type, field, follow, elm)	\
+    do {						\
+	(follow)->field = (elm)->field;			\
+	(elm)->field = follow;				\
+    } while(0)
 #define STAILQ_REMOVE(q, type, field, elm)		\
     do {						\
 	if((elm) == (q).head) {				\