diff src/X_supp.c @ 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 13fdf205047b
line wrap: on
line diff
--- 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);
+}
+