00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <X11/Xlib.h>
00005 #include <X11/Xutil.h>
00006 #include <cairo.h>
00007 #include <cairo-xlib.h>
00008 #include "mb_redraw_man.h"
00009 #include "mb_timer.h"
00010 #include "mb_X_supp.h"
00011
00012 #define ERR -1
00013 #define OK 0
00014
00015
00016
00017
00018 struct _X_kb_info {
00019 int keycode_min, keycode_max;
00020 int ksym_per_code;
00021 KeySym *syms;
00022 subject_t *kbevents;
00023 ob_factory_t *ob_factory;
00024 };
00025
00026
00027
00028 struct _X_MB_runtime {
00029 Display *display;
00030 Window win;
00031 Visual *visual;
00032 cairo_surface_t *surface, *backend_surface;
00033 cairo_t *cr, *backend_cr;
00034 redraw_man_t *rdman;
00035 mb_tman_t *tman;
00036 int w, h;
00037
00038 X_kb_info_t kbinfo;
00039
00040
00041 shape_t *last;
00042 };
00043
00044
00045
00046
00047
00048
00049
00050
00051 static int keycode2sym(X_kb_info_t *kbinfo, unsigned int keycode) {
00052 int sym_idx;
00053 int sym;
00054
00055 sym_idx = kbinfo->ksym_per_code * (keycode - kbinfo->keycode_min);
00056 sym = kbinfo->syms[sym_idx];
00057 return sym;
00058 }
00059
00060 static int X_kb_init(X_kb_info_t *kbinfo, Display *display,
00061 redraw_man_t *rdman) {
00062 int n_syms;
00063 ob_factory_t *factory;
00064 int r;
00065
00066 r = XDisplayKeycodes(display,
00067 &kbinfo->keycode_min,
00068 &kbinfo->keycode_max);
00069 if(r == 0)
00070 return ERR;
00071
00072 n_syms = kbinfo->keycode_max - kbinfo->keycode_min + 1;
00073 kbinfo->syms = XGetKeyboardMapping(display, kbinfo->keycode_min,
00074 n_syms,
00075 &kbinfo->ksym_per_code);
00076 if(kbinfo->syms == NULL)
00077 return ERR;
00078
00079 factory = rdman_get_ob_factory(rdman);
00080 kbinfo->kbevents = subject_new(factory, kbinfo, OBJT_KB);
00081 if(kbinfo->kbevents == NULL)
00082 return ERR;
00083 kbinfo->ob_factory = factory;
00084
00085 return OK;
00086 }
00087
00088 static void X_kb_destroy(X_kb_info_t *kbinfo) {
00089 subject_free(kbinfo->ob_factory, kbinfo->kbevents);
00090 XFree(kbinfo->syms);
00091 }
00092
00093
00094
00095 static void X_kb_handle_event(X_kb_info_t *kbinfo, XKeyEvent *xkey) {
00096 unsigned int code;
00097 int sym;
00098 X_kb_event_t event;
00099
00100 code = xkey->keycode;
00101 sym = keycode2sym(kbinfo, code);
00102 if(xkey->type == KeyPress)
00103 event.event.type = EVT_KB_PRESS;
00104 else if(xkey->type == KeyRelease)
00105 event.event.type = EVT_KB_RELEASE;
00106 event.event.tgt = event.event.cur_tgt = kbinfo->kbevents;
00107 event.keycode = code;
00108 event.sym = sym;
00109
00110 subject_notify(kbinfo->ob_factory, kbinfo->kbevents, &event.event);
00111 }
00112
00113
00114
00115 static unsigned int get_button_state(unsigned int state) {
00116 unsigned int but = 0;
00117
00118 if(state & Button1Mask)
00119 but |= MOUSE_BUT1;
00120 if(state & Button2Mask)
00121 but |= MOUSE_BUT2;
00122 if(state & Button3Mask)
00123 but |= MOUSE_BUT3;
00124
00125 return but;
00126 }
00127
00128 static unsigned int get_button(unsigned int button) {
00129 switch(button) {
00130 case Button1:
00131 return MOUSE_BUT1;
00132 case Button2:
00133 return MOUSE_BUT2;
00134 case Button3:
00135 return MOUSE_BUT3;
00136 }
00137 return 0;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147 static void notify_shapes(redraw_man_t *rdman,
00148 shape_t *shape,
00149 co_aix x, co_aix y, int etype,
00150 unsigned int state,
00151 unsigned int button) {
00152 mouse_event_t mouse_event;
00153 subject_t *subject;
00154 ob_factory_t *factory;
00155
00156 mouse_event.event.type = etype;
00157 mouse_event.x = x;
00158 mouse_event.y = y;
00159 mouse_event.but_state = state;
00160 mouse_event.button = button;
00161
00162 subject = sh_get_mouse_event_subject(shape);
00163 factory = rdman_get_ob_factory(rdman);
00164
00165 subject_notify(factory, subject, (event_t *)&mouse_event);
00166 }
00167
00168
00169
00170 static void handle_x_event(X_MB_runtime_t *rt) {
00171 Display *display = rt->display;
00172 redraw_man_t *rdman = rt->rdman;
00173 XEvent evt;
00174 XMotionEvent *mevt;
00175 XButtonEvent *bevt;
00176 XExposeEvent *eevt;
00177 XKeyEvent *xkey;
00178 co_aix x, y, w, h;
00179
00180 int eflag = 0;
00181 int ex1=0, ey1=0, ex2=0, ey2=0;
00182
00183 shape_t *shape;
00184
00185 unsigned int state, button;
00186 int in_stroke;
00187 int r;
00188
00189 while(XEventsQueued(display, QueuedAfterReading) > 0) {
00190 r = XNextEvent(display, &evt);
00191 if(r == -1)
00192 break;
00193
00194 switch(evt.type) {
00195 case ButtonPress:
00196 bevt = (XButtonEvent *)&evt;
00197 x = bevt->x;
00198 y = bevt->y;
00199 state = get_button_state(bevt->state);
00200 button = get_button(bevt->button);
00201
00202 shape = find_shape_at_pos(rdman, x, y,
00203 &in_stroke);
00204 if(shape)
00205 notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_PRESS,
00206 state, button);
00207 break;
00208
00209 case ButtonRelease:
00210 bevt = (XButtonEvent *)&evt;
00211 x = bevt->x;
00212 y = bevt->y;
00213 state = get_button_state(bevt->state);
00214 button = get_button(bevt->button);
00215
00216 shape = find_shape_at_pos(rdman, x, y,
00217 &in_stroke);
00218 if(shape)
00219 notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_RELEASE,
00220 state, button);
00221 break;
00222
00223 case MotionNotify:
00224 mevt = (XMotionEvent *)&evt;
00225 x = mevt->x;
00226 y = mevt->y;
00227 state = get_button_state(mevt->state);
00228
00229 shape = find_shape_at_pos(rdman, x, y,
00230 &in_stroke);
00231 if(shape != NULL) {
00232 if(rt->last != shape) {
00233 if(rt->last)
00234 notify_shapes(rdman, rt->last, x, y,
00235 EVT_MOUSE_OUT, state, 0);
00236 notify_shapes(rdman, shape, x, y,
00237 EVT_MOUSE_OVER, state, 0);
00238 rt->last = shape;
00239 } else
00240 notify_shapes(rdman, shape, x, y,
00241 EVT_MOUSE_MOVE, state, 0);
00242 } else {
00243 if(rt->last) {
00244 notify_shapes(rdman, rt->last, x, y,
00245 EVT_MOUSE_OUT, state, 0);
00246 rt->last = NULL;
00247 }
00248 }
00249 break;
00250
00251 case KeyPress:
00252 case KeyRelease:
00253 xkey = &evt.xkey;
00254 X_kb_handle_event(&rt->kbinfo, xkey);
00255 break;
00256
00257 case Expose:
00258 eevt = &evt.xexpose;
00259 x = eevt->x;
00260 y = eevt->y;
00261 w = eevt->width;
00262 h = eevt->height;
00263
00264 if(eflag) {
00265 if(x < ex1)
00266 ex1 = x;
00267 if(y < ey1)
00268 ey1 = y;
00269 if((x + w) > ex2)
00270 ex2 = x + w;
00271 if((y + h) > ey2)
00272 ey2 = y + h;
00273 } else {
00274 ex1 = x;
00275 ey1 = y;
00276 ex2 = x + w;
00277 ey2 = y + h;
00278 eflag = 1;
00279 }
00280 break;
00281 }
00282 }
00283 if(eflag) {
00284 rdman_redraw_area(rdman, ex1, ey1, (ex2 - ex1), (ey2 - ey1));
00285 eflag = 0;
00286 }
00287 XFlush(display);
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 void X_MB_handle_connection(X_MB_runtime_t *rt) {
00300 Display *display = rt->display;
00301 redraw_man_t *rdman = rt->rdman;
00302 mb_tman_t *tman = rt->tman;
00303 int fd;
00304 mb_timeval_t now, tmo;
00305 struct timeval tv;
00306 fd_set rfds;
00307 int nfds;
00308 int r, r1;
00309
00310 handle_x_event(rt);
00311
00312 fd = XConnectionNumber(display);
00313 nfds = fd + 1;
00314 while(1) {
00315 FD_ZERO(&rfds);
00316 FD_SET(fd, &rfds);
00317
00318 get_now(&now);
00319 r = mb_tman_next_timeout(tman, &now, &tmo);
00320
00321 if(r == 0) {
00322 tv.tv_sec = MB_TIMEVAL_SEC(&tmo);
00323 tv.tv_usec = MB_TIMEVAL_USEC(&tmo);
00324 r1 = select(nfds, &rfds, NULL, NULL, &tv);
00325 } else
00326 r1 = select(nfds, &rfds, NULL, NULL, NULL);
00327
00328 if(r1 == -1) {
00329 perror("select");
00330 break;
00331 }
00332
00333 if(r1 == 0) {
00334 get_now(&now);
00335 mb_tman_handle_timeout(tman, &now);
00336 rdman_redraw_changed(rdman);
00337 XFlush(display);
00338 } else if(FD_ISSET(fd, &rfds)){
00339 handle_x_event(rt);
00340 }
00341 }
00342 }
00343
00344 #define ERR -1
00345 #define OK 0
00346
00347 static int X_init_connection(const char *display_name,
00348 int w, int h,
00349 Display **displayp,
00350 Visual **visualp,
00351 Window *winp) {
00352 Display *display;
00353 Window root, win;
00354 Visual *visual;
00355 int screen;
00356 XSetWindowAttributes wattr;
00357 int depth;
00358 int x, y;
00359 int r;
00360
00361 display = XOpenDisplay(display_name);
00362 if(display == NULL)
00363 return ERR;
00364
00365 screen = DefaultScreen(display);
00366 root = DefaultRootWindow(display);
00367 visual = DefaultVisual(display, screen);
00368 depth = DefaultDepth(display, screen);
00369 wattr.override_redirect = False;
00370 x = 10;
00371 y = 10;
00372 win = XCreateWindow(display, root,
00373 x, y,
00374 w, h,
00375 1, depth, InputOutput, visual,
00376 CWOverrideRedirect, &wattr);
00377 r = XMapWindow(display, win);
00378 if(r == -1) {
00379 XCloseDisplay(display);
00380 return ERR;
00381 }
00382
00383 XSelectInput(display, win, PointerMotionMask | ExposureMask |
00384 ButtonPressMask | ButtonReleaseMask |
00385 KeyPressMask | KeyReleaseMask);
00386 XFlush(display);
00387
00388 *displayp = display;
00389 *visualp = visual;
00390 *winp = win;
00391
00392 return OK;
00393 }
00394
00395
00396
00397
00398
00399
00400 static int X_MB_init(const char *display_name,
00401 int w, int h, X_MB_runtime_t *xmb_rt) {
00402 memset(xmb_rt, 0, sizeof(X_MB_runtime_t));
00403
00404 xmb_rt->w = w;
00405 xmb_rt->h = h;
00406 X_init_connection(display_name, w, h, &xmb_rt->display,
00407 &xmb_rt->visual, &xmb_rt->win);
00408
00409 xmb_rt->surface =
00410 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
00411
00412 xmb_rt->backend_surface =
00413 cairo_xlib_surface_create(xmb_rt->display,
00414 xmb_rt->win,
00415 xmb_rt->visual,
00416 w, h);
00417
00418 xmb_rt->cr = cairo_create(xmb_rt->surface);
00419 xmb_rt->backend_cr = cairo_create(xmb_rt->backend_surface);
00420
00421 cairo_set_source_surface(xmb_rt->backend_cr, xmb_rt->surface, 0, 0);
00422
00423 xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
00424 redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr);
00425
00426 xmb_rt->tman = mb_tman_new();
00427
00428 xmb_rt->last = NULL;
00429
00430 X_kb_init(&xmb_rt->kbinfo, xmb_rt->display, xmb_rt->rdman);
00431
00432 return OK;
00433 }
00434
00435 static void X_MB_destroy(X_MB_runtime_t *xmb_rt) {
00436 if(xmb_rt->rdman) {
00437 redraw_man_destroy(xmb_rt->rdman);
00438 free(xmb_rt->rdman);
00439 }
00440
00441 if(xmb_rt->tman)
00442 mb_tman_free(xmb_rt->tman);
00443
00444 if(xmb_rt->cr)
00445 cairo_destroy(xmb_rt->cr);
00446 if(xmb_rt->backend_cr)
00447 cairo_destroy(xmb_rt->backend_cr);
00448
00449 if(xmb_rt->surface)
00450 cairo_surface_destroy(xmb_rt->surface);
00451 if(xmb_rt->backend_surface)
00452 cairo_surface_destroy(xmb_rt->backend_surface);
00453
00454 if(xmb_rt->display)
00455 XCloseDisplay(xmb_rt->display);
00456
00457 X_kb_destroy(&xmb_rt->kbinfo);
00458 }
00459
00460 X_MB_runtime_t *X_MB_new(const char *display_name, int w, int h) {
00461 X_MB_runtime_t *rt;
00462 int r;
00463
00464 rt = O_ALLOC(X_MB_runtime_t);
00465 if(rt == NULL)
00466 return NULL;
00467
00468 r = X_MB_init(display_name, w, h, rt);
00469 if(r != OK)
00470 return NULL;
00471
00472 return rt;
00473 }
00474
00475 void X_MB_free(X_MB_runtime_t *rt) {
00476 X_MB_destroy(rt);
00477 free(rt);
00478 }
00479
00480 subject_t *X_MB_kbevents(X_MB_runtime_t *xmb_rt) {
00481 return xmb_rt->kbinfo.kbevents;
00482 }
00483
00484 redraw_man_t *X_MB_rdman(X_MB_runtime_t *xmb_rt) {
00485 return xmb_rt->rdman;
00486 }
00487
00488 mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt) {
00489 return xmb_rt->tman;
00490 }
00491
00492 ob_factory_t *X_MB_ob_factory(X_MB_runtime_t *xmb_rt) {
00493 ob_factory_t *factory;
00494
00495 factory = rdman_get_ob_factory(xmb_rt->rdman);
00496 return factory;
00497 }