~ubuntu-branches/ubuntu/trusty/xfig/trusty

« back to all changes in this revision

Viewing changes to w_capture.c

  • Committer: Bazaar Package Importer
  • Author(s): Roland Rosenfeld
  • Date: 2002-03-22 10:39:49 UTC
  • Revision ID: james.westby@ubuntu.com-20020322103949-63082hoxulq6n7u1
Tags: upstream-3.2.3.d-rel
ImportĀ upstreamĀ versionĀ 3.2.3.d-rel

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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
 
5
 *
 
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.
 
14
 *
 
15
 */
 
16
 
 
17
/*
 
18
  Screen capture functions - let user draw rectangle on screen
 
19
  and write a pcx file of the contents of that area.
 
20
*/
 
21
 
 
22
#include "fig.h"
 
23
#include "resources.h"
 
24
#include "object.h"
 
25
#include "w_capture.h"
 
26
#include "w_msgpanel.h"
 
27
 
 
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 */
 
32
 
 
33
 
 
34
static unsigned char *data;             /* pointer to captured & converted data */
 
35
 
 
36
/* 
 
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
 
40
*/
 
41
static Window   rectWindow;
 
42
static GC       rectGC;
 
43
 
 
44
Boolean
 
45
captureImage(window, filename)          /* returns True on success */
 
46
Widget window;
 
47
char *filename;
 
48
{
 
49
    unsigned char       Red[MAX_COLORMAP_SIZE],
 
50
                        Green[MAX_COLORMAP_SIZE],
 
51
                        Blue[MAX_COLORMAP_SIZE];
 
52
    int                 numcols;
 
53
    int                 captured;
 
54
    int                 width, height;
 
55
    Boolean             status;
 
56
 
 
57
    FILE                *pcxfile;
 
58
    char                *dptr;
 
59
    int                 i,j;
 
60
 
 
61
    if (!ok_to_write(filename, "EXPORT") )
 
62
        return(False);
 
63
 
 
64
    /* unmap the xfig windows, capture a gif/pcx then remap our windows */
 
65
 
 
66
    XtUnmapWidget(tool);
 
67
    XtUnmapWidget(window);
 
68
    app_flush();
 
69
 
 
70
    /* capture the screen area */
 
71
    status = getImageData(&width, &height, &numcols, Red, Green, Blue);
 
72
 
 
73
    /* make sure server is ungrabbed if we're debugging */
 
74
    app_flush();
 
75
    /* map our windows again */
 
76
    XtMapWidget(tool);
 
77
    XtMapWidget(window);
 
78
 
 
79
    if ( status == False ) {
 
80
        put_msg("Nothing Captured.");
 
81
        app_flush();
 
82
        captured = False;
 
83
 } else {
 
84
        /* encode the image and write to the file */
 
85
        put_msg("Writing binary PCX file...");
 
86
 
 
87
        app_flush();
 
88
 
 
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);
 
92
            captured = False;
 
93
        } else {
 
94
            /* write the pcx file */
 
95
            _write_pcx(pcxfile, data, Red, Green, Blue, numcols, width, height);
 
96
            fclose(pcxfile);
 
97
            captured = True;
 
98
        }
 
99
 
 
100
        free(data);
 
101
   }
 
102
 
 
103
   return ( captured );
 
104
}
 
105
 
 
106
 
 
107
static Boolean
 
108
getImageData(w, h, nc, Red, Green, Blue) /* returns False on failure */
 
109
  int *w, *h, *nc;
 
110
  unsigned char Red[], Green[], Blue[];
 
111
{
 
112
  XColor colors[MAX_COLORMAP_SIZE];
 
113
  int colused[MAX_COLORMAP_SIZE];
 
114
  int mapcols[MAX_COLORMAP_SIZE];
 
115
 
 
116
  int x, y, width, height;
 
117
  Window cw;
 
118
  static XImage *image;
 
119
 
 
120
  int i;
 
121
  int numcols;
 
122
  unsigned char *iptr, *dptr;
 
123
 
 
124
  sleep(1);   /* in case he'd like to click on something */
 
125
  if ( selectedRootArea( &x, &y, &width, &height, &cw ) == False )
 
126
     return False;
 
127
 
 
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",
 
132
                                                                width,height);
 
133
    return False;
 
134
  }
 
135
 
 
136
 
 
137
  /* if we get here we got an image! */
 
138
  *w = width = image->width;
 
139
  *h = height = image->height;
 
140
 
 
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 );
 
146
    return False;
 
147
  }
 
148
 
 
149
  iptr = (unsigned char *) image->data;
 
150
  dptr = data = (unsigned char *) malloc(height*width);
 
151
  if ( !dptr ) {
 
152
    fprintf(stderr, "Insufficient memory to convert image.\n");
 
153
    XDestroyImage(image);
 
154
    return False;
 
155
  }
 
156
     
 
157
  if (tool_cells  >  2) { /* color */
 
158
        /* copy them to the Red, Green and Blue arrays */
 
159
        for (i=0; i<numcols; i++) {
 
160
            colused[i] = 0;
 
161
        }
 
162
 
 
163
        /* now map the pixel values to 0..numcolors */
 
164
        x = 0;
 
165
        for (i=0; i<image->bytes_per_line*height; i++, iptr++) {
 
166
            if (x >= image->bytes_per_line)
 
167
                x=0;
 
168
            if (x < width) {
 
169
                colused[*iptr] = 1;     /* mark this color as used */
 
170
                *dptr++ = *iptr;
 
171
            }
 
172
            x++;
 
173
        }
 
174
 
 
175
        /* count the number of colors used */
 
176
        *nc = numcols;
 
177
        numcols = 0;
 
178
        for (i=0; i< *nc; i++) {
 
179
            if (colused[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;
 
184
                numcols++;
 
185
            }
 
186
        }
 
187
        /* remap the pixels */
 
188
        for (i=0, dptr = data; i < width*height; i++, dptr++)
 
189
          {
 
190
            *dptr = mapcols[*dptr];
 
191
          }
 
192
 
 
193
  /* monochrome, copy bits to bytes */
 
194
  } else {
 
195
        int     bitp;
 
196
        x = 0;
 
197
        for (i=0; i<image->bytes_per_line*height; i++, iptr++) {
 
198
            if (x >= image->bytes_per_line*8)
 
199
                x=0;
 
200
            if (image->bitmap_bit_order == LSBFirst) {
 
201
                for (bitp=1; bitp<256; bitp<<=1) {
 
202
                    if (x < width) {
 
203
                        if (*iptr & bitp)
 
204
                            *dptr = 1;
 
205
                        else
 
206
                            *dptr = 0;
 
207
                        dptr++;
 
208
                    }
 
209
                    x++;
 
210
                }
 
211
            } else {
 
212
                for (bitp=128; bitp>0; bitp>>=1) {
 
213
                    if (x < width) {
 
214
                        if (*iptr & bitp)
 
215
                            *dptr = 1;
 
216
                        else
 
217
                            *dptr = 0;
 
218
                        dptr++;
 
219
                    }
 
220
                    x++;
 
221
                }
 
222
            }
 
223
        }
 
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;
 
228
        }
 
229
        numcols = 2;
 
230
  }
 
231
  *nc = numcols;
 
232
 
 
233
  XDestroyImage(image);
 
234
  return True;
 
235
}
 
236
 
 
237
 
 
238
 
 
239
#define PTR_BUTTON_STATE( wx, wy, msk ) \
 
240
 ( XQueryPointer(tool_d, rectWindow, &root_r, &child_r, &root_x, &root_y, \
 
241
                                        &wx, &wy, &msk),    \
 
242
     msk & (Button1Mask | Button2Mask | Button3Mask) )
 
243
 
 
244
        
 
245
/*
 
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
 
249
*/
 
250
 
 
251
static Boolean 
 
252
selectedRootArea( x_r, y_r, w_r, h_r, cw )
 
253
    int *x_r, *y_r;
 
254
    unsigned int *w_r, *h_r;
 
255
    Window *cw;
 
256
{
 
257
    int         x1, y1;                 /* start point of user rect */
 
258
    int         x, y, width, height;    /* current values for rect */
 
259
 
 
260
    Window      root_r, child_r;        /* parameters for xQueryPointer */
 
261
    int         root_x, root_y;
 
262
    int         last_x, last_y;
 
263
    int         win_x,  win_y;
 
264
    unsigned    int dum;
 
265
    unsigned    int mask;
 
266
    XGCValues   gcv;
 
267
    unsigned long gcmask;
 
268
 
 
269
    /* set up our local globals for drawRect */ 
 
270
    rectWindow = XDefaultRootWindow(tool_d);
 
271
 
 
272
    XGrabPointer(tool_d, rectWindow, False, 0L,
 
273
                GrabModeAsync, GrabModeSync, None,
 
274
                        crosshair_cursor, CurrentTime);
 
275
 
 
276
 
 
277
    while (PTR_BUTTON_STATE( win_x, win_y, mask ) == 0) 
 
278
        ;
 
279
 
 
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) 
 
284
            ;
 
285
        XUngrabPointer(tool_d, CurrentTime);
 
286
        if (child_r == None)
 
287
            child_r = root_r;
 
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 */
 
291
        if (*x_r < 0)
 
292
            *x_r = 0;
 
293
        else if (*x_r + *w_r > WidthOfScreen(tool_s))
 
294
            *w_r = WidthOfScreen(tool_s)-*x_r;
 
295
        if (*y_r < 0)
 
296
            *y_r = 0;
 
297
        else if (*y_r + *h_r > HeightOfScreen(tool_s))
 
298
            *h_r = HeightOfScreen(tool_s)-*y_r;
 
299
        *cw = child_r;
 
300
        return True;
 
301
    }
 
302
 
 
303
        
 
304
    /* button 2 pressed, wait for release */
 
305
    if ( !(mask & Button2Mask ) ) {
 
306
        XUngrabPointer(tool_d, CurrentTime);
 
307
        return False; 
 
308
    } else {
 
309
        while (PTR_BUTTON_STATE( win_x, win_y, mask ) != 0) 
 
310
            ;
 
311
    }
 
312
 
 
313
    /* if we're here we got a button 2 press  & release */
 
314
    /* so initialise for tracking box across display    */ 
 
315
 
 
316
    last_x = x1 = x = win_x;  
 
317
    last_y = y1 = y = win_y;  
 
318
    width = 0;
 
319
    height = 0;
 
320
 
 
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);
 
328
 
 
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 */
 
333
 
 
334
            x = min2(x1, win_x);
 
335
            y = min2(y1, win_y);
 
336
            width  = abs(win_x - x1);
 
337
            height = abs(win_y - y1);
 
338
 
 
339
            last_x = win_x;
 
340
            last_y = win_y;
 
341
 
 
342
            if ((width > 1) && (height > 1))
 
343
            drawRect(x, y, width, height, True);        /* display rectangle */
 
344
        }
 
345
    }
 
346
 
 
347
    drawRect(x, y, width, height, False);               /*  remove any remaining rect */
 
348
    XUngrabPointer(tool_d, CurrentTime);                /*  & let go the pointer */
 
349
 
 
350
    /* put GC back to normal */
 
351
    XSetFunction(tool_d, rectGC, GXcopy);
 
352
    XSetSubwindowMode(tool_d, rectGC, ClipByChildren);
 
353
 
 
354
    if (width == 0 || height == 0 || !(mask & Button2Mask) )  
 
355
        return False;   /* cancelled or selected nothing */
 
356
 
 
357
    /* we have a rectangle - set up the return parameters */    
 
358
    *x_r = x;     *y_r = y;
 
359
    *w_r = width; *h_r = height;
 
360
    if ( child_r == None )
 
361
        *cw = root_r;
 
362
    else
 
363
        *cw = child_r;
 
364
 
 
365
    return True;
 
366
}
 
367
 
 
368
 
 
369
/*
 
370
  draw or erase an on screen rectangle - dependant on value of draw
 
371
*/
 
372
 
 
373
static void
 
374
drawRect( x, y, w, h, draw )
 
375
  int x, y, w, h, draw;
 
376
{
 
377
static int onscreen = False;
 
378
 
 
379
if ( onscreen != draw )
 
380
  {
 
381
  if ((w>1) && (h >1))
 
382
     {
 
383
     XDrawRectangle( tool_d, rectWindow, rectGC, x, y, w-1, h-1 );
 
384
     onscreen = draw;
 
385
     }
 
386
  }
 
387
}
 
388
 
 
389
/*
 
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.
 
398
 
 
399
  ****************  This code based on xwd.c *****************
 
400
  ********* Here is the relevant copyright notice: ***********
 
401
 
 
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.
 
407
 
 
408
  Copyright 1984, 1985, 1986, 1987, 1988, Massachusetts Insti-
 
409
  tute of Technology.
 
410
 
 
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.
 
422
 
 
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.
 
426
 
 
427
*/
 
428
 
 
429
#define lowbit(x) ((x) & (~(x) + 1))
 
430
 
 
431
static int
 
432
getCurrentColors(w, colors)
 
433
     Window w;
 
434
     XColor colors[];
 
435
{
 
436
  XWindowAttributes xwa;
 
437
  int i, ncolors;
 
438
  Colormap map;
 
439
 
 
440
  XGetWindowAttributes(tool_d, w, &xwa);
 
441
 
 
442
  if (xwa.visual->class == TrueColor) {
 
443
    fprintf(stderr,"TrueColor visual No colormap.\n");
 
444
    return 0;
 
445
  }
 
446
 
 
447
  else if (!xwa.colormap) {
 
448
    XGetWindowAttributes(tool_d, XDefaultRootWindow(tool_d), &xwa);
 
449
    if (!xwa.colormap) {
 
450
       fprintf(stderr,"no Colormap available.\n");
 
451
       return 0;
 
452
    }
 
453
  }
 
454
 
 
455
  ncolors = xwa.visual->map_entries;
 
456
 
 
457
  if (xwa.visual->class == DirectColor) {
 
458
    Pixel red, green, blue, red1, green1, blue1;
 
459
 
 
460
 
 
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;
 
467
      colors[i].pad = 0;
 
468
      red += red1;
 
469
      if (red > xwa.visual->red_mask)     red = 0;
 
470
      green += green1;
 
471
      if (green > xwa.visual->green_mask) green = 0;
 
472
      blue += blue1;
 
473
      if (blue > xwa.visual->blue_mask)   blue = 0;
 
474
    }
 
475
  }
 
476
  else {
 
477
    for (i=0; i<ncolors; i++) {
 
478
      colors[i].pixel = i;
 
479
      colors[i].pad = 0;
 
480
    }
 
481
  }
 
482
 
 
483
  if ( ( xwa.colormap ) && ( xwa.map_installed ) )
 
484
     map = xwa.colormap;
 
485
 
 
486
  else
 
487
     {
 
488
     Colormap *maps;
 
489
     int count;
 
490
 
 
491
     maps = XListInstalledColormaps(tool_d, XDefaultRootWindow(tool_d), &count);
 
492
     if ( count > 0 )   map = maps[0];
 
493
     else               map = tool_cm;  /* last resort! */
 
494
     XFree( maps );
 
495
     }
 
496
  XQueryColors(tool_d, map, colors, ncolors);
 
497
 
 
498
  return(ncolors);
 
499
}
 
500
 
 
501
 
 
502
/* 
 
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 
 
506
  pointed to by data
 
507
*/
 
508
 
 
509
Boolean
 
510
canHandleCapture( d )
 
511
  Display *d;
 
512
{
 
513
    XWindowAttributes xwa;
 
514
 
 
515
    XGetWindowAttributes(d, XDefaultRootWindow(d), &xwa);
 
516
 
 
517
    if (!xwa.colormap) {
 
518
      file_msg("Can't capture screen because no colormap found");
 
519
      return False;
 
520
    } else if (8 < xwa.depth) {
 
521
      file_msg("Can't capture screen because its depth (%d) is more than 8bpp",
 
522
               xwa.depth);
 
523
      return False;
 
524
    } else if (xwa.visual->class == TrueColor) {
 
525
      file_msg("Can't capture screen because its visual class is TrueColor");
 
526
      return False;
 
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);
 
530
      return False;
 
531
    } else {
 
532
      return True;
 
533
    }
 
534
}