~ubuntu-branches/ubuntu/lucid/graphviz-cairo/lucid

« back to all changes in this revision

Viewing changes to plugin/xlib/gvdevice_xlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2006-07-14 10:33:41 UTC
  • Revision ID: james.westby@ubuntu.com-20060714103341-01voli7xkxzmi320
Tags: upstream-2.8
ImportĀ upstreamĀ versionĀ 2.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: */
 
3
 
 
4
/**********************************************************
 
5
*      This software is part of the graphviz package      *
 
6
*                http://www.graphviz.org/                 *
 
7
*                                                         *
 
8
*            Copyright (c) 1994-2004 AT&T Corp.           *
 
9
*                and is licensed under the                *
 
10
*            Common Public License, Version 1.0           *
 
11
*                      by AT&T Corp.                      *
 
12
*                                                         *
 
13
*        Information and Software Systems Research        *
 
14
*              AT&T Research, Florham Park NJ             *
 
15
**********************************************************/
 
16
 
 
17
#ifdef HAVE_CONFIG_H
 
18
#include "config.h"
 
19
#endif
 
20
 
 
21
#include <stdio.h>
 
22
#ifdef HAVE_STDLIB_H
 
23
#include <stdlib.h>
 
24
#endif
 
25
#ifdef HAVE_STRING_H
 
26
#include <string.h>
 
27
#endif
 
28
 
 
29
#include <cairo.h>
 
30
#include <cairo-xlib.h>
 
31
#include <X11/Xutil.h>
 
32
#include <X11/extensions/Xrender.h>
 
33
 
 
34
#include "gvplugin_device.h"
 
35
 
 
36
typedef struct window_xlib_s {
 
37
    Window win;
 
38
    unsigned long event_mask;
 
39
    Pixmap pix;
 
40
    GC gc;
 
41
    Visual *visual;
 
42
    Colormap cmap;
 
43
    int depth;
 
44
    Atom wm_delete_window_atom;
 
45
} window_xlib_t;
 
46
 
 
47
static void handle_configure_notify_xlib(GVJ_t * job, XConfigureEvent * cev)
 
48
{
 
49
    if (job->fit_mode)
 
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)
 
53
        job->has_grown = 1;
 
54
    job->width = cev->width;
 
55
    job->height = cev->height;
 
56
    job->needs_refresh = 1;
 
57
}
 
58
 
 
59
static void handle_expose_xlib(GVJ_t * job, XExposeEvent * eev)
 
60
{
 
61
    window_xlib_t *window;
 
62
 
 
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);
 
66
}
 
67
 
 
68
static void handle_client_message_xlib(GVJ_t * job, XClientMessageEvent * cmev)
 
69
{
 
70
    window_xlib_t *window;
 
71
 
 
72
    window = (window_xlib_t *)job->window;
 
73
    if (cmev->format == 32
 
74
        && (Atom) cmev->data.l[0] == window->wm_delete_window_atom)
 
75
        exit(0);
 
76
}
 
77
 
 
78
static bool handle_keypress_xlib(GVJ_t *job, XKeyEvent *kev)
 
79
{
 
80
    
 
81
    int i;
 
82
    KeyCode *keycodes;
 
83
 
 
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);
 
88
    }
 
89
    return FALSE;
 
90
}
 
91
 
 
92
static Visual *find_argb_visual(Display * dpy, int scr)
 
93
{
 
94
    XVisualInfo *xvi;
 
95
    XVisualInfo template;
 
96
    int nvi;
 
97
    int i;
 
98
    XRenderPictFormat *format;
 
99
    Visual *visual;
 
100
 
 
101
    template.screen = scr;
 
102
    template.depth = 32;
 
103
    template.class = TrueColor;
 
104
    xvi = XGetVisualInfo(dpy,
 
105
                         VisualScreenMask |
 
106
                         VisualDepthMask |
 
107
                         VisualClassMask, &template, &nvi);
 
108
    if (!xvi)
 
109
        return 0;
 
110
    visual = 0;
 
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;
 
115
            break;
 
116
        }
 
117
    }
 
118
 
 
119
    XFree(xvi);
 
120
    return visual;
 
121
}
 
122
 
 
123
static void xlibgen_init_window(GVJ_t *job, Display *dpy, int scr)
 
124
{
 
125
    int argb = 0;
 
126
    const char *geometry = NULL;
 
127
    const char *base = "";
 
128
    XGCValues gcv;
 
129
    XSetWindowAttributes attributes;
 
130
    XWMHints *wmhints;
 
131
    XSizeHints *normalhints;
 
132
    XClassHint *classhint;
 
133
    unsigned long attributemask = 0;
 
134
    char *name;
 
135
    window_xlib_t *window;
 
136
 
 
137
    window = (window_xlib_t *)malloc(sizeof(window_xlib_t));
 
138
    if (window == NULL) {
 
139
        fprintf(stderr, "Failed to malloc window_xlib_t\n");
 
140
        return;
 
141
    }
 
142
    job->window = (void *)window;
 
143
    job->fit_mode = 0;
 
144
    job->needs_refresh = 1;
 
145
 
 
146
    job->dpi.x = DisplayWidth(dpy, scr) * 25.4 / DisplayWidthMM(dpy, scr);
 
147
    job->dpi.y = DisplayHeight(dpy, scr) * 25.4 / DisplayHeightMM(dpy, scr);
 
148
 
 
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;
 
152
 
 
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);
 
162
        window->depth = 32;
 
163
    } else {
 
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);
 
170
    }
 
171
 
 
172
    if (geometry) {
 
173
        int x, y;
 
174
        XParseGeometry(geometry, &x, &y, &job->width, &job->height);
 
175
    }
 
176
 
 
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);
 
181
 
 
182
    name = malloc(strlen("graphviz: ") + strlen(base) + 1);
 
183
    strcpy(name, "graphviz: ");
 
184
    strcat(name, base);
 
185
 
 
186
    normalhints = XAllocSizeHints();
 
187
    normalhints->flags = 0;
 
188
    normalhints->x = 0;
 
189
    normalhints->y = 0;
 
190
    normalhints->width = job->width;
 
191
    normalhints->height = job->height;
 
192
 
 
193
    classhint = XAllocClassHint();
 
194
    classhint->res_name = "graphviz";
 
195
    classhint->res_class = "Graphviz";
 
196
 
 
197
    wmhints = XAllocWMHints();
 
198
    wmhints->flags = InputHint;
 
199
    wmhints->input = True;
 
200
 
 
201
    Xutf8SetWMProperties(dpy, window->win, name, base, 0, 0,
 
202
                         normalhints, wmhints, classhint);
 
203
    XFree(wmhints);
 
204
    XFree(classhint);
 
205
    XFree(normalhints);
 
206
    free(name);
 
207
 
 
208
    window->pix = XCreatePixmap(dpy, window->win, job->width, job->height,
 
209
                window->depth);
 
210
    if (argb)
 
211
        gcv.foreground = 0;
 
212
    else
 
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);
 
216
 
 
217
    window->event_mask = (
 
218
          ButtonPressMask
 
219
        | ButtonReleaseMask
 
220
        | PointerMotionMask
 
221
        | KeyPressMask
 
222
        | StructureNotifyMask
 
223
        | ExposureMask);
 
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);
 
229
}
 
230
 
 
231
static void xlibgen_finalize(GVJ_t *firstjob)
 
232
{
 
233
    GVJ_t *job;
 
234
    Display *dpy;
 
235
    int scr;
 
236
    window_xlib_t *window;
 
237
    Pixmap pix;
 
238
    XEvent xev;
 
239
    cairo_surface_t *surface;
 
240
    bool done = FALSE;
 
241
    const char *display_name = NULL;
 
242
    int i;
 
243
    KeySym keysym;
 
244
    KeyCode *keycodes;
 
245
    pointf pointer;
 
246
 
 
247
    dpy = XOpenDisplay(display_name);
 
248
    if (dpy == NULL) {
 
249
        fprintf(stderr, "Failed to open XLIB display: %s\n",
 
250
                XDisplayName(NULL));
 
251
        return;
 
252
    }
 
253
    scr = DefaultScreen(dpy);
 
254
 
 
255
    keycodes = (KeyCode *)malloc(firstjob->numkeys * sizeof(KeyCode));
 
256
    if (keycodes == NULL) {
 
257
        fprintf(stderr, "Failed to malloc %d*KeyCode\n", firstjob->numkeys);
 
258
        return;
 
259
    }
 
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);
 
264
        else
 
265
            keycodes[i] = XKeysymToKeycode(dpy, keysym);
 
266
    }
 
267
    firstjob->keycodes = (void*)keycodes;
 
268
 
 
269
    for (job = firstjob; job; job = job->next_active)
 
270
        xlibgen_init_window(job, dpy, scr);
 
271
 
 
272
    while (1) {
 
273
        if (!XPending(dpy)) {
 
274
            for (job = firstjob; job; job = job->next_active) {
 
275
                window = (window_xlib_t *)job->window;
 
276
 
 
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);
 
285
                    window->pix = pix;
 
286
                    job->has_grown = 0;
 
287
                    job->needs_refresh = 1;
 
288
                }
 
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;
 
301
                }
 
302
            }
 
303
        }
 
304
    
 
305
        XNextEvent(dpy, &xev);
 
306
 
 
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) {
 
311
                case ButtonPress:
 
312
                    pointer.x = (double)xev.xbutton.x;
 
313
                    pointer.y = (double)xev.xbutton.y;
 
314
                    (job->callbacks->button_press)(job, xev.xbutton.button, pointer);
 
315
                    break;
 
316
                case MotionNotify:
 
317
                    pointer.x = (double)xev.xbutton.x;
 
318
                    pointer.y = (double)xev.xbutton.y;
 
319
                    (job->callbacks->motion)(job, pointer);
 
320
                    break;
 
321
                case ButtonRelease:
 
322
                    pointer.x = (double)xev.xbutton.x;
 
323
                    pointer.y = (double)xev.xbutton.y;
 
324
                    (job->callbacks->button_release)(job, xev.xbutton.button, pointer);
 
325
                    break;
 
326
                case KeyPress:
 
327
                    done = handle_keypress_xlib(job, &xev.xkey);
 
328
                    break;
 
329
                case ConfigureNotify:
 
330
                    handle_configure_notify_xlib(job, &xev.xconfigure);
 
331
                    break;
 
332
                case Expose:
 
333
                    handle_expose_xlib(job, &xev.xexpose);
 
334
                    break;
 
335
                case ClientMessage:
 
336
                    handle_client_message_xlib(job, &xev.xclient);
 
337
                    break;
 
338
                }
 
339
                break;
 
340
            }
 
341
        }
 
342
        if (done)
 
343
            break;
 
344
    }
 
345
    XCloseDisplay(dpy);
 
346
    free(keycodes);
 
347
    firstjob->keycodes = NULL;
 
348
}
 
349
 
 
350
gvdevice_engine_t xlibgen_device_engine = {
 
351
    xlibgen_finalize,
 
352
};
 
353
 
 
354
gvplugin_installed_t gvdevice_xlibgen_types[] = {
 
355
    {0, "xlib", 0, &xlibgen_device_engine, NULL},
 
356
    {0, NULL, 0, NULL, NULL}
 
357
};