1
/* $Id: gvdevice_xlib.c,v 1.14 2006/01/30 15:43:05 ellson Exp $ $Revision: 1.14 $ */
2
/* vim:set shiftwidth=4 ts=8: */
4
/**********************************************************
5
* This software is part of the graphviz package *
6
* http://www.graphviz.org/ *
8
* Copyright (c) 1994-2004 AT&T Corp. *
9
* and is licensed under the *
10
* Common Public License, Version 1.0 *
13
* Information and Software Systems Research *
14
* AT&T Research, Florham Park NJ *
15
**********************************************************/
30
#include <cairo-xlib.h>
31
#include <X11/Xutil.h>
32
#include <X11/extensions/Xrender.h>
34
#include "gvplugin_device.h"
36
typedef struct window_xlib_s {
38
unsigned long event_mask;
44
Atom wm_delete_window_atom;
47
static void handle_configure_notify_xlib(GVJ_t * job, XConfigureEvent * cev)
50
job->zoom = MIN((double) cev->width / (double) job->width,
51
(double) cev->height / (double) job->height);
52
if (cev->width > job->width || cev->height > job->height)
54
job->width = cev->width;
55
job->height = cev->height;
56
job->needs_refresh = 1;
59
static void handle_expose_xlib(GVJ_t * job, XExposeEvent * eev)
61
window_xlib_t *window;
63
window = (window_xlib_t *)job->window;
64
XCopyArea(eev->display, window->pix, eev->window, window->gc,
65
eev->x, eev->y, eev->width, eev->height, eev->x, eev->y);
68
static void handle_client_message_xlib(GVJ_t * job, XClientMessageEvent * cmev)
70
window_xlib_t *window;
72
window = (window_xlib_t *)job->window;
73
if (cmev->format == 32
74
&& (Atom) cmev->data.l[0] == window->wm_delete_window_atom)
78
static bool handle_keypress_xlib(GVJ_t *job, XKeyEvent *kev)
84
keycodes = (KeyCode *)job->keycodes;
85
for (i=0; i < job->numkeys; i++) {
86
if (kev->keycode == keycodes[i])
87
return (job->keybindings[i].callback)(job);
92
static Visual *find_argb_visual(Display * dpy, int scr)
98
XRenderPictFormat *format;
101
template.screen = scr;
103
template.class = TrueColor;
104
xvi = XGetVisualInfo(dpy,
107
VisualClassMask, &template, &nvi);
111
for (i = 0; i < nvi; i++) {
112
format = XRenderFindVisualFormat(dpy, xvi[i].visual);
113
if (format->type == PictTypeDirect && format->direct.alphaMask) {
114
visual = xvi[i].visual;
123
static void xlibgen_init_window(GVJ_t *job, Display *dpy, int scr)
126
const char *geometry = NULL;
127
const char *base = "";
129
XSetWindowAttributes attributes;
131
XSizeHints *normalhints;
132
XClassHint *classhint;
133
unsigned long attributemask = 0;
135
window_xlib_t *window;
137
window = (window_xlib_t *)malloc(sizeof(window_xlib_t));
138
if (window == NULL) {
139
fprintf(stderr, "Failed to malloc window_xlib_t\n");
142
job->window = (void *)window;
144
job->needs_refresh = 1;
146
job->dpi.x = DisplayWidth(dpy, scr) * 25.4 / DisplayWidthMM(dpy, scr);
147
job->dpi.y = DisplayHeight(dpy, scr) * 25.4 / DisplayHeightMM(dpy, scr);
149
/* adjust width/height for real dpi */
150
job->width *= job->dpi.x / POINTS_PER_INCH;
151
job->height *= job->dpi.y / POINTS_PER_INCH;
153
if (argb && (window->visual = find_argb_visual(dpy, scr))) {
154
window->cmap = XCreateColormap(dpy, RootWindow(dpy, scr),
155
window->visual, AllocNone);
156
attributes.override_redirect = False;
157
attributes.background_pixel = 0;
158
attributes.border_pixel = 0;
159
attributes.colormap = window->cmap;
160
attributemask = (CWBackPixel |
161
CWBorderPixel | CWOverrideRedirect | CWColormap);
164
window->cmap = DefaultColormap(dpy, scr);
165
window->visual = DefaultVisual(dpy, scr);
166
attributes.background_pixel = WhitePixel(dpy, scr);
167
attributes.border_pixel = BlackPixel(dpy, scr);
168
attributemask = (CWBackPixel | CWBorderPixel);
169
window->depth = DefaultDepth(dpy, scr);
174
XParseGeometry(geometry, &x, &y, &job->width, &job->height);
177
window->win = XCreateWindow(dpy, RootWindow(dpy, scr),
178
0, 0, job->width, job->height, 0, window->depth,
179
InputOutput, window->visual,
180
attributemask, &attributes);
182
name = malloc(strlen("graphviz: ") + strlen(base) + 1);
183
strcpy(name, "graphviz: ");
186
normalhints = XAllocSizeHints();
187
normalhints->flags = 0;
190
normalhints->width = job->width;
191
normalhints->height = job->height;
193
classhint = XAllocClassHint();
194
classhint->res_name = "graphviz";
195
classhint->res_class = "Graphviz";
197
wmhints = XAllocWMHints();
198
wmhints->flags = InputHint;
199
wmhints->input = True;
201
Xutf8SetWMProperties(dpy, window->win, name, base, 0, 0,
202
normalhints, wmhints, classhint);
208
window->pix = XCreatePixmap(dpy, window->win, job->width, job->height,
213
gcv.foreground = WhitePixel(dpy, scr);
214
window->gc = XCreateGC(dpy, window->pix, GCForeground, &gcv);
215
XFillRectangle(dpy, window->pix, window->gc, 0, 0, job->width, job->height);
217
window->event_mask = (
222
| StructureNotifyMask
224
XSelectInput(dpy, window->win, window->event_mask);
225
window->wm_delete_window_atom =
226
XInternAtom(dpy, "WM_DELETE_WINDOW", False);
227
XSetWMProtocols(dpy, window->win, &window->wm_delete_window_atom, 1);
228
XMapWindow(dpy, window->win);
231
static void xlibgen_finalize(GVJ_t *firstjob)
236
window_xlib_t *window;
239
cairo_surface_t *surface;
241
const char *display_name = NULL;
247
dpy = XOpenDisplay(display_name);
249
fprintf(stderr, "Failed to open XLIB display: %s\n",
253
scr = DefaultScreen(dpy);
255
keycodes = (KeyCode *)malloc(firstjob->numkeys * sizeof(KeyCode));
256
if (keycodes == NULL) {
257
fprintf(stderr, "Failed to malloc %d*KeyCode\n", firstjob->numkeys);
260
for (i = 0; i < firstjob->numkeys; i++) {
261
keysym = XStringToKeysym(firstjob->keybindings[i].keystring);
262
if (keysym == NoSymbol)
263
fprintf(stderr, "ERROR: No keysym for \"%s\"\n", firstjob->keybindings[i].keystring);
265
keycodes[i] = XKeysymToKeycode(dpy, keysym);
267
firstjob->keycodes = (void*)keycodes;
269
for (job = firstjob; job; job = job->next_active)
270
xlibgen_init_window(job, dpy, scr);
273
if (!XPending(dpy)) {
274
for (job = firstjob; job; job = job->next_active) {
275
window = (window_xlib_t *)job->window;
277
if (job->has_grown) {
278
pix = XCreatePixmap(dpy, window->win,
279
job->width, job->height, window->depth);
280
XFillRectangle(dpy, pix, window->gc, 0, 0,
281
job->width, job->height);
282
XCopyArea(dpy, window->pix, pix, window->gc, 0, 0,
283
job->width, job->height, 0, 0);
284
XFreePixmap(dpy, window->pix);
287
job->needs_refresh = 1;
289
if (job->needs_refresh) {
290
XFillRectangle(dpy, window->pix, window->gc, 0, 0,
291
job->width, job->height);
292
surface = cairo_xlib_surface_create(dpy,
293
window->pix, window->visual,
294
job->width, job->height);
295
job->surface = (void *)cairo_create(surface);
296
cairo_surface_destroy(surface);
297
(job->callbacks->refresh)(job);
298
XCopyArea(dpy, window->pix, window->win, window->gc,
299
0, 0, job->width, job->height, 0, 0);
300
job->needs_refresh = 0;
305
XNextEvent(dpy, &xev);
307
for (job = firstjob; job; job = job->next_active) {
308
window = (window_xlib_t *)job->window;
309
if (xev.xany.window == window->win) {
310
switch (xev.xany.type) {
312
pointer.x = (double)xev.xbutton.x;
313
pointer.y = (double)xev.xbutton.y;
314
(job->callbacks->button_press)(job, xev.xbutton.button, pointer);
317
pointer.x = (double)xev.xbutton.x;
318
pointer.y = (double)xev.xbutton.y;
319
(job->callbacks->motion)(job, pointer);
322
pointer.x = (double)xev.xbutton.x;
323
pointer.y = (double)xev.xbutton.y;
324
(job->callbacks->button_release)(job, xev.xbutton.button, pointer);
327
done = handle_keypress_xlib(job, &xev.xkey);
329
case ConfigureNotify:
330
handle_configure_notify_xlib(job, &xev.xconfigure);
333
handle_expose_xlib(job, &xev.xexpose);
336
handle_client_message_xlib(job, &xev.xclient);
347
firstjob->keycodes = NULL;
350
gvdevice_engine_t xlibgen_device_engine = {
354
gvplugin_installed_t gvdevice_xlibgen_types[] = {
355
{0, "xlib", 0, &xlibgen_device_engine, NULL},
356
{0, NULL, 0, NULL, NULL}