21 #ifdef HAVE_SYS_TIME_H
24 #ifdef HAVE_SYS_IOCTL_H
25 #include <sys/ioctl.h>
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
30 #ifdef HAVE_SYS_SELECT_H
31 #include <sys/select.h>
33 #ifdef HAVE_SYS_INOTIFY_H
34 #include <sys/inotify.h>
48 #ifdef CAIRO_HAS_XLIB_SURFACE
49 #include <cairo-xlib.h>
50 #include <X11/Xutil.h>
51 #include <X11/extensions/Xrender.h>
53 typedef struct window_xlib_s {
61 Atom wm_delete_window_atom;
64 static void handle_configure_notify(
GVJ_t * job, XConfigureEvent * cev)
73 ((
double) cev->width - (
double) job->
width) / (
double) job->
width,
74 ((
double) cev->height - (
double) job->
height) / (
double) job->
height);
75 if (cev->width > job->
width || cev->height > job->
height)
77 job->
width = cev->width;
82 static void handle_expose(
GVJ_t * job, XExposeEvent * eev)
86 window = (window_t *)job->
window;
87 XCopyArea(eev->display, window->pix, eev->window, window->gc,
88 eev->x, eev->y, eev->width, eev->height, eev->x, eev->y);
91 static void handle_client_message(
GVJ_t * job, XClientMessageEvent * cmev)
95 window = (window_t *)job->
window;
96 if (cmev->format == 32
97 && (Atom) cmev->data.l[0] == window->wm_delete_window_atom)
101 static boolean handle_keypress(
GVJ_t *job, XKeyEvent *kev)
107 keycodes = (KeyCode *)job->
keycodes;
109 if (kev->keycode == keycodes[i])
115 static Visual *find_argb_visual(Display * dpy,
int scr)
118 XVisualInfo
template;
121 XRenderPictFormat *format;
124 template.screen = scr;
126 template.class = TrueColor;
127 xvi = XGetVisualInfo(dpy,
130 VisualClassMask, &
template, &nvi);
134 for (i = 0; i < nvi; i++) {
135 format = XRenderFindVisualFormat(dpy, xvi[i].visual);
136 if (format->type == PictTypeDirect && format->direct.alphaMask) {
137 visual = xvi[i].visual;
146 static void browser_show(
GVJ_t *job)
148 #if defined HAVE_SYS_TYPES_H && defined HAVE_UNISTD_H
149 char *exec_argv[3] = {BROWSER,
NULL, NULL};
157 fprintf(stderr,
"fork failed: %s\n", strerror(errno));
160 err = execvp(exec_argv[0], exec_argv);
161 fprintf(stderr,
"error starting %s: %s\n", exec_argv[0], strerror(errno));
168 static int handle_xlib_events (
GVJ_t *firstjob, Display *dpy)
176 while (XPending(dpy)) {
177 XNextEvent(dpy, &xev);
179 for (job = firstjob; job; job = job->
next_active) {
180 window = (window_t *)job->
window;
181 if (xev.xany.window == window->win) {
182 switch (xev.xany.type) {
184 pointer.
x = (double)xev.xbutton.x;
185 pointer.
y = (
double)xev.xbutton.y;
191 pointer.
x = (double)xev.xbutton.x;
192 pointer.
y = (
double)xev.xbutton.y;
198 pointer.
x = (double)xev.xbutton.x;
199 pointer.
y = (
double)xev.xbutton.y;
206 if (handle_keypress(job, &xev.xkey))
210 case ConfigureNotify:
211 handle_configure_notify(job, &xev.xconfigure);
215 handle_expose(job, &xev.xexpose);
219 handle_client_message(job, &xev.xclient);
230 static void update_display(
GVJ_t *job, Display *dpy)
233 cairo_surface_t *surface;
235 window = (window_t *)job->
window;
238 XFreePixmap(dpy, window->pix);
239 window->pix = XCreatePixmap(dpy, window->win,
245 XFillRectangle(dpy, window->pix, window->gc, 0, 0,
247 surface = cairo_xlib_surface_create(dpy,
248 window->pix, window->visual,
250 job->
context = (
void *)cairo_create(surface);
253 cairo_surface_destroy(surface);
254 XCopyArea(dpy, window->pix, window->win, window->gc,
260 static void init_window(
GVJ_t *job, Display *dpy,
int scr)
263 const char *base =
"";
265 XSetWindowAttributes attributes;
267 XSizeHints *normalhints;
268 XClassHint *classhint;
269 uint64_t attributemask = 0;
275 window = (window_t *)malloc(
sizeof(window_t));
276 if (window ==
NULL) {
277 fprintf(stderr,
"Failed to malloc window_t\n");
284 zoom_to_fit =
MIN((
double) w / (
double) job->
width,
285 (
double) h / (
double) job->
height);
286 if (zoom_to_fit < 1.0)
287 job->
zoom *= zoom_to_fit;
292 job->
window = (
void *)window;
296 if (argb && (window->visual = find_argb_visual(dpy, scr))) {
297 window->cmap = XCreateColormap(dpy, RootWindow(dpy, scr),
298 window->visual, AllocNone);
299 attributes.override_redirect = False;
300 attributes.background_pixel = 0;
301 attributes.border_pixel = 0;
302 attributes.colormap = window->cmap;
303 attributemask = ( CWBackPixel
309 window->cmap = DefaultColormap(dpy, scr);
310 window->visual = DefaultVisual(dpy, scr);
311 attributes.background_pixel = WhitePixel(dpy, scr);
312 attributes.border_pixel = BlackPixel(dpy, scr);
313 attributemask = (CWBackPixel | CWBorderPixel);
314 window->depth = DefaultDepth(dpy, scr);
317 window->win = XCreateWindow(dpy, RootWindow(dpy, scr),
319 InputOutput, window->visual,
320 attributemask, &attributes);
322 name = malloc(strlen(
"graphviz: ") + strlen(base) + 1);
323 strcpy(name,
"graphviz: ");
326 normalhints = XAllocSizeHints();
327 normalhints->flags = 0;
330 normalhints->width = job->
width;
331 normalhints->height = job->
height;
333 classhint = XAllocClassHint();
334 classhint->res_name =
"graphviz";
335 classhint->res_class =
"Graphviz";
337 wmhints = XAllocWMHints();
338 wmhints->flags = InputHint;
339 wmhints->input = True;
341 Xutf8SetWMProperties(dpy, window->win, name, base, 0, 0,
342 normalhints, wmhints, classhint);
348 window->pix = XCreatePixmap(dpy, window->win, job->
width, job->
height,
353 gcv.foreground = WhitePixel(dpy, scr);
354 window->gc = XCreateGC(dpy, window->pix, GCForeground, &gcv);
355 update_display(job, dpy);
357 window->event_mask = (
362 | StructureNotifyMask
364 XSelectInput(dpy, window->win, window->event_mask);
365 window->wm_delete_window_atom =
366 XInternAtom(dpy,
"WM_DELETE_WINDOW", False);
367 XSetWMProtocols(dpy, window->win, &window->wm_delete_window_atom, 1);
368 XMapWindow(dpy, window->win);
371 static int handle_stdin_events(
GVJ_t *job,
int stdin_fd)
383 #ifdef HAVE_SYS_INOTIFY_H
384 static int handle_file_events(
GVJ_t *job,
int inotify_fd)
386 int avail, ret, len, ln, rc = 0;
389 struct inotify_event *event;
391 ret = ioctl(inotify_fd, FIONREAD, &avail);
393 fprintf(stderr,
"ioctl() failed\n");
398 buf = realloc(buf, avail);
400 fprintf(stderr,
"problem with realloc(%d)\n", avail);
403 len =
read(inotify_fd, buf, avail);
405 fprintf(stderr,
"avail = %u, len = %u\n", avail, len);
410 event = (
struct inotify_event *)bf;
411 switch (event->mask) {
418 if (strcmp((
char*)(&(event->name)), p) == 0) {
427 case IN_CLOSE_NOWRITE:
442 ln = event->len +
sizeof(
struct inotify_event);
447 fprintf(stderr,
"length miscalculation, len = %d\n", len);
455 static void xlib_initialize(
GVJ_t *firstjob)
460 const char *display_name =
NULL;
463 dpy = XOpenDisplay(display_name);
465 fprintf(stderr,
"Failed to open XLIB display: %s\n",
469 scr = DefaultScreen(dpy);
471 firstjob->
display = (
void*)dpy;
474 keycodes = (KeyCode *)malloc(firstjob->
numkeys *
sizeof(KeyCode));
475 if (keycodes ==
NULL) {
476 fprintf(stderr,
"Failed to malloc %d*KeyCode\n", firstjob->
numkeys);
479 for (i = 0; i < firstjob->
numkeys; i++) {
481 if (keysym == NoSymbol)
482 fprintf(stderr,
"ERROR: No keysym for \"%s\"\n",
485 keycodes[i] = XKeysymToKeycode(dpy, keysym);
487 firstjob->
keycodes = (
void*)keycodes;
489 firstjob->
device_dpi.
x = DisplayWidth(dpy, scr) * 25.4 / DisplayWidthMM(dpy, scr);
490 firstjob->
device_dpi.
y = DisplayHeight(dpy, scr) * 25.4 / DisplayHeightMM(dpy, scr);
494 static void xlib_finalize(
GVJ_t *firstjob)
497 Display *dpy = (Display *)(firstjob->
display);
498 int scr = firstjob->
screen;
499 KeyCode *keycodes= firstjob->
keycodes;
500 int numfds, stdin_fd=0, xlib_fd, ret, events;
502 boolean watching_stdin_p =
FALSE;
503 #ifdef HAVE_SYS_INOTIFY_H
506 boolean watching_file_p =
FALSE;
508 char *p, *cwd =
NULL;
510 inotify_fd = inotify_init();
511 if (inotify_fd < 0) {
512 fprintf(stderr,
"inotify_init() failed\n");
517 numfds = xlib_fd = XConnectionNumber(dpy);
521 #ifdef HAVE_SYS_INOTIFY_H
522 watching_file_p =
TRUE;
525 cwd = getcwd(
NULL, 0);
526 dir = realloc(dir, strlen(cwd) + 1 + strlen(firstjob->
input_filename) + 1);
536 p = strrchr(dir,
'/');
539 wd = inotify_add_watch(inotify_fd, dir, IN_MODIFY );
541 numfds =
MAX(inotify_fd, numfds);
546 watching_stdin_p =
TRUE;
547 stdin_fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
548 numfds =
MAX(stdin_fd, numfds);
552 init_window(job, dpy, scr);
559 #ifdef HAVE_SYS_INOTIFY_H
560 if (watching_file_p) {
561 if (FD_ISSET(inotify_fd, &rfds)) {
562 ret = handle_file_events(firstjob, inotify_fd);
567 FD_SET(inotify_fd, &rfds);
571 if (watching_stdin_p) {
572 if (FD_ISSET(stdin_fd, &rfds)) {
573 ret = handle_stdin_events(firstjob, stdin_fd);
575 watching_stdin_p =
FALSE;
576 FD_CLR(stdin_fd, &rfds);
580 if (watching_stdin_p)
581 FD_SET(stdin_fd, &rfds);
584 ret = handle_xlib_events(firstjob, dpy);
588 FD_SET(xlib_fd, &rfds);
592 update_display(job, dpy);
598 fprintf(stderr,
"select() failed\n");
603 #ifdef HAVE_SYS_INOTIFY_H
605 ret = inotify_rm_watch(inotify_fd, wd);
629 #ifdef CAIRO_HAS_XLIB_SURFACE
630 {0,
"xlib:cairo", 0, &device_engine_xlib, &device_features_xlib},
631 {0,
"x11:cairo", 0, &device_engine_xlib, &device_features_xlib},
void(* button_press)(GVJ_t *job, int button, pointf pointer)
void(* refresh)(GVJ_t *job)
void(* button_release)(GVJ_t *job, int button, pointf pointer)
if(aagss+aagstacksize-1<=aagssp)
gvevent_key_binding_t * keybindings
void(* read)(GVJ_t *job, const char *filename, const char *layout)
gvevent_key_callback_t callback
void(* motion)(GVJ_t *job, pointf pointer)
gvplugin_installed_t gvdevice_types_xlib[]
gvdevice_callbacks_t * callbacks
#define GVDEVICE_DOES_TRUECOLOR