2
* FIG : Facility for Interactive Generation of figures
3
* Copyright (c) 1995 Jim Daley (jdaley@cix.compulink.co.uk)
4
* Parts Copyright (c) 1989-2000 by Brian V. Smith
6
* Any party obtaining a copy of these files is granted, free of charge, a
7
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
8
* nonexclusive right and license to deal in this software and
9
* documentation files (the "Software"), including without limitation the
10
* rights to use, copy, modify, merge, publish, distribute, sublicense,
11
* and/or sell copies of the Software, and to permit persons who receive
12
* copies from any such party to do so, with the only requirement being
13
* that this copyright notice remain intact.
18
Screen capture functions - let user draw rectangle on screen
19
and write a pcx file of the contents of that area.
23
#include "resources.h"
25
#include "w_capture.h"
26
#include "w_msgpanel.h"
28
static Boolean getImageData(); /* returns zero on failure */
29
static Boolean selectedRootArea(); /* returns zero on failure */
30
static void drawRect();
31
static int getCurrentColors(); /* returns number of colors in map */
34
static unsigned char *data; /* pointer to captured & converted data */
37
statics which need to be set up before we can call
38
drawRect - drawRect relies on GC being an xor so
39
a second XDrawRectangle will erase the first
41
static Window rectWindow;
45
captureImage(window, filename) /* returns True on success */
49
unsigned char Red[MAX_COLORMAP_SIZE],
50
Green[MAX_COLORMAP_SIZE],
51
Blue[MAX_COLORMAP_SIZE];
61
if (!ok_to_write(filename, "EXPORT") )
64
/* unmap the xfig windows, capture a gif/pcx then remap our windows */
67
XtUnmapWidget(window);
70
/* capture the screen area */
71
status = getImageData(&width, &height, &numcols, Red, Green, Blue);
73
/* make sure server is ungrabbed if we're debugging */
75
/* map our windows again */
79
if ( status == False ) {
80
put_msg("Nothing Captured.");
84
/* encode the image and write to the file */
85
put_msg("Writing binary PCX file...");
89
if ((pcxfile = fopen(filename,"wb"))==0) {
90
file_msg("Cannot open PCX file %s for writing",filename);
91
put_msg("Cannot open PCX file %s for writing",filename);
94
/* write the pcx file */
95
_write_pcx(pcxfile, data, Red, Green, Blue, numcols, width, height);
108
getImageData(w, h, nc, Red, Green, Blue) /* returns False on failure */
110
unsigned char Red[], Green[], Blue[];
112
XColor colors[MAX_COLORMAP_SIZE];
113
int colused[MAX_COLORMAP_SIZE];
114
int mapcols[MAX_COLORMAP_SIZE];
116
int x, y, width, height;
118
static XImage *image;
122
unsigned char *iptr, *dptr;
124
sleep(1); /* in case he'd like to click on something */
125
if ( selectedRootArea( &x, &y, &width, &height, &cw ) == False )
128
image = XGetImage(tool_d, XDefaultRootWindow(tool_d),
129
x, y, width, height, AllPlanes, ZPixmap);
130
if (!image || !image->data) {
131
fprintf(stderr, "Cannot capture %dx%d area - memory problems?\n",
137
/* if we get here we got an image! */
138
*w = width = image->width;
139
*h = height = image->height;
141
numcols = getCurrentColors(XDefaultRootWindow(tool_d), colors);
142
if ( numcols <= 0 ) { /* ought not to get here as capture button
143
should not appear for these displays */
144
fprintf(stderr, "Cannot handle a display without a colormap.\n");
145
XDestroyImage( image );
149
iptr = (unsigned char *) image->data;
150
dptr = data = (unsigned char *) malloc(height*width);
152
fprintf(stderr, "Insufficient memory to convert image.\n");
153
XDestroyImage(image);
157
if (tool_cells > 2) { /* color */
158
/* copy them to the Red, Green and Blue arrays */
159
for (i=0; i<numcols; i++) {
163
/* now map the pixel values to 0..numcolors */
165
for (i=0; i<image->bytes_per_line*height; i++, iptr++) {
166
if (x >= image->bytes_per_line)
169
colused[*iptr] = 1; /* mark this color as used */
175
/* count the number of colors used */
178
for (i=0; i< *nc; i++) {
180
mapcols[i] = numcols;
181
Red[numcols] = colors[i].red >> 8;
182
Green[numcols] = colors[i].green >> 8;
183
Blue[numcols] = colors[i].blue >> 8;
187
/* remap the pixels */
188
for (i=0, dptr = data; i < width*height; i++, dptr++)
190
*dptr = mapcols[*dptr];
193
/* monochrome, copy bits to bytes */
197
for (i=0; i<image->bytes_per_line*height; i++, iptr++) {
198
if (x >= image->bytes_per_line*8)
200
if (image->bitmap_bit_order == LSBFirst) {
201
for (bitp=1; bitp<256; bitp<<=1) {
212
for (bitp=128; bitp>0; bitp>>=1) {
224
for (i=0; i<2; i++) {
225
Red[i] = colors[i].red >> 8;
226
Green[i] = colors[i].green >> 8;
227
Blue[i] = colors[i].blue >> 8;
233
XDestroyImage(image);
239
#define PTR_BUTTON_STATE( wx, wy, msk ) \
240
( XQueryPointer(tool_d, rectWindow, &root_r, &child_r, &root_x, &root_y, \
242
msk & (Button1Mask | Button2Mask | Button3Mask) )
246
let user mark which bit of the window we want, UI follows xfig:
247
button1 marks start point, any other cancels
248
button1 again marks end point - any other cancels
252
selectedRootArea( x_r, y_r, w_r, h_r, cw )
254
unsigned int *w_r, *h_r;
257
int x1, y1; /* start point of user rect */
258
int x, y, width, height; /* current values for rect */
260
Window root_r, child_r; /* parameters for xQueryPointer */
267
unsigned long gcmask;
269
/* set up our local globals for drawRect */
270
rectWindow = XDefaultRootWindow(tool_d);
272
XGrabPointer(tool_d, rectWindow, False, 0L,
273
GrabModeAsync, GrabModeSync, None,
274
crosshair_cursor, CurrentTime);
277
while (PTR_BUTTON_STATE( win_x, win_y, mask ) == 0)
280
/* button 1 pressed, get whole window under pointer */
281
if ( (mask & Button1Mask ) ) {
282
/* after user releases button */
283
while (PTR_BUTTON_STATE( win_x, win_y, mask ) != 0)
285
XUngrabPointer(tool_d, CurrentTime);
288
/* get the geometry right into the return vars */
289
XGetGeometry(tool_d, child_r, &root_r, x_r, y_r, w_r, h_r, &dum, &dum);
290
/* make sure area is on screen */
293
else if (*x_r + *w_r > WidthOfScreen(tool_s))
294
*w_r = WidthOfScreen(tool_s)-*x_r;
297
else if (*y_r + *h_r > HeightOfScreen(tool_s))
298
*h_r = HeightOfScreen(tool_s)-*y_r;
304
/* button 2 pressed, wait for release */
305
if ( !(mask & Button2Mask ) ) {
306
XUngrabPointer(tool_d, CurrentTime);
309
while (PTR_BUTTON_STATE( win_x, win_y, mask ) != 0)
313
/* if we're here we got a button 2 press & release */
314
/* so initialise for tracking box across display */
316
last_x = x1 = x = win_x;
317
last_y = y1 = y = win_y;
321
/* Nobble our GC to let us draw a box over everything */
322
gcv.foreground = x_color(BLACK) ^ x_color(WHITE);
323
gcv.background = x_color(WHITE);
324
gcv.function = GXxor;
325
gcmask = GCFunction | GCForeground | GCBackground;
326
rectGC = XCreateGC(tool_d, XtWindow(canvas_sw), gcmask, &gcv);
327
XSetSubwindowMode(tool_d, rectGC, IncludeInferiors);
329
/* Wait for button press while tracking rectangle on screen */
330
while ( PTR_BUTTON_STATE( win_x, win_y, mask ) == 0 ) {
331
if (win_x != last_x || win_y != last_y) {
332
drawRect(x, y, width, height, False); /* remove any existing rectangle */
336
width = abs(win_x - x1);
337
height = abs(win_y - y1);
342
if ((width > 1) && (height > 1))
343
drawRect(x, y, width, height, True); /* display rectangle */
347
drawRect(x, y, width, height, False); /* remove any remaining rect */
348
XUngrabPointer(tool_d, CurrentTime); /* & let go the pointer */
350
/* put GC back to normal */
351
XSetFunction(tool_d, rectGC, GXcopy);
352
XSetSubwindowMode(tool_d, rectGC, ClipByChildren);
354
if (width == 0 || height == 0 || !(mask & Button2Mask) )
355
return False; /* cancelled or selected nothing */
357
/* we have a rectangle - set up the return parameters */
359
*w_r = width; *h_r = height;
360
if ( child_r == None )
370
draw or erase an on screen rectangle - dependant on value of draw
374
drawRect( x, y, w, h, draw )
375
int x, y, w, h, draw;
377
static int onscreen = False;
379
if ( onscreen != draw )
383
XDrawRectangle( tool_d, rectWindow, rectGC, x, y, w-1, h-1 );
390
in picking up the color map I'm making the assumption that the user
391
has arranged the captured screen to appear as he wishes - ie that
392
whatever colors he wants are displayed - this means that if the
393
chosen window color map is not installed then we need to pick
394
the one that is - rather than the one appropriate to the window
395
The catch is that there may be several installed maps
396
so we do need to check the window - rather than pick up
397
the current installed map.
399
**************** This code based on xwd.c *****************
400
********* Here is the relevant copyright notice: ***********
402
The following copyright and permission notice outlines the
403
rights and restrictions covering most parts of the standard
404
distribution of the X Window System from MIT. Other parts
405
have additional or different copyrights and permissions; see
406
the individual source files.
408
Copyright 1984, 1985, 1986, 1987, 1988, Massachusetts Insti-
411
Permission to use, copy, modify, and distribute this
412
software and its documentation for any purpose and without
413
fee is hereby granted, provided that the above copyright
414
notice appear in all copies and that both that copyright
415
notice and this permission notice appear in supporting docu-
416
mentation, and that the name of M.I.T. not be used in
417
advertising or publicity pertaining to distribution of the
418
software without specific, written prior permission. M.I.T.
419
makes no representations about the suitability of this
420
software for any purpose. It is provided "as is" without
421
express or implied warranty.
423
This software is not subject to any license of the American
424
Telephone and Telegraph Company or of the Regents of the
425
University of California.
429
#define lowbit(x) ((x) & (~(x) + 1))
432
getCurrentColors(w, colors)
436
XWindowAttributes xwa;
440
XGetWindowAttributes(tool_d, w, &xwa);
442
if (xwa.visual->class == TrueColor) {
443
fprintf(stderr,"TrueColor visual No colormap.\n");
447
else if (!xwa.colormap) {
448
XGetWindowAttributes(tool_d, XDefaultRootWindow(tool_d), &xwa);
450
fprintf(stderr,"no Colormap available.\n");
455
ncolors = xwa.visual->map_entries;
457
if (xwa.visual->class == DirectColor) {
458
Pixel red, green, blue, red1, green1, blue1;
461
red = green = blue = 0;
462
red1 = lowbit(xwa.visual->red_mask);
463
green1 = lowbit(xwa.visual->green_mask);
464
blue1 = lowbit(xwa.visual->blue_mask);
465
for (i=0; i<ncolors; i++) {
466
colors[i].pixel = red|green|blue;
469
if (red > xwa.visual->red_mask) red = 0;
471
if (green > xwa.visual->green_mask) green = 0;
473
if (blue > xwa.visual->blue_mask) blue = 0;
477
for (i=0; i<ncolors; i++) {
483
if ( ( xwa.colormap ) && ( xwa.map_installed ) )
491
maps = XListInstalledColormaps(tool_d, XDefaultRootWindow(tool_d), &count);
492
if ( count > 0 ) map = maps[0];
493
else map = tool_cm; /* last resort! */
496
XQueryColors(tool_d, map, colors, ncolors);
503
returns True if we can handle XImages from the visual class
504
The current Image write functions & our image conversion routines
505
require us to produce a colormapped byte per pixel image
510
canHandleCapture( d )
513
XWindowAttributes xwa;
515
XGetWindowAttributes(d, XDefaultRootWindow(d), &xwa);
518
file_msg("Can't capture screen because no colormap found");
520
} else if (8 < xwa.depth) {
521
file_msg("Can't capture screen because its depth (%d) is more than 8bpp",
524
} else if (xwa.visual->class == TrueColor) {
525
file_msg("Can't capture screen because its visual class is TrueColor");
527
} else if (MAX_COLORMAP_SIZE < xwa.visual->map_entries) {
528
file_msg("Can't capture screen because colormap (%d) is larger than %d",
529
xwa.visual->map_entries, MAX_COLORMAP_SIZE);