1 /*
2 * imgWindow.c --
3 *
4 * A photo image file handler to put the content of a window in a photo.
5 *
6 */
7
8 /* Author : Jan Nijtmans */
9 /* Date : 11/16/97 */
10
11 #include "tkPort.h"
12 #include "Lang.h"
13
14 #include <string.h>
15 #include <ctype.h>
16 #include <stdlib.h>
17
18 #include "imgInt.h"
19 #include "X11/Xutil.h"
20 #ifndef __WIN32__
21 # include "X11/Xproto.h"
22 #else
23 # include <windows.h>
24 # include "X11/Xlib.h"
25 # include "tkInt.h"
26 # include "tkWinInt.h"
27 # include "X11/Xfuncproto.h"
28 # undef X_GetImage
29 #endif
30
31 /*
32 * The format record for the Win data format:
33 */
34
35 static int ChanMatchWin _ANSI_ARGS_((Tcl_Channel chan, Tcl_Obj *filename,
36 Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp));
37 static int ObjMatchWin _ANSI_ARGS_((Tcl_Obj *dataObj,
38 Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp));
39 static int ObjReadWin _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj,
40 Tcl_Obj *format, Tk_PhotoHandle imageHandle,
41 int destX, int destY, int width, int height, int srcX, int srcY));
42 #ifdef X_GetImage
43 static int xerrorhandler _ANSI_ARGS_((ClientData clientData,
44 XErrorEvent *e));
45 #endif
46
47 Tk_PhotoImageFormat imgFmtWin = {
48 "window", /* name */
49 ChanMatchWin, /* fileMatchProc */
50 ObjMatchWin, /* stringMatchProc */
51 (Tk_ImageFileReadProc *) NULL, /* fileReadProc */
52 ObjReadWin, /* stringReadProc */
53 (Tk_ImageFileWriteProc *) NULL, /* fileWriteProc */
54 (Tk_ImageStringWriteProc *) NULL, /* stringWriteProc */
55 };
56
57 typedef struct ColormapData { /* Hold color information for a window */
58 int separated; /* Whether to use separate color bands */
59 int color; /* Whether window is color or black/white */
60 int ncolors; /* Number of color values stored */
61 XColor *colors; /* Pixel value -> RGB mappings */
62 int red_mask, green_mask, blue_mask; /* Masks and shifts for each */
63 int red_shift, green_shift, blue_shift; /* color band */
64 } ColormapData;
65
66 /*
67 * Prototypes for local procedures defined in this file:
68 */
69
70 #define UCHAR(c) ((unsigned char) (c))
71 /*
72 *--------------------------------------------------------------
73 *
74 * xerrorhandler --
75 *
76 * This is a dummy function to catch X11 errors during an
77 * attempt to convert a window to a photo image.
78 *
79 * Results:
80 * None.
81 *
82 * Side effects:
83 * None.
84 *
85 *--------------------------------------------------------------
86 */
87
88 #ifdef X_GetImage
89 static int
xerrorhandler(clientData,e)90 xerrorhandler(clientData, e)
91 ClientData clientData;
92 XErrorEvent *e;
93 {
94 return 0;
95 }
96 #endif
97
98 /*
99 *----------------------------------------------------------------------
100 *
101 * ChanMatchWin --
102 *
103 * This procedure is invoked by the photo image type to see if
104 * a file contains image data in WINDOW format.
105 *
106 * Results:
107 * The return value is always 0, because a window cannot be
108 * read from a file.
109 *
110 * Side effects:
111 * None.
112 *
113 *----------------------------------------------------------------------
114 */
115
ChanMatchWin(chan,filename,format,widthPtr,heightPtr,interp)116 static int ChanMatchWin(chan, filename, format, widthPtr, heightPtr, interp)
117 Tcl_Channel chan;
118 Tcl_Obj *filename;
119 Tcl_Obj *format;
120 int *widthPtr, *heightPtr;
121 Tcl_Interp *interp;
122 {
123 return 0;
124 }
125
126 /*
127 *----------------------------------------------------------------------
128 *
129 * ObjMatchWin --
130 *
131 * This procedure is invoked by the photo image type to see if
132 * an object contains image data which can be read from a window.
133 *
134 * Results:
135 * The return value is 1 if data contains a valid window name.
136 *
137 * Side effects:
138 * the size of the image is placed in widthPtr and heightPtr.
139 *
140 *----------------------------------------------------------------------
141 */
142
ObjMatchWin(data,format,widthPtr,heightPtr,interp)143 static int ObjMatchWin(data, format, widthPtr, heightPtr, interp)
144 Tcl_Obj *data;
145 Tcl_Obj *format;
146 int *widthPtr, *heightPtr;
147 Tcl_Interp *interp;
148 {
149 Tk_Window tkwin;
150 char *name;
151
152 ImgFixObjMatchProc(&interp, &data, &format, &widthPtr, &heightPtr);
153
154 name = ImgGetStringFromObj(data, NULL);
155
156 if (interp && name && (name[0] == '.') && ((name[1] == 0) || islower(UCHAR(name[1])))) {
157 tkwin = Tk_MainWindow(interp);
158 if (tkwin == NULL) {
159 return 0;
160 }
161 tkwin = Tk_NameToWindow(interp, name, tkwin);
162 if (tkwin == NULL) {
163 *widthPtr = *heightPtr = 0;
164 return 1;
165 }
166 *widthPtr = Tk_Width(tkwin);
167 *heightPtr = Tk_Height(tkwin);
168 return 1;
169 }
170 return 0;
171 }
172
173 /*
174 *----------------------------------------------------------------------
175 *
176 * ObjReadWin --
177 *
178 * This procedure is called by the photo image type to read
179 * the contents of a window and give it to the photo image.
180 *
181 * Results:
182 * A standard TCL completion code. If TCL_ERROR is returned
183 * then an error message is left in interp->result.
184 *
185 * Side effects:
186 * new data is added to the image given by imageHandle.
187 *
188 *----------------------------------------------------------------------
189 */
190
191 typedef struct myblock {
192 Tk_PhotoImageBlock ck;
193 int dummy; /* extra space for offset[3], in case it is not
194 included already in Tk_PhotoImageBlock */
195 } myblock;
196
197 #define block bl.ck
198
ObjReadWin(interp,data,format,imageHandle,destX,destY,width,height,srcX,srcY)199 static int ObjReadWin(interp, data, format, imageHandle,
200 destX, destY, width, height, srcX, srcY)
201 Tcl_Interp *interp;
202 Tcl_Obj *data;
203 Tcl_Obj *format;
204 Tk_PhotoHandle imageHandle;
205 int destX, destY;
206 int width, height;
207 int srcX, srcY;
208 {
209 myblock bl;
210 Tk_Window tkwin;
211 int fileWidth, fileHeight, i, depth, ncolors, nBytes, x, y;
212 char *name;
213 #ifndef __WIN32__
214 XImage *ximage;
215 ColormapData cdata;
216 #else
217 # undef XGetPixel
218 # define XGetPixel(P,X,Y) GetPixel(P, X, Y)
219 TkWinDCState DCi;
220 HDC ximage;
221 #endif
222 Colormap cmap;
223 Visual *visual;
224 unsigned char *p;
225 #ifdef X_GetImage
226 Tk_ErrorHandler handle;
227 #endif
228 int green, blue;
229
230 name = ImgGetStringFromObj(data, NULL);
231
232 tkwin = Tk_NameToWindow(interp, name, Tk_MainWindow(interp));
233
234 if (!tkwin) {
235 Tcl_AppendResult(interp, "Window \"", name,"\" doesn't exist", (char *) NULL);
236 return TCL_ERROR;
237 }
238
239 if (!Tk_WindowId(tkwin)) {
240 Tcl_AppendResult(interp, "Window \"", name,"\" is not mapped", (char *) NULL);
241 return TCL_ERROR;
242 }
243
244 fileWidth = Tk_Width(tkwin);
245 fileHeight = Tk_Height(tkwin);
246
247 if ((srcX + width) > fileWidth) {
248 width = fileWidth - srcX;
249 }
250 if ((srcY + height) > fileHeight) {
251 height = fileHeight - srcY;
252 }
253 if ((width <= 0) || (height <= 0)) {
254 return TCL_OK;
255 }
256
257 /*
258 * If the window is off the screen it will generate an BadMatch/XError
259 * We catch any BadMatch errors here
260 */
261
262 #ifdef X_GetImage
263 handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch,
264 X_GetImage, -1, xerrorhandler, (ClientData) tkwin);
265 #endif
266
267 #ifndef __WIN32__
268 /*
269 * Generate an XImage from the window. We can then read pixel
270 * values out of the XImage.
271 */
272
273 ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), srcX, srcY,
274 width, height, AllPlanes, ZPixmap);
275
276 #ifdef X_GetImage
277 Tk_DeleteErrorHandler(handle);
278 #endif
279
280 if (ximage == (XImage*) NULL) {
281 Tcl_AppendResult(interp, "Window \"", name,
282 "\" cannot be transformed into a pixmap (possibly obscured?)",
283 (char *) NULL);
284 return TCL_ERROR;
285 }
286 #else
287 ximage = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &DCi);
288 #endif
289
290 depth = Tk_Depth(tkwin);
291 visual = Tk_Visual(tkwin);
292 #ifndef __WIN32__
293 cmap = Tk_Colormap(tkwin);
294
295 /*
296 * Obtain information about the colormap, ie the mapping between
297 * pixel values and RGB values. The code below should work
298 * for all Visual types.
299 */
300
301 ncolors = visual->map_entries;
302 cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors);
303 cdata.ncolors = ncolors;
304 if (visual->class == DirectColor || visual->class == TrueColor) {
305 cdata.separated = 1;
306 cdata.red_mask = visual->red_mask;
307 cdata.green_mask = visual->green_mask;
308 cdata.blue_mask = visual->blue_mask;
309 cdata.red_shift = 0;
310 cdata.green_shift = 0;
311 cdata.blue_shift = 0;
312 while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0)
313 cdata.red_shift ++;
314 while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0)
315 cdata.green_shift ++;
316 while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0)
317 cdata.blue_shift ++;
318 for (i = 0; i < ncolors; i ++)
319 cdata.colors[i].pixel =
320 ((i << cdata.red_shift) & cdata.red_mask) |
321 ((i << cdata.green_shift) & cdata.green_mask) |
322 ((i << cdata.blue_shift) & cdata.blue_mask);
323 } else {
324 cdata.separated=0;
325 for (i = 0; i < ncolors; i ++) cdata.colors[i].pixel = i;
326 }
327 cdata.color = !(visual->class == StaticGray || visual->class == GrayScale);
328
329 XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors);
330 #endif
331
332 Tk_PhotoExpand(imageHandle, destX + width, destY + height);
333 block.offset[0] = 0;
334 block.offset[3] = 0;
335 #ifndef __WIN32__
336 if (cdata.color) {
337 #endif
338 block.pixelSize = 3;
339 block.offset[1] = green = 1;
340 block.offset[2] = blue = 2;
341 #ifndef __WIN32__
342 } else {
343 block.pixelSize = 1;
344 block.offset[1] = green = 0;
345 block.offset[2] = blue = 0;
346 }
347 #endif
348 block.width = width;
349 block.height = height;
350 block.pitch = block.pixelSize * width;
351 nBytes = block.pitch * height;
352 block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
353
354 p = block.pixelPtr;
355 for (y = 0; y<height; y++) {
356 for (x = 0; x<width; x++) {
357 unsigned long pixel = XGetPixel(ximage, x, y);
358 #ifndef __WIN32__
359 if (cdata.separated) {
360 int r = (pixel & cdata.red_mask) >> cdata.red_shift;
361 p[0] = cdata.colors[r].red >> 8;
362 if (cdata.color) {
363 int g = (pixel & cdata.green_mask) >> cdata.green_shift;
364 int b = (pixel & cdata.blue_mask) >> cdata.blue_shift;
365 p[1] = cdata.colors[g].green >> 8;
366 p[2] = cdata.colors[b].blue >> 8;
367 }
368 } else {
369 p[0] = cdata.colors[pixel].red >> 8;
370 if (cdata.color) {
371 p[1] = cdata.colors[pixel].green >> 8;
372 p[2] = cdata.colors[pixel].blue >> 8;
373 }
374 }
375 #else
376 p[0] = GetRValue(pixel);
377 p[1] = GetGValue(pixel);
378 p[2] = GetBValue(pixel);
379 #endif
380 p += block.pixelSize;
381 }
382 }
383
384 Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height, TK_PHOTO_COMPOSITE_SET);
385
386 #ifndef __WIN32__
387 XDestroyImage(ximage);
388 ckfree((char *) cdata.colors);
389 #else
390 # undef XGetPixel
391 TkWinReleaseDrawableDC(Tk_WindowId(tkwin), ximage, &DCi);
392 #endif
393 ckfree((char *) block.pixelPtr);
394 return TCL_OK;
395 }
396
397