diff src/X_supp.c @ 122:17e97e92b76e

Encapsulate X_MB_runtime_t and support X keyboard events.
author Thinker K.F. Li <thinker@branda.to>
date Mon, 15 Sep 2008 20:33:06 +0800
parents 5df7403b6fbc
children 6a8588df68af
line wrap: on
line diff
--- a/src/X_supp.c	Sun Sep 14 23:40:57 2008 +0800
+++ b/src/X_supp.c	Mon Sep 15 20:33:06 2008 +0800
@@ -9,6 +9,108 @@
 #include "mb_timer.h"
 #include "X_supp.h"
 
+#define ERR -1
+#define OK 0
+
+/*! \ingroup xkb
+ * @{
+ */
+struct _X_kb_info {
+    int keycode_min, keycode_max;
+    int ksym_per_code;
+    KeySym *syms;
+    subject_t *kbevents;
+    ob_factory_t *ob_factory;
+};
+
+/* @} */
+
+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;
+
+    X_kb_info_t kbinfo;
+
+    /* States */
+    shape_t *last;
+};
+
+/*! \defgroup xkb X Keyboard Handling
+ *
+ * Accept keyboard events from X server and delivery it to
+ * application through observer pattern.  There is a subject,
+ * per X-connection, for that.
+ * @{
+ */
+static int keycode2sym(X_kb_info_t *kbinfo, unsigned int keycode) {
+    int sym_idx;
+    int sym;
+
+    sym_idx = kbinfo->ksym_per_code * (keycode - kbinfo->keycode_min);
+    sym =  kbinfo->syms[sym_idx];
+    return sym;
+}
+
+static int X_kb_init(X_kb_info_t *kbinfo, Display *display,
+		     redraw_man_t *rdman) {
+    int n_syms;
+    ob_factory_t *factory;
+    int r;
+
+    r = XDisplayKeycodes(display,
+			 &kbinfo->keycode_min,
+			 &kbinfo->keycode_max);
+    if(r == 0)
+	return ERR;
+
+    n_syms = kbinfo->keycode_max - kbinfo->keycode_min + 1;
+    kbinfo->syms = XGetKeyboardMapping(display, kbinfo->keycode_min,
+				       n_syms,
+				       &kbinfo->ksym_per_code);
+    if(kbinfo->syms == NULL)
+	return ERR;
+
+    factory = rdman_get_ob_factory(rdman);
+    kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB);
+    if(kbinfo->kbevents == NULL)
+	return ERR;
+    kbinfo->ob_factory = factory;
+
+    return OK;
+}
+
+static void X_kb_destroy(X_kb_info_t *kbinfo) {
+    subject_free(kbinfo->ob_factory, kbinfo->kbevents);
+    XFree(kbinfo->syms);
+}
+
+/*! \brief Accept X keyboard events from handle_x_event() and dispatch it.
+ */
+static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) {
+    unsigned int code;
+    int sym;
+    X_kb_event_t event;
+
+    code = xkey->keycode;
+    sym = keycode2sym(kbinfo, code);
+    if(xkey->type == KeyPress)
+	event.event.type = EVT_KB_PRESS;
+    else if(xkey->type == KeyRelease)
+	event.event.type = EVT_KB_RELEASE;
+    event.event.tgt = event.event.cur_tgt = kbinfo->kbevents;
+    event.keycode = code;
+    event.sym = sym;
+
+    subject_notify(kbinfo->ob_factory, kbinfo->kbevents, &event.event);
+}
+
+/* @} */
 
 static unsigned int get_button_state(unsigned int state) {
     unsigned int but = 0;
@@ -72,6 +174,7 @@
     XMotionEvent *mevt;
     XButtonEvent *bevt;
     XExposeEvent *eevt;
+    XKeyEvent *xkey;
     co_aix x, y, w, h;
 
     int eflag = 0;
@@ -145,6 +248,12 @@
 	    }
 	    break;
 
+	case KeyPress:
+	case KeyRelease:
+	    xkey = &evt.xkey;
+	    X_kb_handle_event(&rt->kbinfo, xkey);
+	    break;
+
 	case Expose:
 	    eevt = &evt.xexpose;
 	    x = eevt->x;
@@ -273,7 +382,8 @@
     }
 
     XSelectInput(display, win, PointerMotionMask | ExposureMask |
-		 ButtonPressMask | ButtonReleaseMask);
+		 ButtonPressMask | ButtonReleaseMask |
+		 KeyPressMask | KeyReleaseMask);
     XFlush(display);
 
     *displayp = display;
@@ -288,7 +398,7 @@
  * 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,
+static 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));
 
@@ -318,10 +428,12 @@
 
     xmb_rt->last = NULL;
 
+    X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman);
+
     return OK;
 }
 
-void X_MB_destroy(X_MB_runtime_t *xmb_rt) {
+static void X_MB_destroy(X_MB_runtime_t *xmb_rt) {
     if(xmb_rt->rdman) {
 	redraw_man_destroy(xmb_rt->rdman);
 	free(xmb_rt->rdman);
@@ -342,5 +454,38 @@
 
     if(xmb_rt->display)
 	XCloseDisplay(xmb_rt->display);
+
+    X_kb_destroy(&xmb_rt->kbinfo);
 }
 
+X_MB_runtime_t *X_MB_new(const char *display_name, int w, int h) {
+    X_MB_runtime_t *rt;
+    int r;
+
+    rt = O_ALLOC(X_MB_runtime_t);
+    if(rt == NULL)
+	return NULL;
+
+    r = X_MB_init(display_name, w, h, rt);
+    if(r != OK)
+	return NULL;
+
+    return rt;
+}
+
+void X_MB_free(X_MB_runtime_t *rt) {
+    X_MB_destroy(rt);
+    free(rt);
+}
+
+subject_t *X_MB_kbevents(X_MB_runtime_t *xmb_rt) {
+    return xmb_rt->kbinfo.kbevents;
+}
+
+redraw_man_t *X_MB_rdman(X_MB_runtime_t *xmb_rt) {
+    return xmb_rt->rdman;
+}
+
+mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt) {
+    return xmb_rt->tman;
+}