changeset 78:3645e29e4986

Add runtime for Xlib.
author Thinker K.F. Li <thinker@branda.to>
date Wed, 20 Aug 2008 23:33:04 +0800
parents a6763f080da5
children 5bcb329a5157
files examples/svg2code_ex/Makefile examples/svg2code_ex/main.c src/Makefile src/X_supp.c src/X_supp.h src/observer.h src/timertool.c tools/mb_c_header.m4 tools/mb_c_source.m4 tools/svg2code.py
diffstat 10 files changed, 321 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/examples/svg2code_ex/Makefile	Wed Aug 20 00:32:11 2008 +0800
+++ b/examples/svg2code_ex/Makefile	Wed Aug 20 23:33:04 2008 +0800
@@ -1,16 +1,25 @@
 SVG=svg2code_ex.svg
 TOOLSDIR=../../tools
 INCS=-I../../src
-CFLAGS=-g `pkg-config --cflags cairo` $(INCS) -Wall
+CFLAGS+=`pkg-config --cflags cairo` $(INCS) -Wall
+LDFLAGS=-L../../src/ `pkg-config --libs cairo`
+LIBS=-lmbfly
+BINS=	ex1
 
-all:	$(SVG:C/.svg/.o/)
+all:	$(BINS)
+
+ex1:	main.o $(SVG:C/.svg/.o/)
+	$(CC) $(LDFLAGS) -o $@ $(.ALLSRC) $(LIBS)
+
+main.o:	main.c $(SVG:C/.svg/.h/)
+	$(CC) $(CFLAGS) -c -o $@ main.c
 
 $(SVG:C/.svg/.o/): $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/)
 	$(CC) -c $(CFLAGS) -o $@ $(SVG:C/.svg/.c/)
 
 $(SVG:C/.svg/.mb/): $(SVG)
 	$(TOOLSDIR)/svg2code.py $(.ALLSRC) $@
-	
+
 $(SVG:C/.svg/.c/): $(SVG:C/.svg/.mb/)
 	m4 -I $(TOOLSDIR) mb_c_source.m4 $(.ALLSRC) > $@
 
@@ -18,7 +27,7 @@
 	m4 -I $(TOOLSDIR) mb_c_header.m4 $(.ALLSRC) > $@
 
 clean:
-	for i in *.mb *.o *~ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/); do \
+	for i in *.mb *.o *~ $(SVG:C/.svg/.c/) $(SVG:C/.svg/.h/) $(BINS); do \
 		if [ -e "$$i" ]; then \
 			echo "delete $$i"; \
 			rm -f "$$i"; \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/svg2code_ex/main.c	Wed Aug 20 23:33:04 2008 +0800
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <mb_types.h>
+#include <X_supp.h>
+#include "svg2code_ex.h"
+
+int main(int argc, char * const argv[]) {
+    X_MB_runtime_t rt;
+    svg2code_ex_t *svg2code;
+    int r;
+
+    r = X_MB_init(":0.0", 200, 200, &rt);
+
+    svg2code = svg2code_ex_new(rt.rdman);
+    X_MB_handle_connection(rt.display, rt.rdman, rt.tman);
+
+    X_MB_destroy(&rt);
+
+    return 0;
+}
--- a/src/Makefile	Wed Aug 20 00:32:11 2008 +0800
+++ b/src/Makefile	Wed Aug 20 23:33:04 2008 +0800
@@ -5,13 +5,17 @@
 TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g}
 CFLAGS+=	-Wall -I/usr/local/include `pkg-config --cflags cairo`
 LDFLAGS =	`pkg-config --libs cairo`
-BINS =	testcase X_main
+BINS =	testcase libmbfly.a X_main
 
 all: $(BINS)
 
 testcase: testcase.o $(TESTCASE_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $(.ALLSRC) -L/usr/local/lib -lcunit
 
+libmbfly.a: $(OBJS)
+	$(AR) -cr $@ $(.ALLSRC)
+
+
 .for i in $(TESTCASE_OBJS)
 ${i}: ${i:C/testcase-(.*).o/\1.c/}
 	$(CC) $(CFLAGS) -DUNITTEST -g -c -o $@ $(.ALLSRC)
@@ -20,7 +24,7 @@
 testcase.o:	testcase.c
 	$(CC) $(CFLAGS) -c $(.ALLSRC)
 
-X_main: X_main.o $(OBJS)
+X_main: X_main.o libmbfly.a
 	$(CC) $(CFALGS) `pkg-config --libs cairo` -o $@ $(.ALLSRC)
 
 X_main.o: X_main.c
--- a/src/X_supp.c	Wed Aug 20 00:32:11 2008 +0800
+++ b/src/X_supp.c	Wed Aug 20 23:33:04 2008 +0800
@@ -1,24 +1,83 @@
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
 #include "redraw_man.h"
 #include "mb_timer.h"
+#include "X_supp.h"
 
 
-/*! \brief Dispatch all events in the queue.
+static unsigned int get_button_state(unsigned int state) {
+    unsigned int but = 0;
+
+    if(state & Button1Mask)
+	but |= MOUSE_BUT1;
+    if(state & Button2Mask)
+	but |= MOUSE_BUT2;
+    if(state & Button3Mask)
+	but |= MOUSE_BUT3;
+    
+    return but;
+}
+
+static unsigned int get_button(unsigned int button) {
+    switch(button) {
+    case Button1:
+	return MOUSE_BUT1;
+    case Button2:
+	return MOUSE_BUT2;
+    case Button3:
+	return MOUSE_BUT3;
+    }
+    return 0;
+}
+
+/*! \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_shapes(redraw_man_t *rdman,
+			  co_aix x, co_aix y, int etype,
+			  unsigned int state,
+			  unsigned int button) {
+    mouse_event_t mouse_event;
+    shape_t *shape;
+    subject_t *subject;
+    ob_factory_t *factory;
+    int in_stroke;
+
+    mouse_event.event.type = etype;
+    mouse_event.x = x;
+    mouse_event.y = y;
+    mouse_event.but_state = state;
+    mouse_event.button = button;
+    
+    shape = find_shape_at_pos(rdman, x, y,
+			      &in_stroke);
+    if(shape == NULL)
+	return;
+    subject = sh_get_mouse_event_subject(shape);
+    factory = rdman_get_ob_factory(rdman);
+    
+    subject_notify(factory, subject, (event_t *)&mouse_event);
+}
+
+/*! \brief Dispatch all X events in the queue.
  */
 static void handle_x_event(Display *display,
 			   redraw_man_t *rdman,
 			   mb_tman_t *tman) {
     XEvent evt;
     XMotionEvent *mevt;
-    mouse_event_t mouse_event;
-    shape_t *shape;
-    subject_t *subject;
-    ob_factory_t *factory;
+    XButtonEvent *bevt;
     co_aix x, y;
-    int in_stroke;
-    int but;
+    unsigned int state, button;
     int r;
 
     while(XEventsQueued(display, QueuedAfterReading) > 0) {
@@ -27,29 +86,35 @@
 	    break;
 
 	switch(evt.type) {
+	case ButtonPress:
+	    bevt = (XButtonEvent *)&evt;
+	    x = bevt->x;
+	    y = bevt->y;
+	    state = get_button_state(bevt->state);
+	    button = get_button(bevt->button);
+
+	    notify_shapes(rdman, x, y, EVT_MOUSE_BUT_PRESS,
+			  state, button);
+	    break;
+
+	case ButtonRelease:
+	    bevt = (XButtonEvent *)&evt;
+	    x = bevt->x;
+	    y = bevt->y;
+	    state = get_button_state(bevt->state);
+	    button = get_button(bevt->button);
+
+	    notify_shapes(rdman, x, y, EVT_MOUSE_BUT_RELEASE,
+			  state, button);
+	    break;
+
 	case MotionNotify:
 	    mevt = (XMotionEvent *)&evt;
 	    x = mevt->x;
 	    y = mevt->y;
-	    but = 0;
-	    if(mevt->state & Button1Mask)
-		but |= MOUSE_BUT1;
-	    if(mevt->state & Button2Mask)
-		but |= MOUSE_BUT2;
-	    if(mevt->state & Button3Mask)
-		but |= MOUSE_BUT3;
+	    state = get_button_state(mevt->state);
 
-	    mouse_event.event.type = EVT_MOUSE_MOVE;
-	    mouse_event.x = x;
-	    mouse_event.y = y;
-	    mouse_event.button = but;
-
-	    shape = find_shape_at_pos(rdman, x, y,
-				      &in_stroke);
-	    subject = sh_get_mouse_event_subject(shape);
-	    factory = rdman_get_ob_factory(rdman);
-
-	    subject_notify(factory, subject, (event_t *)&mouse_event);
+	    notify_shapes(rdman, x, y, EVT_MOUSE_MOVE, state, 0);
 	    break;
 
 	case Expose:
@@ -63,10 +128,17 @@
 }
 
 /*! \brief Handle connection coming data and timeout of timers.
+ *
+ * \param display is a Display returned by XOpenDisplay().
+ * \param rdman is a redraw manager.
+ * \param tman is a timer manager.
+ *
+ * The display is managed by specified rdman and tman.  rdman draws
+ * on the display, and tman trigger actions according timers.
  */
-void X_handle_connection(Display *display,
-			 redraw_man_t *rdman,
-			 mb_tman_t *tman) {
+void X_MB_handle_connection(Display *display,
+			    redraw_man_t *rdman,
+			    mb_tman_t *tman) {
     int fd;
     mb_timeval_t now, tmo;
     struct timeval tv;
@@ -74,6 +146,9 @@
     int nfds;
     int r;
 
+    rdman_redraw_all(rdman);
+    XFlush(display);
+
     fd = XConnectionNumber(display);
     nfds = fd + 1;
     while(1) {
@@ -105,3 +180,112 @@
 	}
     }
 }
+
+#define ERR -1
+#define OK 0
+
+static int X_init_connection(const char *display_name,
+			     int w, int h,
+			     Display **displayp,
+			     Visual **visualp,
+			     Window *winp) {
+    Display *display;
+    Window root, win;
+    Visual *visual;
+    int screen;
+    XSetWindowAttributes wattr;
+    int depth;
+    int x, y;
+    int r;
+
+    display = XOpenDisplay(display_name);
+    if(display == NULL)
+	return ERR;
+
+    screen = DefaultScreen(display);
+    root = DefaultRootWindow(display);
+    visual = DefaultVisual(display, screen);
+    depth = DefaultDepth(display, screen);
+    wattr.override_redirect = False;
+    x = 10;
+    y = 10;
+    win = XCreateWindow(display, root,
+			 x, y,
+			 w, h,
+			 1, depth, InputOutput, visual,
+			 CWOverrideRedirect, &wattr);
+    r = XMapWindow(display, win);
+    if(r == -1) {
+	XCloseDisplay(display);
+	return ERR;
+    }
+
+    XSelectInput(display, win, PointerMotionMask | ExposureMask);
+    XFlush(display);
+
+    *displayp = display;
+    *visualp = visual;
+    *winp = win;
+
+    return OK;
+}
+
+/*! \brief Initialize a MadButterfy runtime for Xlib.
+ *
+ * It setups a runtime environment to run MadButterfly with Xlib.
+ * Users should specify width and height of the opening window.
+ */
+int X_MB_init(const char *display_name,
+	      int w, int h, X_MB_runtime_t *xmb_rt) {
+    memset(xmb_rt, 0, sizeof(X_MB_runtime_t));
+
+    xmb_rt->w = w;
+    xmb_rt->h = h;
+    X_init_connection(display_name, w, h, &xmb_rt->display,
+		      &xmb_rt->visual, &xmb_rt->win);
+
+    xmb_rt->surface =
+	cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
+    
+    xmb_rt->backend_surface =
+	cairo_xlib_surface_create(xmb_rt->display,
+				  xmb_rt->win,
+				  xmb_rt->visual,
+				  w, h);
+
+    xmb_rt->cr = cairo_create(xmb_rt->surface);
+    xmb_rt->backend_cr = cairo_create(xmb_rt->backend_surface);
+
+    cairo_set_source_surface(xmb_rt->backend_cr, xmb_rt->surface, 0, 0);
+
+    xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
+    redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr);
+
+    xmb_rt->tman = mb_tman_new();
+
+    return OK;
+}
+
+void X_MB_destroy(X_MB_runtime_t *xmb_rt) {
+    if(xmb_rt->rdman) {
+	redraw_man_destroy(xmb_rt->rdman);
+	free(xmb_rt->rdman);
+    }
+
+    if(xmb_rt->tman)
+	mb_tman_free(xmb_rt->tman);
+
+    if(xmb_rt->cr)
+	cairo_destroy(xmb_rt->cr);
+    if(xmb_rt->backend_cr)
+	cairo_destroy(xmb_rt->backend_cr);
+
+    if(xmb_rt->surface)
+	cairo_surface_destroy(xmb_rt->surface);
+    if(xmb_rt->backend_surface)
+	cairo_surface_destroy(xmb_rt->backend_surface);
+
+    if(xmb_rt->display)
+	XCloseDisplay(xmb_rt->display);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/X_supp.h	Wed Aug 20 23:33:04 2008 +0800
@@ -0,0 +1,28 @@
+#ifndef __X_SUPP_H_
+#define __X_SUPP_H_
+
+#include <X11/Xlib.h>
+#include "mb_timer.h"
+#include "redraw_man.h"
+
+typedef struct _X_MB_runtime X_MB_runtime_t;
+struct _X_MB_runtime {
+    Display *display;
+    Window win;
+    Visual *visual;
+    cairo_surface_t *surface, *backend_surface;
+    cairo_t *cr, *backend_cr;
+    redraw_man_t *rdman;
+    mb_tman_t *tman;
+    int w, h;
+};
+
+extern void X_MB_handle_connection(Display *display,
+				   redraw_man_t *rdman,
+				   mb_tman_t *tman);
+extern int X_MB_init(const char *display_name,
+		     int w, int h, X_MB_runtime_t *xmb_rt);
+extern void X_MB_destroy(X_MB_runtime_t *xmb_rt);
+
+
+#endif
--- a/src/observer.h	Wed Aug 20 00:32:11 2008 +0800
+++ b/src/observer.h	Wed Aug 20 23:33:04 2008 +0800
@@ -15,18 +15,29 @@
     subject_t *tgt, *cur_tgt;
 };
 
+/*! \brief Observer of observer pattern.
+ *
+ * A target for receiving events.
+ */
 struct _observer {
     evt_handler hdr;
     void *arg;
     observer_t *next;
 };
 
+/*! \brief Subject of observer pattern.
+ *
+ * Observer is a pattern to decouple caller and callee,
+ * especial for multiple callee.
+ * \see http://en.wikipedia.org/wiki/Observer_pattern
+ */
 struct _subject {
-    int obj_type;
-    void *obj;
+    int obj_type;		/*!< type of object (a.k.a. OBJT_*). */
+    void *obj;			/*!< the object this subject for. */
     int flags;
     STAILQ(observer_t) observers;
 };
+/*! \brief Flag that make a subject to propagate events to parents. */
 #define SUBF_STOP_PROPAGATE 0x1
 
 enum {OBJT_GEO, OBJT_COORD};
@@ -34,7 +45,8 @@
 struct _mouse_event {
     event_t event;
     int x, y;
-    int button;
+    unsigned int but_state;
+    unsigned int button;
 };
 
 #define MOUSE_BUT1 0x1
--- a/src/timertool.c	Wed Aug 20 00:32:11 2008 +0800
+++ b/src/timertool.c	Wed Aug 20 23:33:04 2008 +0800
@@ -13,16 +13,20 @@
     static uint64_t cpufreq;
     static mb_timeval_t tm = {0, 0};
     static uint64_t last_ts;
-
     mb_timeval_t diff_tm;
     uint64_t ts, diff, udiff, sdiff;
     size_t sysctl_sz;
+    int r;
 
     if(MB_TIMEVAL_SEC(&tm) == 0) {
 	sysctl_sz = sizeof(uint64_t);
-	cpufreq = sysctlbyname("kern.timecounter.tc.TSC.frequency",
-			       &cpufreq, &sysctl_sz,
-			       NULL, 0);
+	r = sysctlbyname("kern.timecounter.tc.TSC.frequency",
+			 &cpufreq, &sysctl_sz,
+			 NULL, 0);
+	if(r == -1) {
+	    perror("sysctl");
+	    return;
+	}
 
 	gettimeofday(&tv, NULL);
 	last_ts = rdtsc();
--- a/tools/mb_c_header.m4	Wed Aug 20 00:32:11 2008 +0800
+++ b/tools/mb_c_header.m4	Wed Aug 20 23:33:04 2008 +0800
@@ -19,7 +19,8 @@
 ]])
 define([COLOR_STOP],[ ])
 
-define([REF_STOPS],)
+define([REF_STOPS_RADIAL],)
+define([REF_STOPS_LINEAR],)
 define([FILL_SHAPE],[[
     paint_t *$1_fill;
 ]])
--- a/tools/mb_c_source.m4	Wed Aug 20 00:32:11 2008 +0800
+++ b/tools/mb_c_source.m4	Wed Aug 20 23:33:04 2008 +0800
@@ -32,7 +32,8 @@
 DIMPORT([ADD_LINEAR_PAINT])
 DIMPORT([ADD_RADIAL_PAINT])
 DIMPORT([COLOR_STOP])
-define([REF_STOPS])
+define([REF_STOPS_RADIAL])
+define([REF_STOPS_LINEAR])
 define([ADD_PATH])
 define([ADD_RECT])
 define([ADD_COORD])
@@ -61,12 +62,19 @@
 ])
 
 define([S_COLOR_STOP],[])
-define([S_REF_STOPS],[dnl
+
+define([S_REF_STOPS_RADIAL],[dnl
 [    stops = (grad_stop_t *)malloc(sizeof(grad_stop_t) * n_$2_stops);
     memcpy(stops, $2_stops, sizeof(grad_stop_t) * n_$2_stops);
     paint_radial_stops(obj->$1, n_$2_stops, stops);
 ]])
 
+define([S_REF_STOPS_LINEAR],[dnl
+[    stops = (grad_stop_t *)malloc(sizeof(grad_stop_t) * n_$2_stops);
+    memcpy(stops, $2_stops, sizeof(grad_stop_t) * n_$2_stops);
+    paint_linear_stops(obj->$1, n_$2_stops, stops);
+]])
+
 define([S_ADD_RECT],[[
     obj->$1 = sh_rect_new($2, $3, $4, $5, 0, 0);
     rdman_add_shape(rdman, obj->$1, obj->$6);
@@ -104,7 +112,8 @@
 SIMPORT([ADD_LINEAR_PAINT])
 SIMPORT([ADD_RADIAL_PAINT])
 SIMPORT([COLOR_STOP])
-SIMPORT([REF_STOPS])
+SIMPORT([REF_STOPS_RADIAL])
+SIMPORT([REF_STOPS_LINEAR])
 SIMPORT([ADD_PATH],)
 SIMPORT([ADD_RECT])
 SIMPORT([ADD_COORD])
@@ -147,7 +156,8 @@
 FIMPORT([ADD_LINEAR_PAINT])
 FIMPORT([ADD_RADIAL_PAINT])
 define([COLOR_STOP])
-define([REF_STOPS])
+define([REF_STOPS_RADIAL])
+define([REF_STOPS_LINEAR])
 FIMPORT([ADD_PATH],)
 FIMPORT([ADD_RECT])
 define([ADD_COORD])
--- a/tools/svg2code.py	Wed Aug 20 00:32:11 2008 +0800
+++ b/tools/svg2code.py	Wed Aug 20 23:33:04 2008 +0800
@@ -51,7 +51,8 @@
 
     href = linear.getAttributeNS(xlinkns, 'href').strip()
     if href and href[0] == '#':
-        print >> codefo, 'REF_STOPS([%s], [%s])dnl' % (linear_id, href[1:])
+        print >> codefo, 'REF_STOPS_LINEAR([%s], [%s])dnl' % (
+            linear_id, href[1:])
         pass
     pass
 
@@ -75,7 +76,8 @@
 
     href = radial.getAttributeNS(xlinkns, 'href').strip()
     if href[0] == '#':
-        print >> codefo, 'REF_STOPS([%s], [%s])dnl' % (radial_id, href[1:])
+        print >> codefo, 'REF_STOPS_RADIAL([%s], [%s])dnl' % (
+            radial_id, href[1:])
         pass
     pass