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