Index: src/Fl_Copy_Surface.cxx
===================================================================
--- src/Fl_Copy_Surface.cxx	(revision 0)
+++ src/Fl_Copy_Surface.cxx	(revision 0)
@@ -0,0 +1,447 @@
+#include <FL/Fl_Copy_Surface.H>
+#include <FL/Fl.H>
+
+
+#if defined(__APPLE__)
+#include <ApplicationServices/ApplicationServices.h>
+#if defined(__ppc__)
+#include <QuickTime/QuickTimeComponents.h>
+#endif // __ppc__
+
+Fl_Quartz_Surface::Fl_Quartz_Surface(int w, int h) : Fl_System_Printer(), width(w), height(h) {
+}
+
+int Fl_Quartz_Surface::printable_rect(int *w, int *h) {
+  *w = width;
+  *h = height;
+  return 0;
+}
+
+const char *Fl_Quartz_Surface::class_id = "Fl_Quartz_Surface";
+
+#elif defined(WIN32)
+
+Fl_GDI_Surface::Fl_GDI_Surface() : Fl_Paged_Device() {
+  driver(new Fl_GDI_Graphics_Driver);
+  depth = 0;
+}
+
+Fl_GDI_Surface::~Fl_GDI_Surface() {
+  delete driver();
+}
+
+void Fl_GDI_Surface::translate(int x, int y) {
+  GetWindowOrgEx(fl_gc, origins+depth);
+  SetWindowOrgEx(fl_gc, origins[depth].x - x, origins[depth].y - y, NULL);
+  if (depth < sizeof(origins)/sizeof(POINT)) depth++;
+  else Fl::warning("Fl_GDI_Surface: translate stack overflow!");
+}
+
+void Fl_GDI_Surface::untranslate() {
+  if (depth > 0) depth--;
+  SetWindowOrgEx(fl_gc, origins[depth].x, origins[depth].y, NULL);
+}
+  
+const char *Fl_GDI_Surface::class_id = "Fl_GDI_Surface";
+
+#endif
+
+
+const char *Fl_Copy_Surface::class_id = "Fl_Copy_Surface";
+
+/** Constructor. 
+ \param w and \param h are the width and height of the clipboard surface
+ in pixels where drawing will occur.
+ */
+Fl_Copy_Surface::Fl_Copy_Surface(int w, int h) :  Fl_Surface_Device(NULL)
+{
+  width = w;
+  height = h;
+#ifdef __APPLE__
+  helper = new Fl_Quartz_Surface(width, height);
+  driver(helper->driver());
+  prepare_copy_pdf_and_tiff(w, h);
+  oldgc = fl_gc;
+#elif defined(WIN32)
+  helper = new Fl_GDI_Surface();
+  driver(helper->driver());
+  oldgc = fl_gc;
+  // exact computation of factor from screen units to EnhMetaFile units (0.01 mm)
+  HDC hdc = GetDC(NULL);
+  int hmm = GetDeviceCaps(hdc, HORZSIZE);
+  int hdots = GetDeviceCaps(hdc, HORZRES);
+  int vmm = GetDeviceCaps(hdc, VERTSIZE);
+  int vdots = GetDeviceCaps(hdc, VERTRES);
+  ReleaseDC(NULL, hdc);
+  float factorw =  (100. * hmm) / hdots;
+  float factorh =  (100. * vmm) / vdots + 0.5;
+  
+  RECT rect; rect.left = 0; rect.top = 0; rect.right = w * factorw; rect.bottom = h * factorh;
+  gc = CreateEnhMetaFile (NULL, NULL, &rect, NULL);
+  if (gc != NULL) {
+    SetTextAlign(gc, TA_BASELINE|TA_LEFT);
+    SetBkMode(gc, TRANSPARENT);
+  } 
+#else // Xlib
+  helper = new Fl_Xlib_Surface();
+  driver(helper->driver());
+  Fl::first_window()->make_current();
+  oldwindow = fl_xid(Fl::first_window());
+  xid = fl_create_offscreen(w,h);
+  Fl_Surface_Device *present_surface = Fl_Surface_Device::surface();
+  set_current();
+  fl_color(FL_WHITE);
+  fl_rectf(0, 0, w, h);
+  present_surface->set_current();
+#endif
+}
+
+/** Destructor.
+ */
+Fl_Copy_Surface::~Fl_Copy_Surface()
+{
+#ifdef __APPLE__
+  complete_copy_pdf_and_tiff();
+  fl_gc = oldgc;
+  delete (Fl_Quartz_Surface*)helper;
+#elif defined(WIN32)
+  if(oldgc == fl_gc) oldgc = NULL;
+  HENHMETAFILE hmf = CloseEnhMetaFile (gc);
+  if ( hmf != NULL ) {
+    if ( OpenClipboard (NULL) ){
+      EmptyClipboard ();
+      SetClipboardData (CF_ENHMETAFILE, hmf);
+      CloseClipboard ();
+    }
+    DeleteEnhMetaFile(hmf);
+  }
+  DeleteDC(gc);
+  fl_gc = oldgc;
+  delete (Fl_GDI_Surface*)helper;
+#else // Xlib
+  fl_pop_clip(); 
+  unsigned char *data = fl_read_image(NULL,0,0,width,height,0);
+  fl_window = oldwindow; 
+  _ss->set_current();
+  Fl::copy_image(data,width,height,1);
+  delete[] data;
+  fl_delete_offscreen(xid);
+  delete (Fl_Xlib_Surface*)helper;
+#endif
+}
+
+/** Copies a widget in the clipboard
+ 
+ \param widget any FLTK widget (e.g., standard, custom, window, GL view) to copy
+ \param delta_x and \param delta_y give 
+ the position in the clipboard of the top-left corner of the widget
+ */
+void Fl_Copy_Surface::draw(Fl_Widget* widget, int delta_x, int delta_y) 
+{
+  helper->print_widget(widget, delta_x, delta_y);
+}
+
+void Fl_Copy_Surface::set_current()
+{
+#if defined(__APPLE__) || defined(WIN32)
+  fl_gc = gc;
+  fl_window = (Window)1;
+  Fl_Surface_Device::set_current();
+#else
+  fl_window=xid; 
+  _ss = Fl_Surface_Device::surface(); 
+  Fl_Surface_Device::set_current();
+  fl_push_no_clip();
+#endif
+}
+
+
+#if defined(__APPLE__)
+
+size_t Fl_Copy_Surface::MyPutBytes(void* info, const void* buffer, size_t count)
+  {
+  CFDataAppendBytes ((CFMutableDataRef) info, (const UInt8 *)buffer, count);
+  return count;
+}
+
+void Fl_Copy_Surface::init_PDF_context(int w, int h)
+{
+  CGRect bounds = CGRectMake(0, 0, w, h );	
+  pdfdata = CFDataCreateMutable(NULL, 0);
+  CGDataConsumerRef myconsumer;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+  if(CGDataConsumerCreateWithCFData != NULL) {
+    myconsumer = CGDataConsumerCreateWithCFData(pdfdata); // 10.4
+  }
+  else 
+#endif
+  {
+    static CGDataConsumerCallbacks callbacks = { Fl_Copy_Surface::MyPutBytes, NULL };
+    myconsumer = CGDataConsumerCreate ((void*) pdfdata, &callbacks);
+  }
+  gc = CGPDFContextCreate (myconsumer, &bounds, NULL);
+  CGDataConsumerRelease (myconsumer);
+}
+
+void Fl_Copy_Surface::prepare_copy_pdf_and_tiff(int w, int h)
+{
+  init_PDF_context(w, h);
+  if (gc == NULL) return;
+  CGRect bounds = CGRectMake(0, 0, w, h );	
+  CGContextBeginPage (gc, &bounds);
+  CGContextTranslateCTM(gc, 0, h);
+  CGContextScaleCTM(gc, 1.0f, -1.0f);
+  CGContextSaveGState(gc);
+}
+
+static void bitmap_to_tiff_clipboard(CGContextRef c, PasteboardRef clipboard)
+{
+  if (fl_mac_os_version >= 100400) {
+    CFStringRef tiff = CFSTR("public.tiff");
+    CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+    CGImageRef image = CGBitmapContextCreateImage(c); // 10.4
+    CGImageDestinationRef dest = CGImageDestinationCreateWithData(data,tiff, 1, NULL); // 10.4
+    CGImageDestinationAddImage(dest, image, NULL); // 10.4
+    CGImageDestinationFinalize(dest); // 10.4
+    CGImageRelease(image);
+    CFRelease(dest);
+#endif
+    PasteboardPutItemFlavor(clipboard, (PasteboardItemID)1, tiff, data, kPasteboardFlavorNoFlags );
+    CFRelease(data);
+    }
+  else {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 && defined(__ppc__)
+#warning Compilation with -mmacosx-version-min=10.3 requires -framework QuickTime at link time
+	GraphicsExportComponent exporter;
+   	OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, /*kQTFileTypePicture*/ 'PICT', &exporter);
+   	ComponentResult cerr = GraphicsExportSetInputCGBitmapContext(exporter, c); // 10.3 -framework QuickTime
+   	Handle dataHandle = NewHandle(0);
+   	cerr = GraphicsExportSetOutputHandle(exporter, dataHandle); // -framework QuickTime
+  	unsigned long size;
+   	cerr = GraphicsExportDoExport(exporter, &size); // -framework QuickTime
+   	err = CloseComponent(exporter);
+   	if (GetHandleSize(dataHandle) > 512) {
+     	HLock(dataHandle);
+     	// The clipboard REQUIRES only the image data, not the header.
+     	CFDataRef pictdata = CFDataCreate(NULL, (const UInt8 *)*dataHandle + 512, GetHandleSize(dataHandle) - 512);
+     	HUnlock(dataHandle);
+     	PasteboardPutItemFlavor(clipboard, (PasteboardItemID)1,
+					 	CFSTR("com.apple.pict"),
+					 	pictdata,
+					 	kPasteboardFlavorNoFlags );
+     	CFRelease(pictdata);
+     	}
+   	DisposeHandle(dataHandle);
+#endif
+  }
+}
+
+
+void Fl_Copy_Surface::complete_copy_pdf_and_tiff()
+{
+  CGContextRestoreGState(gc);
+  CGContextEndPage(gc);
+  CGContextRelease(gc);
+  PasteboardRef clipboard = NULL;
+  PasteboardCreate(kPasteboardClipboard, &clipboard);
+  PasteboardClear(clipboard); //	first, copy PDF to clipboard 
+  PasteboardPutItemFlavor (clipboard, (PasteboardItemID)1, 
+			   CFSTR("com.adobe.pdf"), // kUTTypePDF
+			   pdfdata, kPasteboardFlavorNoFlags);
+  //second, transform this PDF to a bitmap image and put it as tiff in clipboard
+  CGDataProviderRef prov;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+  if(fl_mac_os_version >= 100400)
+    prov = CGDataProviderCreateWithCFData(pdfdata); // 10.4
+  else 
+#endif
+    prov = CGDataProviderCreateWithData(NULL, CFDataGetBytePtr(pdfdata), CFDataGetLength(pdfdata), NULL);
+  CGPDFDocumentRef pdfdoc = CGPDFDocumentCreateWithProvider(prov);
+  CGPDFPageRef pdfpage = CGPDFDocumentGetPage(pdfdoc, 1);
+  CGDataProviderRelease(prov);
+  CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+  void *mem = ( fl_mac_os_version >= 100600 ? NULL : malloc(width * height * 4) );
+  gc = CGBitmapContextCreate(mem, width, height, 8, width * 4, space, kCGImageAlphaNoneSkipLast);
+  CFRelease(space);
+  if (gc == NULL) { if (mem) free(mem); return; }
+  CGRect rect = CGRectMake(0, 0, width, height);
+  CGContextSetRGBFillColor(gc,  1,1,1,1);//need to clear background
+  CGContextFillRect(gc, rect);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+  CGContextDrawPDFPage(gc, pdfpage);  // requires 10.3
+#endif
+  CGPDFDocumentRelease(pdfdoc);
+  CFRelease(pdfdata);
+  bitmap_to_tiff_clipboard(gc, clipboard);
+  CFRelease(clipboard);    
+  CGContextRelease(gc);
+  if (mem) free(mem);
+}
+
+#endif  // __APPLE__
+
+#if !(defined(__APPLE__) || defined(WIN32) || defined(FL_DOXYGEN))
+/** graphics driver that translates all graphics coordinates before calling Xlib */
+class Fl_translated_Xlib_Graphics_Driver : public Fl_Xlib_Graphics_Driver {
+  Fl_Xlib_Graphics_Driver *direct;
+  int offset_x, offset_y; // translation between user and graphical coordinates: graphical = user + offset
+  int depth; // depth of translation stack
+  int stack_x[10], stack_y[10]; // translation stack allowing cumulative translations
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_translated_Xlib_Graphics_Driver(Fl_Xlib_Graphics_Driver *driver) {
+    direct = driver;
+    offset_x = 0; offset_y = 0;
+    depth = 0;
+    }
+  virtual ~Fl_translated_Xlib_Graphics_Driver() {};
+  void translate_all(int dx, int dy) { // reversible adds dx,dy to the offset between user and graphical coordinates
+    stack_x[depth] = offset_x;
+    stack_y[depth] = offset_y;
+    offset_x = stack_x[depth] + dx;
+    offset_y = stack_y[depth] + dy;
+    push_matrix();
+    translate(dx, dy);
+    if (depth < sizeof(stack_x)/sizeof(int)) depth++;
+    else Fl::warning("%s: translate stack overflow!", class_id);
+  }
+  void untranslate_all() { // undoes previous translate_all()
+    if (depth > 0) depth--;
+    offset_x = stack_x[depth];
+    offset_y = stack_y[depth];
+    pop_matrix();
+  }
+  void color(uchar r, uchar g, uchar b) {
+    direct->color(r, g, b); 
+    Fl_Graphics_Driver::color(direct->Fl_Graphics_Driver::color());
+  }
+  void color(Fl_Color c) {
+    direct->color(c); 
+    Fl_Graphics_Driver::color(c);
+  }
+  void font(Fl_Font face, Fl_Fontsize fsize) {
+    direct->font(face, fsize); 
+    Fl_Graphics_Driver::font(face, fsize);
+  }
+  void text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h) { direct->text_extents(str, n,dx,dy,w,h);}
+  double width(const char *str, int n) {return direct->width(str, n);}
+  double width(unsigned int c) {return direct->width(c);}
+  int height() {return direct->height();}
+  int descent() {return direct->descent();}
+  void rect(int x, int y, int w, int h) { Fl_Xlib_Graphics_Driver::rect(x+offset_x, y+offset_y, w, h); }
+  void rectf(int x, int y, int w, int h) { Fl_Xlib_Graphics_Driver::rectf(x+offset_x, y+offset_y, w, h); }
+  void xyline(int x, int y, int x1) { Fl_Xlib_Graphics_Driver::xyline(x+offset_x, y+offset_y, x1+offset_x); }
+  void xyline(int x, int y, int x1, int y2) { Fl_Xlib_Graphics_Driver::xyline(x+offset_x, y+offset_y, x1+offset_x, y2+offset_y); }
+  void xyline(int x, int y, int x1, int y2, int x3) { Fl_Xlib_Graphics_Driver::xyline(x+offset_x, y+offset_y, x1+offset_x, y2+offset_y, x3+offset_x); }
+  void yxline(int x, int y, int y1) { Fl_Xlib_Graphics_Driver::yxline(x+offset_x, y+offset_y, y1+offset_y); }
+  void yxline(int x, int y, int y1, int x2) { Fl_Xlib_Graphics_Driver::yxline(x+offset_x, y+offset_y, y1+offset_y, x2+offset_x); }
+  void yxline(int x, int y, int y1, int x2, int y3) { Fl_Xlib_Graphics_Driver::yxline(x+offset_x, y+offset_y, y1+offset_y, x2+offset_x, y3+offset_y); }
+  void line(int x, int y, int x1, int y1) { Fl_Xlib_Graphics_Driver::line(x+offset_x, y+offset_y, x1+offset_x, y1+offset_y); }
+  void line(int x, int y, int x1, int y1, int x2, int y2) { Fl_Xlib_Graphics_Driver::line(x+offset_x, y+offset_y, x1+offset_x, y1+offset_y, x2+offset_x, y2+offset_y); }
+  void draw(const char* str, int n, int x, int y) { 
+    fl_graphics_driver = direct;
+    direct->draw(str, n, x+offset_x, y+offset_y); 
+    fl_graphics_driver = this;
+ }
+  void draw(int angle, const char *str, int n, int x, int y) { 
+    fl_graphics_driver = direct;
+    direct->draw(angle, str, n, x+offset_x, y+offset_y); 
+    fl_graphics_driver = this;
+  }
+  void rtl_draw(const char* str, int n, int x, int y) { 
+    fl_graphics_driver = direct;
+    direct->rtl_draw(str, n, x+offset_x, y+offset_y); 
+    fl_graphics_driver = this;
+  }
+  void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { 
+    fl_graphics_driver = direct;
+    direct->draw(pxm, XP+offset_x, YP+offset_y, WP,HP,cx,cy); 
+    fl_graphics_driver = this;
+  }
+  void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { 
+    fl_graphics_driver = direct;
+    direct->draw(bm, XP+offset_x, YP+offset_y, WP,HP,cx,cy); 
+    fl_graphics_driver = this;
+  }
+  void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { 
+    fl_graphics_driver = direct;
+    direct->draw(img, XP+offset_x, YP+offset_y, WP,HP,cx,cy); 
+    fl_graphics_driver = this;
+  }
+  void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) { 
+    fl_graphics_driver = direct;
+    direct->draw_image(buf, X+offset_x, Y+offset_y, W,H,D,L); 
+    fl_graphics_driver = this;
+  }
+  void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) { 
+    fl_graphics_driver = direct;
+    direct->draw_image(cb, data, X+offset_x, Y+offset_y, W,H,D); 
+    fl_graphics_driver = this;
+  }
+  void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) { 
+    fl_graphics_driver = direct;
+    direct->draw_image_mono(buf, X+offset_x, Y+offset_y, W,H,D,L); 
+    fl_graphics_driver = this;
+  }
+  void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) { 
+    fl_graphics_driver = direct;
+    direct->draw_image_mono(cb, data, X+offset_x, Y+offset_y, W,H,D); 
+    fl_graphics_driver = this;
+  }
+  void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { direct->copy_offscreen(x+offset_x, y+offset_y, w, h,pixmap,srcx,srcy); }
+  void push_clip(int x, int y, int w, int h) {
+    fl_graphics_driver = direct;
+    fl_push_clip(x+offset_x, y+offset_y, w, h); 
+    fl_graphics_driver = this;
+  }
+  void pop_clip() {
+    fl_graphics_driver = direct;
+    fl_pop_clip(); 
+    fl_graphics_driver = this;
+  }
+  void push_no_clip() {
+    fl_graphics_driver = direct;
+    fl_push_no_clip(); 
+    fl_graphics_driver = this;
+  };
+  int not_clipped(int x, int y, int w, int h) { return Fl_Xlib_Graphics_Driver::not_clipped(x + offset_x, y + offset_y, w, h); };
+  int clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H) { 
+    int retval = Fl_Xlib_Graphics_Driver::clip_box(x + offset_x, y + offset_y, w,h,X,Y,W,H);
+    X -= offset_x;
+    Y -= offset_y;
+    return retval;
+  }
+  void pie(int x, int y, int w, int h, double a1, double a2) { Fl_Xlib_Graphics_Driver::pie(x+offset_x,y+offset_y,w,h,a1,a2); }
+  void arc(int x, int y, int w, int h, double a1, double a2) { Fl_Xlib_Graphics_Driver::arc(x+offset_x,y+offset_y,w,h,a1,a2); }
+  void polygon(int x0, int y0, int x1, int y1, int x2, int y2) { Fl_Xlib_Graphics_Driver::polygon(x0+offset_x,y0+offset_y,x1+offset_x,y1+offset_y,x2+offset_x,y2+offset_y);}
+  void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
+    Fl_Xlib_Graphics_Driver::polygon(x0+offset_x,y0+offset_y,x1+offset_x,y1+offset_y,x2+offset_x,y2+offset_y,x3+offset_x,y3+offset_y);
+  }
+  void loop(int x0, int y0, int x1, int y1, int x2, int y2) {Fl_Xlib_Graphics_Driver::loop(x0+offset_x,y0+offset_y,x1+offset_x,y1+offset_y,x2+offset_x,y2+offset_y);}
+  void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
+    Fl_Xlib_Graphics_Driver::loop(x0+offset_x,y0+offset_y,x1+offset_x,y1+offset_y,x2+offset_x,y2+offset_y,x3+offset_x,y3+offset_y);
+  }
+  void point(int x, int y) { Fl_Xlib_Graphics_Driver::point(x+offset_x, y+offset_y); }
+};
+
+const char *Fl_translated_Xlib_Graphics_Driver::class_id = "Fl_translated_Xlib_Graphics_Driver";
+
+void Fl_Xlib_Surface::translate(int x, int y) { 
+  ((Fl_translated_Xlib_Graphics_Driver*)driver())->translate_all(x, y); 
+}
+void Fl_Xlib_Surface::untranslate() { 
+  ((Fl_translated_Xlib_Graphics_Driver*)driver())->untranslate_all(); 
+}
+
+Fl_Xlib_Surface::Fl_Xlib_Surface() : Fl_Paged_Device() {
+  driver(new Fl_translated_Xlib_Graphics_Driver((Fl_Xlib_Graphics_Driver*)Fl_Display_Device::display_device()->driver()));
+}
+Fl_Xlib_Surface::~Fl_Xlib_Surface() {
+  delete driver();
+}
+
+const char *Fl_Xlib_Surface::class_id = "Fl_Xlib_Surface";
+
+#endif
Index: src/Fl_Image_Surface.cxx
===================================================================
--- src/Fl_Image_Surface.cxx	(revision 0)
+++ src/Fl_Image_Surface.cxx	(revision 0)
@@ -0,0 +1,132 @@
+#include <FL/Fl_Image_Surface.H>
+#include <FL/Fl_Printer.H>
+#include <FL/Fl.H>
+
+
+const char *Fl_Image_Surface::class_id = "Fl_Image_Surface";
+
+/** The constructor.
+ \param w and \param h give the size in pixels of the resulting image.
+ */
+Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
+  width = w;
+  height = h;
+  offscreen = fl_create_offscreen(w, h);
+#ifdef __APPLE__
+  helper = new Fl_Quartz_Flipped_Surface(width, height);
+  driver(helper->driver());
+#elif defined(WIN32)
+  helper = new Fl_GDI_Surface();
+  driver(helper->driver());
+#else
+  helper = new Fl_Xlib_Surface();
+  driver(helper->driver());
+#endif
+}
+
+/** The destructor.
+ */
+Fl_Image_Surface::~Fl_Image_Surface() {
+  fl_delete_offscreen(offscreen);
+#ifdef __APPLE__
+  delete (Fl_Quartz_Flipped_Surface*)helper;
+#elif defined(WIN32)
+  delete (Fl_GDI_Surface*)helper;
+#else
+  delete (Fl_Xlib_Surface*)helper;
+#endif
+}
+
+/** Returns the image made of all drawings sent to the Fl_Image_Surface object.
+ The returned object can be safely cast to Fl_RGB_Image* and contains its own copy
+ of the RGB data.
+ */
+Fl_Image* Fl_Image_Surface::image()
+{
+  unsigned char *data;
+#ifdef __APPLE__
+  CGContextFlush(offscreen);
+  data = fl_read_image(NULL, 0, 0, width, height, 0);
+  fl_end_offscreen();
+#elif defined(WIN32)
+  fl_pop_clip(); 
+  data = fl_read_image(NULL, 0, 0, width, height, 0);
+  RestoreDC(fl_gc, _savedc); 
+  DeleteDC(fl_gc); 
+  _ss->set_current(); 
+  fl_window=_sw; 
+  fl_gc = _sgc;
+#else
+  fl_pop_clip(); 
+  data = fl_read_image(NULL, 0, 0, width, height, 0);
+  fl_window = pre_window; 
+  previous->set_current();
+#endif
+  Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height);
+  image->alloc_array = 1;
+  return image;
+}
+
+/** Draws a widget in the image surface
+ 
+ \param widget any FLTK widget (e.g., standard, custom, window, GL view) to draw in the image
+ \param delta_x and \param delta_y give 
+ the position in the image of the top-left corner of the widget
+ */
+void Fl_Image_Surface::draw(Fl_Widget *widget, int delta_x, int delta_y)
+{
+  helper->print_widget(widget, delta_x, delta_y);
+}
+
+
+void Fl_Image_Surface::set_current()
+{
+#if defined(__APPLE__)
+  fl_begin_offscreen(offscreen);
+  fl_pop_clip();
+  Fl_Surface_Device::set_current(); 
+  fl_push_no_clip();
+#elif defined(WIN32)
+  _sgc=fl_gc; 
+  _sw=fl_window;
+  _ss = Fl_Surface_Device::surface(); 
+  Fl_Surface_Device::set_current();
+  fl_gc = fl_makeDC(offscreen); 
+   _savedc = SaveDC(fl_gc); 
+  fl_window=(HWND)offscreen; 
+  fl_push_no_clip();
+#else
+  pre_window = fl_window; 
+  fl_window = offscreen; 
+  previous = Fl_Surface_Device::surface(); 
+  Fl_Surface_Device::set_current();
+  fl_push_no_clip();
+#endif
+}
+
+#if defined(__APPLE__)
+
+Fl_Quartz_Flipped_Surface::Fl_Quartz_Flipped_Surface(int w, int h) : Fl_Quartz_Surface(w, h) {
+}
+
+void Fl_Quartz_Flipped_Surface::translate(int x, int y) {
+  CGContextRestoreGState(fl_gc);
+  CGContextSaveGState(fl_gc);
+  /*CGContextTranslateCTM(fl_gc, 0, height);
+   CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
+   CGContextTranslateCTM(fl_gc, x, y);
+   CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
+   CGContextTranslateCTM(fl_gc, 0, -height);*/
+  CGContextTranslateCTM(fl_gc, x, -y);
+  CGContextSaveGState(fl_gc);
+  CGContextTranslateCTM(fl_gc, 0, height);
+  CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
+}
+
+void Fl_Quartz_Flipped_Surface::untranslate() {
+  CGContextRestoreGState(fl_gc);
+}
+
+const char *Fl_Quartz_Flipped_Surface::class_id = "Fl_Quartz_Flipped_Surface";
+
+#endif // __APPLE__
Index: src/Makefile
===================================================================
--- src/Makefile	(revision 10113)
+++ src/Makefile	(working copy)
@@ -31,6 +31,7 @@
 	Fl_Choice.cxx \
 	Fl_Clock.cxx \
 	Fl_Color_Chooser.cxx \
+	Fl_Copy_Surface.cxx \
 	Fl_Counter.cxx \
 	Fl_Dial.cxx \
 	Fl_Device.cxx \
@@ -43,6 +44,7 @@
 	Fl_Group.cxx \
 	Fl_Help_View.cxx \
 	Fl_Image.cxx \
+	Fl_Image_Surface.cxx \
 	Fl_Input.cxx \
 	Fl_Input_.cxx \
 	Fl_Light_Button.cxx \
Index: src/Fl_win32.cxx
===================================================================
--- src/Fl_win32.cxx	(revision 10113)
+++ src/Fl_win32.cxx	(working copy)
@@ -589,13 +589,11 @@
 }
 
 // Call this when a "paste" operation happens:
-void Fl::paste(Fl_Widget &receiver, int clipboard) {
-  if (!clipboard || fl_i_own_selection[clipboard]) {
+void Fl::paste(Fl_Widget &receiver, int clipboard, const char *type) {
+  if (!clipboard || (fl_i_own_selection[clipboard] && strcmp(type, Fl::clipboard_plain_text) == 0)) {
     // We already have it, do it quickly without window server.
     // Notice that the text is clobbered if set_selection is
     // called in response to FL_PASTE!
-
-    // Convert \r\n -> \n
     char *i = fl_selection_buffer[clipboard];
     if (i==0L) {
       Fl::e_text = 0; 
@@ -603,39 +601,137 @@
     }
     Fl::e_text = new char[fl_selection_length[clipboard]+1];
     char *o = Fl::e_text;
-    while (*i) {
+    while (*i) { // Convert \r\n -> \n
       if ( *i == '\r' && *(i+1) == '\n') i++;
       else *o++ = *i++;
     }
     *o = 0;
     Fl::e_length = (int) (o - Fl::e_text);
+    Fl::e_clipboard_type = Fl::clipboard_plain_text;
     receiver.handle(FL_PASTE);
     delete [] Fl::e_text;
     Fl::e_text = 0;
-  } else {
+  } else if (clipboard) {
+    HANDLE h;
     if (!OpenClipboard(NULL)) return;
-    HANDLE h = GetClipboardData(CF_UNICODETEXT);
-    if (h) {
-      wchar_t *memLock = (wchar_t*) GlobalLock(h);
-      size_t utf16_len = wcslen(memLock);
-      Fl::e_text = (char*) malloc (utf16_len * 4 + 1);
-      unsigned utf8_len = fl_utf8fromwc(Fl::e_text, (unsigned) (utf16_len * 4), memLock, (unsigned) utf16_len);
-      *(Fl::e_text + utf8_len) = 0;
-      LPSTR a,b;
-      a = b = Fl::e_text;
-      while (*a) { // strip the CRLF pairs ($%$#@^)
-        if (*a == '\r' && a[1] == '\n') a++;
-        else *b++ = *a++;
+    if (strcmp(type, Fl::clipboard_plain_text) == 0) { // we want plain text from clipboard
+      if ((h = GetClipboardData(CF_UNICODETEXT))) { // there's text in the clipboard
+	wchar_t *memLock = (wchar_t*) GlobalLock(h);
+	size_t utf16_len = wcslen(memLock);
+	Fl::e_text = new char[utf16_len * 4 + 1];
+	unsigned utf8_len = fl_utf8fromwc(Fl::e_text, (unsigned) (utf16_len * 4), memLock, (unsigned) utf16_len);
+	*(Fl::e_text + utf8_len) = 0;
+	GlobalUnlock(h);
+	LPSTR a,b;
+	a = b = Fl::e_text;
+	while (*a) { // strip the CRLF pairs ($%$#@^)
+	  if (*a == '\r' && a[1] == '\n') a++;
+	  else *b++ = *a++;
+	}
+	*b = 0;
+	Fl::e_length = (int) (b - Fl::e_text);
+	Fl::e_clipboard_type = Fl::clipboard_plain_text;  // indicates that the paste event is for plain UTF8 text
+	receiver.handle(FL_PASTE); // send the FL_PASTE event to the widget
+	delete[] Fl::e_text;
+	Fl::e_text = 0;
+	}
       }
-      *b = 0;
-      Fl::e_length = (int) (b - Fl::e_text);
-      receiver.handle(FL_PASTE);
-      GlobalUnlock(h);
-      free(Fl::e_text);
-      Fl::e_text = 0;
+      else if (strcmp(type, Fl::clipboard_image) == 0) { // we want an image from clipboard
+	uchar *rgb = NULL;
+	int width, height, depth;
+	if ( (h = GetClipboardData(CF_DIB)) ) { // if there's a DIB in clipboard
+	  LPBITMAPINFO lpBI = (LPBITMAPINFO)GlobalLock(h) ;
+	  width = lpBI->bmiHeader.biWidth; // bitmap width & height
+	  height = lpBI->bmiHeader.biHeight;
+	  if ( (lpBI->bmiHeader.biBitCount == 24 || lpBI->bmiHeader.biBitCount == 32) && 
+	      lpBI->bmiHeader.biCompression == BI_RGB &&
+	      lpBI->bmiHeader.biClrUsed == 0) { // direct use of the DIB data if it's RGB or RGBA
+	    int linewidth; // row length
+	    depth = lpBI->bmiHeader.biBitCount/8; // 3 or 4
+	    if (depth == 3) linewidth = 4 * ((3*width + 3)/4); // row length: series of groups of 3 bytes, rounded to multiple of 4 bytes
+	    else linewidth = 4*width;
+	    rgb = new uchar[width * height * depth]; // will hold the image data
+	    uchar *p = rgb, *r, rr, gg, bb;
+	    for (int i=height-1; i>=0; i--) { // for each row, from last to first
+	      r = (uchar*)(lpBI->bmiColors) + i*linewidth; // beginning of pixel data for the ith row
+	      for (int j=0; j<width; j++) { // for each pixel in a row
+		bb = *r++; // BGR is in DIB
+		gg = *r++;
+		rr = *r++;
+		*p++ = rr; // we want RGB
+		*p++ = gg;
+		*p++ = bb;
+		if (depth == 4) *p++ = *r++; // copy alpha if present
+	      }
+	    }
+	  }
+	  else { // the system will decode a complex DIB
+	    void *pDIBBits = (void*)(lpBI->bmiColors); 
+	    if (lpBI->bmiHeader.biCompression == BI_BITFIELDS) pDIBBits = (void*)(lpBI->bmiColors + 3);
+	    else if (lpBI->bmiHeader.biClrUsed > 0) pDIBBits = (void*)(lpBI->bmiColors + lpBI->bmiHeader.biClrUsed);
+	    Fl_Offscreen off = fl_create_offscreen(width, height);
+	    fl_begin_offscreen(off);
+	    SetDIBitsToDevice(fl_gc, 0, 0, width, height, 0, 0, 0, height, pDIBBits, lpBI, DIB_RGB_COLORS);
+	    rgb = fl_read_image(NULL, 0, 0, width, height);
+	    depth = 3;
+	    fl_end_offscreen();
+	    fl_delete_offscreen(off);
+	  }
+	  GlobalUnlock(h);
+	}
+	else if ((h = GetClipboardData(CF_ENHMETAFILE))) { // if there's an enhanced metafile in clipboard
+	  ENHMETAHEADER header;
+	  GetEnhMetaFileHeader((HENHMETAFILE)h, sizeof(header), &header); // get structure containing metafile dimensions
+	  width = (header.rclFrame.right - header.rclFrame.left + 1); // in .01 mm units
+	  height = (header.rclFrame.bottom - header.rclFrame.top + 1);
+	  HDC hdc = GetDC(NULL); // get unit correspondance between .01 mm and screen pixels
+	  int hmm = GetDeviceCaps(hdc, HORZSIZE);
+	  int hdots = GetDeviceCaps(hdc, HORZRES);
+	  int vmm = GetDeviceCaps(hdc, VERTSIZE);
+	  int vdots = GetDeviceCaps(hdc, VERTRES);
+	  ReleaseDC(NULL, hdc);
+	  float factorw =  (100. * hmm) / hdots;
+	  float factorh =  (100. * vmm) / vdots + 0.5;
+	  width /= factorw; height /= factorh; // convert to screen pixel unit
+	  RECT rect = {0, 0, width, height};
+	  Fl_Offscreen off = fl_create_offscreen(width, height);
+	  fl_begin_offscreen(off);
+	  fl_color(FL_WHITE); fl_rectf(0,0,width, height); // draw white background
+	  PlayEnhMetaFile(fl_gc, (HENHMETAFILE)h, &rect); // draw metafile to offscreen buffer
+	  rgb = fl_read_image(NULL, 0, 0, width, height); // read pixels from offscreen buffer
+	  depth = 3;
+	  fl_end_offscreen();
+	  fl_delete_offscreen(off);
+	}
+	if (rgb) {
+	  Fl_RGB_Image *image = new Fl_RGB_Image(rgb, width, height, depth); // create new image from pixel data
+	  image->alloc_array = 1;
+	  Fl::e_clipboard_data = image;
+	  Fl::e_clipboard_type = Fl::clipboard_image;  // indicates that the paste event is for image data
+	  int done = receiver.handle(FL_PASTE); // send FL_PASTE event to widget
+	  Fl::e_clipboard_type = "";
+	  if (done == 0) { // if widget did not handle the event, delete the image
+	    Fl::e_clipboard_data = NULL;
+	    delete image;
+	  }
+	}
+      }
+     CloseClipboard();
     }
-    CloseClipboard();
+}
+
+int Fl::clipboard_contains(const char *type)
+{
+  int retval = 0;
+  if (!OpenClipboard(NULL)) return 0;
+  if (strcmp(type, Fl::clipboard_plain_text) == 0 || type[0] == 0) {
+    retval = IsClipboardFormatAvailable(CF_UNICODETEXT);
   }
+  else if (strcmp(type, Fl::clipboard_image) == 0) {
+    retval = IsClipboardFormatAvailable(CF_DIB) || IsClipboardFormatAvailable(CF_ENHMETAFILE);
+  }
+  CloseClipboard();
+  return retval;
 }
 
 static HWND clipboard_wnd = 0;
Index: src/Fl_x.cxx
===================================================================
--- src/Fl_x.cxx	(revision 10118)
+++ src/Fl_x.cxx	(working copy)
@@ -34,6 +34,7 @@
 #  include <FL/Fl_Tooltip.H>
 #  include <FL/fl_draw.H>
 #  include <FL/Fl_Paged_Device.H>
+#  include <FL/Fl_Shared_Image.H>
 #  include <FL/fl_ask.H>
 #  include <stdio.h>
 #  include <stdlib.h>
@@ -335,6 +336,9 @@
 Atom fl_XaCompoundText;
 Atom fl_XaUtf8String;
 Atom fl_XaTextUriList;
+Atom fl_XaImageBmp;
+Atom fl_XaImagePNG;
+Atom fl_INCR;
 Atom fl_NET_WM_NAME;			// utf8 aware window label
 Atom fl_NET_WM_ICON_NAME;		// utf8 aware window icon name
 Atom fl_NET_SUPPORTING_WM_CHECK;
@@ -641,6 +645,9 @@
   fl_XaCompoundText     = XInternAtom(d, "COMPOUND_TEXT",       0);
   fl_XaUtf8String       = XInternAtom(d, "UTF8_STRING",         0);
   fl_XaTextUriList      = XInternAtom(d, "text/uri-list",       0);
+  fl_XaImageBmp         = XInternAtom(d, "image/bmp",           0);
+  fl_XaImagePNG         = XInternAtom(d, "image/png",           0);
+  fl_INCR               = XInternAtom(d, "INCR",                0);
   fl_NET_WM_NAME        = XInternAtom(d, "_NET_WM_NAME",        0);
   fl_NET_WM_ICON_NAME   = XInternAtom(d, "_NET_WM_ICON_NAME",   0);
   fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0);
@@ -773,15 +780,18 @@
 Fl_Widget *fl_selection_requestor;
 char *fl_selection_buffer[2];
 int fl_selection_length[2];
+const char * fl_selection_type[2];
 int fl_selection_buffer_length[2];
 char fl_i_own_selection[2] = {0,0};
 
 // Call this when a "paste" operation happens:
-void Fl::paste(Fl_Widget &receiver, int clipboard) {
+void Fl::paste(Fl_Widget &receiver, int clipboard, const char *type) {
   if (fl_i_own_selection[clipboard]) {
     // We already have it, do it quickly without window server.
     // Notice that the text is clobbered if set_selection is
     // called in response to FL_PASTE!
+    // However, for now, we only paste text in this function
+    if (fl_selection_type[clipboard] != Fl::clipboard_plain_text) return;
     Fl::e_text = fl_selection_buffer[clipboard];
     Fl::e_length = fl_selection_length[clipboard];
     if (!Fl::e_text) Fl::e_text = (char *)"";
@@ -791,10 +801,57 @@
   // otherwise get the window server to return it:
   fl_selection_requestor = &receiver;
   Atom property = clipboard ? CLIPBOARD : XA_PRIMARY;
+  Fl::e_clipboard_type = type;
   XConvertSelection(fl_display, property, TARGETS, property,
                     fl_xid(Fl::first_window()), fl_event_time);
 }
 
+int Fl::clipboard_contains(const char *type)
+{
+  XEvent event;
+  Atom actual; int format; unsigned long count, remaining, i = 0;
+  unsigned char* portion = NULL;
+  Fl_Window *win = Fl::first_window();
+  if (!win || !fl_xid(win)) return 0;
+  XConvertSelection(fl_display, CLIPBOARD, TARGETS, CLIPBOARD,
+		    fl_xid(win), fl_event_time);
+  XFlush(fl_display);
+  do  { XNextEvent(fl_display, &event); i++; }
+  while (i < 10 && (event.type != SelectionNotify || event.xselection.property == None));
+  if (i >= 10) return 0;
+  XGetWindowProperty(fl_display,
+		     event.xselection.requestor,
+		     event.xselection.property,
+		     0, 4000, 0, 0,
+		     &actual, &format, &count, &remaining, &portion);
+  if (actual != XA_ATOM) return 0;
+  Atom t;
+  int retval = 0;
+  if (strcmp(type, Fl::clipboard_plain_text) == 0) {
+    for (i = 0; i<count; i++) { // searching for text data
+      t = ((Atom*)portion)[i];
+      if (t == fl_Xatextplainutf ||
+	  t == fl_Xatextplainutf2 ||
+	  t == fl_Xatextplain ||
+	  t == fl_XaUtf8String) {
+	retval = 1;
+	break;
+      }
+    }	
+  }
+  else if (strcmp(type, Fl::clipboard_image) == 0) {
+    for (i = 0; i<count; i++) { // searching for image data
+      t = ((Atom*)portion)[i];
+      if (t == fl_XaImageBmp || t == fl_XaImagePNG) {
+	retval = 1;
+	break;
+      }
+    }	
+  }
+  XFree(portion);
+  return retval;
+}
+
 Window fl_dnd_source_window;
 Atom *fl_dnd_source_types; // null-terminated list of data types being supplied
 Atom fl_dnd_type;
@@ -870,10 +927,81 @@
   fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
   fl_selection_length[clipboard] = len;
   fl_i_own_selection[clipboard] = 1;
+  fl_selection_type[clipboard] = Fl::clipboard_plain_text;
   Atom property = clipboard ? CLIPBOARD : XA_PRIMARY;
   XSetSelectionOwner(fl_display, property, fl_message_window, fl_event_time);
 }
 
+static void write_short(unsigned char **cp,short i){
+  unsigned char *c=*cp;
+  *c++=i&0xFF;i>>=8;
+  *c++=i&0xFF;i>>=8;
+  *cp=c;
+}
+
+static void write_int(unsigned char **cp,int i){
+  unsigned char *c=*cp;
+  *c++=i&0xFF;i>>=8;
+  *c++=i&0xFF;i>>=8;
+  *c++=i&0xFF;i>>=8;
+  *c++=i&0xFF;i>>=8;
+  *cp=c;
+}
+
+static unsigned char *create_bmp(const unsigned char *data, int W, int H, int *return_size){
+  int R=(3*W+3)/4 * 4; // the number of bytes per row, rounded up to multiple of 4
+  int s=H*R;
+  int fs=14+40+s;
+  unsigned char *b=new unsigned char[fs];
+  unsigned char *c=b;
+  // BMP header
+  *c++='B';
+  *c++='M';
+  write_int(&c,fs);
+  write_int(&c,0);
+  write_int(&c,14+40);
+  // DIB header:
+  write_int(&c,40);
+  write_int(&c,W);
+  write_int(&c,H);
+  write_short(&c,1);
+  write_short(&c,24);//bits ber pixel
+  write_int(&c,0);//RGB
+  write_int(&c,s);
+  write_int(&c,0);// horizontal resolution
+  write_int(&c,0);// vertical resolution
+  write_int(&c,0);//number of colors. 0 -> 1<<bits_per_pixel
+  write_int(&c,0);
+  // Pixel data
+  data+=3*W*H;
+  for (int y=0;y<H;++y){
+    data-=3*W;
+    const unsigned char *s=data;
+    unsigned char *p=c;
+    for (int x=0;x<W;++x){
+      *p++=s[2];
+      *p++=s[1];
+      *p++=s[0];
+      s+=3;
+    }
+    c+=R;
+  }
+  *return_size = fs;
+  return b;
+}
+
+void Fl::copy_image(const unsigned char *data, int W, int H, int clipboard){
+  if(!data || W<=0 || H<=0) return;
+  delete[] fl_selection_buffer[clipboard];
+  fl_selection_buffer[clipboard] = (char *) create_bmp(data,W,H,&fl_selection_length[clipboard]);
+  fl_selection_buffer_length[clipboard] = fl_selection_length[clipboard];
+  fl_i_own_selection[clipboard] = 1;
+  fl_selection_type[clipboard] = Fl::clipboard_image;
+
+  Atom property = clipboard ? CLIPBOARD : XA_PRIMARY;
+  XSetSelectionOwner(fl_display, property, fl_message_window, fl_event_time);
+}
+
 ////////////////////////////////////////////////////////////////
 // Code for tracking clipboard changes:
 
@@ -1047,7 +1175,63 @@
 
 }
 
+static bool getNextEvent(XEvent *event_return)
+{
+  time_t t = time(NULL);
+  while(!XPending(fl_display))
+  {
+    if(time(NULL) - t > 10.0)
+    {
+      //fprintf(stderr,"Error: The XNextEvent never came...\n");
+      return false; 
+    }
+  }
+  XNextEvent(fl_display, event_return);
+  return true;
+}
 
+static long getIncrData(uchar* &data, const XSelectionEvent& selevent, long lower_bound)
+{
+//fprintf(stderr,"Incremental transfer starting due to INCR property\n");
+  size_t total = 0;
+  XEvent event;
+  XDeleteProperty(fl_display, selevent.requestor, selevent.property);  
+  data = (uchar*)realloc(data, lower_bound);
+  for (;;)
+  {
+    if (!getNextEvent(&event)) break;
+    if (event.type == PropertyNotify)
+    {
+      if (event.xproperty.state != PropertyNewValue) continue;
+      Atom actual_type;
+      int actual_format;
+      unsigned long nitems;
+      unsigned long bytes_after;
+      unsigned char* prop = 0;
+      long offset = 0;
+      size_t num_bytes;
+      //size_t slice_size = 0;
+      do
+      {
+	XGetWindowProperty(fl_display, selevent.requestor, selevent.property, offset, 70000, True,
+			   AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
+	num_bytes = nitems * (actual_format / 8);
+	offset += num_bytes/4;
+	//slice_size += num_bytes;
+	if (total + num_bytes > lower_bound) data = (uchar*)realloc(data, total + num_bytes);
+	memcpy(data + total, prop, num_bytes); total += num_bytes;
+	if (prop) XFree(prop);
+      } while (bytes_after != 0);
+//fprintf(stderr,"INCR data size:%ld\n", slice_size);
+      if (num_bytes == 0) break;
+    }
+    else break;
+  }
+  XDeleteProperty(fl_display, selevent.requestor, selevent.property);
+  return (long)total;
+}
+
+
 int fl_handle(const XEvent& thisevent)
 {
   XEvent xevent = thisevent;
@@ -1139,6 +1323,7 @@
 
   case SelectionNotify: {
     static unsigned char* sn_buffer = 0;
+    //static const char *buffer_format = 0;
     if (sn_buffer) {XFree(sn_buffer); sn_buffer = 0;}
     long bytesread = 0;
     if (fl_xevent->xselection.property) for (;;) {
@@ -1150,7 +1335,7 @@
       if (XGetWindowProperty(fl_display,
                              fl_xevent->xselection.requestor,
                              fl_xevent->xselection.property,
-                             bytesread/4, 65536, 1, 0,
+                             bytesread/4, 65536, 0/*1*/, AnyPropertyType,
                              &actual, &format, &count, &remaining,
                              &portion)) break; // quit on error
 
@@ -1168,9 +1353,24 @@
       }
 
       if (actual == TARGETS || actual == XA_ATOM) {
-	Atom type = XA_STRING;
-	for (unsigned i = 0; i<count; i++) {
-	  Atom t = ((Atom*)portion)[i];
+/*for (unsigned i = 0; i<count; i++) {
+  fprintf(stderr," %s", XGetAtomName(fl_display, ((Atom*)portion)[i]) );
+  }
+fprintf(stderr,"\n");*/
+	Atom t, type = XA_STRING;
+	if (Fl::e_clipboard_type == Fl::clipboard_image) { // searching for image data
+	  for (unsigned i = 0; i<count; i++) { 
+	    t = ((Atom*)portion)[i];
+	    if (t == fl_XaImageBmp || t == fl_XaImagePNG) {
+	      type = t;
+	      goto found;
+	    }
+	  }
+	  XFree(portion);
+	  return true;
+	}
+	for (unsigned i = 0; i<count; i++) { // searching for text data
+	  t = ((Atom*)portion)[i];
 	  if (t == fl_Xatextplainutf ||
 	      t == fl_Xatextplainutf2 ||
 	      t == fl_Xatextplain ||
@@ -1183,14 +1383,33 @@
 	      t == fl_XaTextUriList ||
 	      t == fl_XaCompoundText) type = t;
 	}
+      found:
 	XFree(portion); portion = 0;
 	Atom property = xevent.xselection.property;
 	XConvertSelection(fl_display, property, type, property,
 	      fl_xid(Fl::first_window()),
 	      fl_event_time);
+	if (type == fl_XaImageBmp) {
+	  Fl::e_clipboard_type = Fl::clipboard_image;
+	  //buffer_format = "image/bmp";
+	  }
+	else if (type == fl_XaImagePNG) {
+	  Fl::e_clipboard_type = Fl::clipboard_image;
+	  //buffer_format = "image/png";
+	  }
+	else {
+	  Fl::e_clipboard_type = Fl::clipboard_plain_text;
+	  //buffer_format = Fl::clipboard_plain_text;
+	  }
+//fprintf(stderr,"used format=%s\n", buffer_format);
 	return true;
       }
-      // Make sure we got something sane...
+	if (actual == fl_INCR) {
+	  bytesread = getIncrData(sn_buffer, xevent.xselection, *(long*)portion);
+	  XFree(portion);
+	  break;
+	}
+	// Make sure we got something sane...
       if ((portion == NULL) || (format != 8) || (count == 0)) {
 	if (portion) { XFree(portion); portion = 0; }
         return true;
@@ -1203,22 +1422,45 @@
       sn_buffer[bytesread] = '\0';
       if (!remaining) break;
     }
-    if (sn_buffer) {
+    if (sn_buffer && Fl::e_clipboard_type == Fl::clipboard_plain_text) {
       sn_buffer[bytesread] = 0;
       convert_crlf(sn_buffer, bytesread);
     }
-
+    if (Fl::e_clipboard_type == Fl::clipboard_image) {
+      if (bytesread == 0) return 0;
+      Fl_Image *image = 0;
+      static char tmp_fname[21];
+      static Fl_Shared_Image *shared = 0;
+      strcpy(tmp_fname, "/tmp/clipboardXXXXXX");
+      int fd = mkstemp(tmp_fname);
+      if (fd == -1) return 0;
+      uchar *p = sn_buffer; ssize_t towrite = bytesread, written;
+      while (towrite) {
+	written = write(fd, p, towrite);
+	p += written; towrite -= written;
+	}
+      close(fd);
+      free(sn_buffer); sn_buffer = 0;
+      shared = Fl_Shared_Image::get(tmp_fname);
+      unlink(tmp_fname);
+      if (!shared) return 0;
+      image = shared->copy();
+      shared->release();
+      Fl::e_clipboard_data = (void*)image;
+    }
     if (!fl_selection_requestor) return 0;
 
-    Fl::e_text = sn_buffer ? (char*)sn_buffer : (char *)"";
-    Fl::e_length = bytesread;
+    if (Fl::e_clipboard_type == Fl::clipboard_plain_text) {
+      Fl::e_text = sn_buffer ? (char*)sn_buffer : (char *)"";
+      Fl::e_length = bytesread;
+      }
     int old_event = Fl::e_number;
     fl_selection_requestor->handle(Fl::e_number = FL_PASTE);
     Fl::e_number = old_event;
     // Detect if this paste is due to Xdnd by the property name (I use
     // XA_SECONDARY for that) and send an XdndFinished message. It is not
     // clear if this has to be delayed until now or if it can be done
-    // immediatly after calling XConvertSelection.
+    // immediately after calling XConvertSelection.
     if (fl_xevent->xselection.property == XA_SECONDARY &&
         fl_dnd_source_window) {
       fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished,
@@ -1242,32 +1484,54 @@
     e.target = fl_xevent->xselectionrequest.target;
     e.time = fl_xevent->xselectionrequest.time;
     e.property = fl_xevent->xselectionrequest.property;
-    if (e.target == TARGETS) {
-      Atom a[3] = {fl_XaUtf8String, XA_STRING, fl_XaText};
-      XChangeProperty(fl_display, e.requestor, e.property,
-                      XA_ATOM, atom_bits, 0, (unsigned char*)a, 3);
-    } else if (/*e.target == XA_STRING &&*/ fl_selection_length[clipboard]) {
-    if (e.target == fl_XaUtf8String ||
-	     e.target == XA_STRING ||
-	     e.target == fl_XaCompoundText ||
-	     e.target == fl_XaText ||
-	     e.target == fl_Xatextplain ||
-	     e.target == fl_Xatextplainutf ||
-	     e.target == fl_Xatextplainutf2) {
-	// clobber the target type, this seems to make some applications
-	// behave that insist on asking for XA_TEXT instead of UTF8_STRING
-	// Does not change XA_STRING as that breaks xclipboard.
-	if (e.target != XA_STRING) e.target = fl_XaUtf8String;
+    if (fl_selection_type[clipboard] == Fl::clipboard_plain_text) {
+      if (e.target == TARGETS) {
+	Atom a[3] = {fl_XaUtf8String, XA_STRING, fl_XaText};
 	XChangeProperty(fl_display, e.requestor, e.property,
-			 e.target, 8, 0,
-			 (unsigned char *)fl_selection_buffer[clipboard],
-			 fl_selection_length[clipboard]);
+	                XA_ATOM, atom_bits, 0, (unsigned char*)a, 3);
+      } else {
+	if (/*e.target == XA_STRING &&*/ fl_selection_length[clipboard]) {
+	  if (e.target == fl_XaUtf8String ||
+	      e.target == XA_STRING ||
+	      e.target == fl_XaCompoundText ||
+	      e.target == fl_XaText ||
+	      e.target == fl_Xatextplain ||
+	      e.target == fl_Xatextplainutf ||
+	      e.target == fl_Xatextplainutf2) {
+	    // clobber the target type, this seems to make some applications
+	    // behave that insist on asking for XA_TEXT instead of UTF8_STRING
+	    // Does not change XA_STRING as that breaks xclipboard.
+	    if (e.target != XA_STRING) e.target = fl_XaUtf8String;
+	    XChangeProperty(fl_display, e.requestor, e.property,
+		            e.target, 8, 0,
+		            (unsigned char *)fl_selection_buffer[clipboard],
+		            fl_selection_length[clipboard]);
+	  }
+	} else {
+	  //    char* x = XGetAtomName(fl_display,e.target);
+	  //    fprintf(stderr,"selection request of %s\n",x);
+	  //    XFree(x);
+	  e.property = 0;
+	}
       }
-    } else {
-//    char* x = XGetAtomName(fl_display,e.target);
-//    fprintf(stderr,"selection request of %s\n",x);
-//    XFree(x);
-      e.property = 0;
+    } else { // image in clipboard
+      if (e.target == TARGETS) {
+	Atom a[1] = {fl_XaImageBmp};
+	XChangeProperty(fl_display, e.requestor, e.property,
+	                XA_ATOM, atom_bits, 0, (unsigned char*)a, 1);
+      } else {
+	if (e.target == fl_XaImageBmp && fl_selection_length[clipboard]) {
+	    XChangeProperty(fl_display, e.requestor, e.property,
+		            e.target, 8, 0,
+		            (unsigned char *)fl_selection_buffer[clipboard],
+		            fl_selection_length[clipboard]);
+	} else {
+	  //    char* x = XGetAtomName(fl_display,e.target);
+	  //    fprintf(stderr,"selection request of %s\n",x);
+	  //    XFree(x);
+	  e.property = 0;
+	}
+      }
     }
     XSendEvent(fl_display, e.requestor, 0, 0, (XEvent *)&e);}
     return 1;
@@ -1517,13 +1781,13 @@
       // Display * display ;
       // Bool detectable ;
       // Bool * supported_rtrn ;
-      // ...would be the easy way to corrct this isuue. Unfortunatly, this call is also
+      // ...would be the easy way to correct this issue. Unfortunately, this call is also
       // broken on many Unix distros including Ubuntu and Solaris (as of Dec 2009)
 
       // Bogus KeyUp events are generated by repeated KeyDown events. One
-      // neccessary condition is an identical key event pending right after
+      // necessary condition is an identical key event pending right after
       // the bogus KeyUp.
-      // The new code introduced Dec 2009 differs in that it only check the very
+      // The new code introduced Dec 2009 differs in that it only checks the very
       // next event in the queue, not the entire queue of events.
       // This function wrongly detects a repeat key if a software keyboard
       // sends a burst of events containing two consecutive equal keys. However,
Index: src/Fl_cocoa.mm
===================================================================
--- src/Fl_cocoa.mm	(revision 10113)
+++ src/Fl_cocoa.mm	(working copy)
@@ -41,10 +41,8 @@
 #include <FL/x.H>
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Tooltip.H>
-#include <FL/Fl_Menu_Item.H>
 #include <FL/Fl_Printer.H>
 #include <FL/Fl_Input_.H>
-#include <FL/Fl_Secret_Input.H>
 #include <FL/Fl_Text_Display.H>
 #include <stdio.h>
 #include <stdlib.h>
@@ -112,6 +110,9 @@
 static int got_events = 0;
 static Fl_Window* resize_from_system;
 static int main_screen_height; // height of menubar-containing screen used to convert between Cocoa and FLTK global screen coordinates
+// through_drawRect = YES means the drawRect: message was sent to the view, 
+// thus the graphics context was prepared by the system
+static BOOL through_drawRect = NO; 
 
 #if CONSOLIDATE_MOTION
 static Fl_Window* send_motion;
@@ -739,6 +740,7 @@
   return time;
 }
 
+
 /*
  * This public function handles all events. It wait a maximum of 
  * 'time' seconds for an event. This version returns 1 if events
@@ -768,8 +770,10 @@
   if (Fl::idle && !in_idle) // 'idle' may have been set within flush()
     time_to_wait = 0.0;
   double retval = fl_wait(time_to_wait);
-  if (fl_gc) CGContextFlush(fl_gc);
-  fl_gc = 0; // essential because the graphics context may be autoreleased
+  if (fl_gc) {
+    CGContextFlush(fl_gc);
+    fl_gc = 0;
+    }  
   [pool release];
   return retval;
 }
@@ -1454,16 +1458,6 @@
 
 
 /*
- * Initialize the given port for redraw and call the window's flush() to actually draw the content
- */ 
-void Fl_X::flush()
-{
-  w->flush();
-  if (fl_gc) CGContextFlush(fl_gc);
-  fl_gc = 0;
-}
-
-/*
  * Gets called when a window is created, resized, or deminiaturized
  */    
 static void handleUpdateEvent( Fl_Window *window ) 
@@ -1483,7 +1477,10 @@
       cx->region = 0;
     }
     cx->w->clear_damage(FL_DAMAGE_ALL);
+    CGContextRef gc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+    CGContextSaveGState(gc); // save original context
     cx->flush();
+    CGContextRestoreGState(gc); // restore original context
     cx->w->clear_damage();
   }
   window->clear_damage(FL_DAMAGE_ALL);
@@ -1750,6 +1747,8 @@
   BOOL need_handle; // YES means Fl::handle(FL_KEYBOARD,) is needed after handleEvent processing
   NSInteger identifier;
   NSRange selectedRange;
+  @public
+  Fl_X *fl_x_to_redraw; // set by Fl_X::flush() to the Fl_X object of the window to be redrawn
 }
 + (void)prepareEtext:(NSString*)aString;
 + (void)concatEtext:(NSString*)aString;
@@ -1795,15 +1794,19 @@
   if (self) {
     in_key_event = NO;
     identifier = ++counter;
+    fl_x_to_redraw = NULL;
     }
   return self;
 }
 - (void)drawRect:(NSRect)rect
 {
   fl_lock_function();
+  through_drawRect = YES;
   FLWindow *cw = (FLWindow*)[self window];
   Fl_Window *w = [cw getFl_Window];
-  handleUpdateEvent(w);
+  if (fl_x_to_redraw) fl_x_to_redraw->flush();
+  else handleUpdateEvent(w);
+  through_drawRect = NO;
   fl_unlock_function();
 }
 
@@ -2255,6 +2258,26 @@
 }
 
 /*
+ * Initialize the given port for redraw and call the window's flush() to actually draw the content
+ */ 
+void Fl_X::flush()
+{
+  if (through_drawRect || w->as_gl_window()) {
+    w->flush();
+    Fl_X::q_release_context();
+    return;
+  }
+  // have Cocoa immediately redraw the window's view
+  FLView *view = (FLView*)[fl_xid(w) contentView];
+  view->fl_x_to_redraw = this;
+  [view setNeedsDisplay:YES];
+  // will send the drawRect: message to the window's view after having prepared the adequate NSGraphicsContext
+  [view displayIfNeededIgnoringOpacity]; 
+  view->fl_x_to_redraw = NULL;
+}
+
+
+/*
  * go ahead, create that (sub)window
  */
 void Fl_X::make(Fl_Window* w)
@@ -2587,6 +2610,29 @@
 
 /*
  * make all drawing go into this window (called by subclass flush() impl.)
+ 
+ This can be called in 3 different instances:
+ 
+ 1) When a window is created, resized, or deminiaturized. 
+ The system sends the drawRect: message to the window's view after having prepared the current graphics context 
+ to draw to this view. Variable through_drawRect is YES, and fl_x_to_redraw is NULL. Processing of drawRect: calls 
+ handleUpdateEvent() that calls Fl_X::flush() for the window and its subwindows. Fl_X::flush() calls 
+ Fl_Window::flush() that calls Fl_Window::make_current() that only needs to identify the graphics port of the 
+ current graphics context. The window's draw() function is then executed.
+ 
+ 2) At each round of the FLTK event loop.
+ Fl::flush() is called, that calls Fl_X::flush() on each window that needs drawing. Fl_X::flush() sets 
+ fl_x_to_redraw to this and sends the displayIfNeededIgnoringOpacity message to the window's view. 
+ This message makes the system prepare the current graphics context adequately for drawing to this view, and 
+ send it the drawRect: message which sets through_drawRect to YES. Processing of the drawRect: message calls 
+ Fl_X::flush() for the window which proceeds as in 1) above.
+ 
+ 3) An FLTK application can call Fl_Window::make_current() at any time before it draws to a window.
+ This occurs for instance in the idle callback function of the mandelbrot test program. Variable through_drawRect is NO,
+ so Fl_Window::make_current() creates a new graphics context adequate for the window. 
+ Subsequent drawing requests go to this window. CAUTION: it's not possible to call Fl::wait(), Fl::check()
+ nor Fl::ready() while in the draw() function of a widget. Use an idle callback instead.
+ 
  */
 void Fl_Window::make_current() 
 {
@@ -2603,8 +2649,9 @@
     yp += win->y();
     win = (Fl_Window*)win->window();
   }
-  
-  i->gc = (CGContextRef)[[NSGraphicsContext graphicsContextWithWindow:fl_window] graphicsPort];
+  NSGraphicsContext *nsgc = through_drawRect ? [NSGraphicsContext currentContext] : 
+					       [NSGraphicsContext graphicsContextWithWindow:fl_window];
+  i->gc = (CGContextRef)[nsgc graphicsPort];
   fl_gc = i->gc;
   Fl_Region fl_window_region = XRectangleRegion(0,0,w(),h());
   if ( ! this->window() ) {
@@ -2720,8 +2767,8 @@
 }
 
 // clipboard variables definitions :
-char *fl_selection_buffer[2];
-int fl_selection_length[2];
+char *fl_selection_buffer[2] = {NULL, NULL};
+int fl_selection_length[2] = {0, 0};
 static int fl_selection_buffer_length[2];
 
 static PasteboardRef allocatePasteboard(void) 
@@ -2777,55 +2824,171 @@
   }
 }
 
-// Call this when a "paste" operation happens:
-void Fl::paste(Fl_Widget &receiver, int clipboard) {
-  if (clipboard) {
-    // see if we own the selection, if not go get it:
-    fl_selection_length[1] = 0;
-    
-    NSPasteboard *clip = [NSPasteboard generalPasteboard];
-    NSString *found = [clip availableTypeFromArray:[NSArray arrayWithObjects:utf8_format, @"public.utf16-plain-text", @"com.apple.traditional-mac-plain-text", nil]];
-    if (found) {
-      NSData *data = [clip dataForType:found];
-      if (data) {
-	NSInteger len;
-	char *aux_c = NULL;
-	if (![found isEqualToString:utf8_format]) {
-	  NSString *auxstring;
-	  auxstring = (NSString *)CFStringCreateWithBytes(NULL, 
-							  (const UInt8*)[data bytes], 
-							  [data length],
-							  [found isEqualToString:@"public.utf16-plain-text"] ? kCFStringEncodingUnicode : kCFStringEncodingMacRoman,
-							  false);
-	  aux_c = strdup([auxstring UTF8String]);
-	  [auxstring release];
-	  len = strlen(aux_c) + 1;
-	}
-	else len = [data length] + 1;
-        if ( len >= fl_selection_buffer_length[1] ) {
-          fl_selection_buffer_length[1] = len;
-          delete[] fl_selection_buffer[1];
-          fl_selection_buffer[1] = new char[len];
-        }
-	if (![found isEqualToString:utf8_format]) {
-	  strcpy(fl_selection_buffer[1], aux_c);
-	  free(aux_c);
+static int get_plain_text_from_clipboard(char **buffer, int previous_length)
+{
+  NSInteger length = 0;
+  NSPasteboard *clip = [NSPasteboard generalPasteboard];
+  NSString *found = [clip availableTypeFromArray:[NSArray arrayWithObjects:utf8_format, @"public.utf16-plain-text", @"com.apple.traditional-mac-plain-text", nil]];
+  if (found) {
+    NSData *data = [clip dataForType:found];
+    if (data) {
+      NSInteger len;
+      char *aux_c = NULL;
+      if (![found isEqualToString:utf8_format]) {
+	NSString *auxstring;
+	auxstring = (NSString *)CFStringCreateWithBytes(NULL, 
+							(const UInt8*)[data bytes], 
+							[data length],
+							[found isEqualToString:@"public.utf16-plain-text"] ? kCFStringEncodingUnicode : kCFStringEncodingMacRoman,
+							false);
+	aux_c = strdup([auxstring UTF8String]);
+	[auxstring release];
+	len = strlen(aux_c) + 1;
+      }
+      else len = [data length] + 1;
+      if ( len >= previous_length ) {
+	length = len;
+	delete[] *buffer;
+	*buffer = new char[len];
+      }
+      if (![found isEqualToString:utf8_format]) {
+	strcpy(*buffer, aux_c);
+	free(aux_c);
+      }
+      else {
+	[data getBytes:*buffer];
+      }
+      (*buffer)[len - 1] = 0;
+      length = len - 1;
+      convert_crlf(*buffer, len - 1); // turn all \r characters into \n:
+      Fl::e_clipboard_type = Fl::clipboard_plain_text;
+    }
+  }    
+  return length;
+}
+
+static Fl_Image* get_image_from_clipboard()
+{
+  Fl_RGB_Image *image = NULL;
+  uchar *imagedata;
+  NSBitmapImageRep *bitmap;
+  NSPasteboard *clip = [NSPasteboard generalPasteboard];
+  NSArray *present = [clip types]; // types in pasteboard in order of decreasing preference
+  NSArray  *possible = [NSArray arrayWithObjects:@"com.adobe.pdf", @"public.tiff", @"com.apple.pict", nil];
+  NSString *found = nil;
+  NSUInteger rank;
+  for (rank = 0; rank < [present count]; rank++) { // find first of possible types present in pasteboard
+    for (NSUInteger i = 0; i < [possible count]; i++) {
+      if ([[present objectAtIndex:rank] isEqualToString:[possible objectAtIndex:i]]) {
+	found = [present objectAtIndex:rank];
+	goto after_loop;
+      }
+    }
+  }
+after_loop: 
+  if (found) {
+    NSData *data = [clip dataForType:found];
+    if (data) {
+      if ([found isEqualToString:@"public.tiff"]) {
+	bitmap = [NSBitmapImageRep imageRepWithData:data];
+	int bpp = [bitmap bytesPerPlane];
+	int bpr = [bitmap bytesPerRow];
+	int depth = [bitmap samplesPerPixel], w = bpr/depth, h = bpp/bpr;
+	imagedata = new uchar[w * h * depth];
+	memcpy(imagedata, [bitmap bitmapData], w * h * depth);
+	image = new Fl_RGB_Image(imagedata, w, h, depth);
+	image->alloc_array = 1;
+      }
+      else if ([found isEqualToString:@"com.adobe.pdf"] || [found isEqualToString:@"com.apple.pict"]) {
+	NSRect rect;
+	NSImageRep *vectorial;
+	NSAffineTransform *dilate = [NSAffineTransform transform];
+	if ([found isEqualToString:@"com.adobe.pdf"] ) {
+	  vectorial = [NSPDFImageRep imageRepWithData:data];
+	  rect = [(NSPDFImageRep*)vectorial bounds]; // in points =  1/72 inch
+	  Fl_Window *win = Fl::first_window();
+	  int screen_num = win ? Fl::screen_num(win->x(), win->y(), win->w(), win->h()) : 0;
+	  float hr, vr;
+	  Fl::screen_dpi(hr, vr, screen_num); // 1 inch = hr pixels = 72 points -> hr/72 pixel/point	  
+	  CGFloat scale = hr/72;
+	  [dilate scaleBy:scale];
+	  rect.size.width *= scale;
+	  rect.size.height *= scale;
+	  rect = NSIntegralRect(rect);
 	  }
 	else {
-	  [data getBytes:fl_selection_buffer[1]];
+	  vectorial = [NSPICTImageRep imageRepWithData:data];
+	  rect = [(NSPICTImageRep*)vectorial boundingBox]; // in pixel, no scaling required
 	  }
-	fl_selection_buffer[1][len - 1] = 0;
-	fl_selection_length[1] = len - 1;
-        convert_crlf(fl_selection_buffer[1], len - 1); // turn all \r characters into \n:
+	imagedata = new uchar[(int)(rect.size.width * rect.size.height) * 4];
+	memset(imagedata, -1, (int)(rect.size.width * rect.size.height) * 4);
+	bitmap = [[NSBitmapImageRep alloc]  initWithBitmapDataPlanes:&imagedata
+							  pixelsWide:rect.size.width
+							  pixelsHigh:rect.size.height
+						       bitsPerSample:8
+						     samplesPerPixel:3
+							    hasAlpha:NO
+							    isPlanar:NO
+						      colorSpaceName:NSDeviceRGBColorSpace
+							 bytesPerRow:rect.size.width*4
+							bitsPerPixel:32];
+	NSDictionary *dict = [NSDictionary dictionaryWithObject:bitmap 
+							 forKey:NSGraphicsContextDestinationAttributeName];
+	NSGraphicsContext *oldgc = [NSGraphicsContext currentContext];
+	[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithAttributes:dict]];
+	[dilate concat];
+	[vectorial draw];
+	[NSGraphicsContext setCurrentContext:oldgc];
+	[bitmap release];
+	image = new Fl_RGB_Image(imagedata, rect.size.width, rect.size.height, 4);
+	image->alloc_array = 1;
       }
-    }    
+      Fl::e_clipboard_type = Fl::clipboard_image;
+    }
   }
+  return image;
+}
+
+// Call this when a "paste" operation happens:
+void Fl::paste(Fl_Widget &receiver, int clipboard, const char *type) {
+  if (type[0] == 0) type = Fl::clipboard_plain_text;
+  if (clipboard) {
+    Fl::e_clipboard_type = "";
+   if (strcmp(type, Fl::clipboard_plain_text) == 0) {
+      fl_selection_length[1] = get_plain_text_from_clipboard( &fl_selection_buffer[1],  fl_selection_length[1]);   
+      }
+    else if (strcmp(type, Fl::clipboard_image) == 0) {
+      Fl::e_clipboard_data = get_image_from_clipboard( );
+      if (Fl::e_clipboard_data) {
+	int done = receiver.handle(FL_PASTE);
+	Fl::e_clipboard_type = "";
+	if (done == 0) {
+	  delete (Fl_Image*)Fl::e_clipboard_data;
+	  Fl::e_clipboard_data = NULL;
+	}
+      }
+      return;
+      }
+    else
+      fl_selection_length[1] = 0;
+  }
   Fl::e_text = fl_selection_buffer[clipboard];
   Fl::e_length = fl_selection_length[clipboard];
-  if (!Fl::e_text) Fl::e_text = (char *)"";
+  if (!Fl::e_length) Fl::e_text = (char *)"";
   receiver.handle(FL_PASTE);
 }
 
+int Fl::clipboard_contains(const char *type) {
+  NSString *found = nil;
+  if (strcmp(type, Fl::clipboard_plain_text) == 0) {
+    found = [[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:utf8_format, @"public.utf16-plain-text", @"com.apple.traditional-mac-plain-text", nil]];
+    }
+  else if (strcmp(type, Fl::clipboard_image) == 0) {
+    found = [[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:@"public.tiff", @"com.adobe.pdf", @"com.apple.pict", nil]];
+    }
+  return found != nil;
+}
+
 int Fl_X::unlink(Fl_X *start) {
   if (start) {
     Fl_X *pc = start;
@@ -2980,19 +3143,19 @@
   else 
 #endif
     {
-    unsigned char *pdata = (unsigned char *)CGBitmapContextGetData(c);
-    NSBitmapImageRep *imagerep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pdata
-									 pixelsWide:CGBitmapContextGetWidth(c)
-									 pixelsHigh:CGBitmapContextGetHeight(c)
-								      bitsPerSample:8
-								    samplesPerPixel:4
-									   hasAlpha:YES
-									   isPlanar:NO
-								     colorSpaceName:NSDeviceRGBColorSpace
-									bytesPerRow:CGBitmapContextGetBytesPerRow(c)
-								       bitsPerPixel:CGBitmapContextGetBitsPerPixel(c)];
-    image = [[NSImage alloc] initWithData: [imagerep TIFFRepresentation]];
-    [imagerep release];
+      unsigned char *pdata = (unsigned char *)CGBitmapContextGetData(c);
+      NSBitmapImageRep *imagerep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pdata
+									   pixelsWide:CGBitmapContextGetWidth(c)
+									   pixelsHigh:CGBitmapContextGetHeight(c)
+									bitsPerSample:8
+								      samplesPerPixel:4
+									     hasAlpha:YES
+									     isPlanar:NO
+								       colorSpaceName:NSDeviceRGBColorSpace
+									  bytesPerRow:CGBitmapContextGetBytesPerRow(c)
+									 bitsPerPixel:CGBitmapContextGetBitsPerPixel(c)];
+      image = [[NSImage alloc] initWithData: [imagerep TIFFRepresentation]];
+      [imagerep release];
     }
   return [image autorelease];
 }
@@ -3080,7 +3243,7 @@
 }
 //#include <FL/Fl_PostScript.H>
 - (void)printPanel
-{
+{  
   Fl_Printer printer;
   //Fl_PostScript_File_Device printer;
   int w, h, ww, wh;
@@ -3329,16 +3492,26 @@
 static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, int w, int h)
 // the returned value is autoreleased
 {
+  NSRect rect;
+  NSView *winview = nil;
   while (win->window()) {
     x += win->x();
     y += win->y();
     win = win->window();
   }
-  NSRect rect = NSMakeRect(x, win->h()-(y+h), w, h);
-  NSView *currentview = [fl_xid(win) contentView];
-  [currentview lockFocus];
+  if ( through_drawRect ) {
+    CGFloat epsilon = 0;
+    if (fl_mac_os_version >= 100600) epsilon = 0.5; // STR #2887
+    rect = NSMakeRect(x - epsilon, y - epsilon, w, h);
+    }
+  else {
+    rect = NSMakeRect(x, win->h()-(y+h), w, h);
+    // lock focus to win's view
+    winview = [fl_xid(win) contentView];
+    [winview lockFocus];
+    }
   NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:rect] autorelease];
-  [currentview unlockFocus];
+  if ( !through_drawRect ) [winview unlockFocus];
   return bitmap;
 }
 
@@ -3472,7 +3645,7 @@
       [title_s drawWithRect:r options:0 attributes:attr]; // 10.4
       [[NSGraphicsContext currentContext] setShouldAntialias:NO];
       [NSGraphicsContext setCurrentContext:current];
-      }
+    }
     else {
       fl_font(FL_HELVETICA, 14); // the exact font is LucidaGrande 13 pts
       fl_color(FL_BLACK);
@@ -3481,8 +3654,8 @@
       fl_push_clip(x_offset, y_offset, win->w(), bt);
       fl_draw(title, x, y_offset+bt/2+4);
       fl_pop_clip();
-      }
     }
+  }
   this->print_widget(win, x_offset, y_offset + bt); // print the window inner part
 }
 
Index: src/Fl.cxx
===================================================================
--- src/Fl.cxx	(revision 10113)
+++ src/Fl.cxx	(working copy)
@@ -104,6 +104,8 @@
 
 char		*Fl::e_text = (char *)"";
 int		Fl::e_length;
+const char*	Fl::e_clipboard_type = "";
+void *		Fl::e_clipboard_data = NULL;
 
 Fl_Event_Dispatch Fl::e_dispatch = 0;
 
@@ -118,6 +120,9 @@
 
 #endif // FL_DOXYGEN
 
+char const * const Fl::clipboard_plain_text = "text/plain";
+char const * const Fl::clipboard_image = "image";
+
 //
 // 'Fl::version()' - Return the API version number...
 //
@@ -1605,12 +1610,18 @@
 
 /** Backward compatibility only.
   This calls Fl::paste(receiver, 0);
-  \see Fl::paste(Fl_Widget &receiver, int clipboard)
+  \see Fl::paste(Fl_Widget &receiver, int clipboard, const char* type)
 */
 void Fl::paste(Fl_Widget &receiver) {
   Fl::paste(receiver, 0);
 }
-
+#if FLTK_ABI_VERSION >= 10303
+#elif !defined(FL_DOXYGEN)
+void Fl::paste(Fl_Widget &receiver, int source)
+{
+  Fl::paste(receiver, source, Fl::clipboard_plain_text);
+}
+#endif
 ////////////////////////////////////////////////////////////////
 
 #include <FL/fl_draw.H>
Index: FL/Fl.H
===================================================================
--- FL/Fl.H	(revision 10113)
+++ FL/Fl.H	(working copy)
@@ -137,6 +137,8 @@
   static int e_keysym;
   static char* e_text;
   static int e_length;
+  static void *e_clipboard_data;
+  static const char *e_clipboard_type;
   static Fl_Event_Dispatch e_dispatch;
   static Fl_Widget* belowmouse_;
   static Fl_Widget* pushed_;
@@ -151,7 +153,9 @@
   static void reset_marked_text(); // resets marked text
   static void insertion_point_location(int x, int y, int height); // sets window coordinates & height of insertion point
 #endif
-#endif
+#endif // FL_DOXYGEN
+  
+  
   /**
     If true then flush() will do something.
   */
@@ -724,7 +728,17 @@
     you paste a nul character.
   */
   static int event_length() {return e_length;}
+  
+  /** During an FL_PASTE event of non-textual data, returns a pointer to the pasted data.
+   The returned data is an Fl_Image * when the result of Fl::event_clipboard_type() is Fl::clipboard_image.
+   */
+  static void *event_clipboard() { return e_clipboard_data; }
+  /** Returns the type of the pasted data during an FL_PASTE event.
+   This type can be Fl::clipboard_plain_text or Fl::clipboard_image.
+   */
+  static const char *event_clipboard_type() {return e_clipboard_type; }
 
+
   static int compose(int &del);
   static void compose_reset();
   static int event_inside(int,int,int,int);
@@ -763,14 +777,26 @@
   The selection buffer is used for
   middle-mouse pastes and for drag-and-drop selections. The 
   clipboard is used for traditional copy/cut/paste operations.
+   
+   \note This function is intended only to copy UTF-8 encoded textual data.
+   To copy graphical data, use the Fl_Copy_Surface class.
   */
   static void copy(const char* stuff, int len, int destination = 0); // platform dependent
+#if !(defined(__APPLE__) || defined(WIN32) || defined(FL_DOXYGEN))
+  static void copy_image(const unsigned char* data, int W, int H, int destination = 0); // platform dependent
+#endif
   /**
   Pastes the data from the selection buffer (\p source is 0) or the clipboard 
-  (\p source is 1) into \p receiver.  
-  Set things up so the receiver widget will be called with an FL_PASTE event some
-  time in the future with the data from the specified \p source in Fl::event_text()
-  and the number of characters in Fl::event_length().
+  (\p source is 1) into \p receiver.  If \p source is 1,
+  the optional \p type argument indicates what type of data is requested from the clipboard
+  (at present, Fl::clipboard_plain_text - requesting text data - and 
+  Fl::clipboard_image - requesting image data - are possible).
+  Set things up so the handle function of the \p receiver widget will be called with an FL_PASTE event some
+  time in the future if the clipboard does contain data of the requested type. During processing of this event,
+  and if \p type is Fl::clipboard_plain_text, the text data from the specified \p source are in Fl::event_text()
+  with UTF-8 encoding, and the number of characters in Fl::event_length();
+  if \p type is Fl::clipboard_image, Fl::event_clipboard() returns a pointer to the
+  image data, as an Fl_Image *.
   The receiver
   should be prepared to be called \e directly by this, or for
   it to happen \e later, or possibly <i>not at all</i>.  This
@@ -782,7 +808,12 @@
   drag-and-drop selections. The clipboard is used for traditional 
   copy/cut/paste operations.
   */
-  static void paste(Fl_Widget &receiver, int source /*=0*/); // platform dependent
+#if FLTK_ABI_VERSION >= 10303 || defined(FL_DOXYGEN)
+  static void paste(Fl_Widget &receiver, int source, const char *type = Fl::clipboard_plain_text); // platform dependent
+#else
+  static void paste(Fl_Widget &receiver, int source, const char *type);
+  static void paste(Fl_Widget &receiver, int source /*=0*/);
+#endif
   /**
   FLTK will call the registered callback whenever there is a change to the
   selection buffer or the clipboard. The source argument indicates which
@@ -810,6 +841,17 @@
   buffer or the clipboard.
   */
   static void remove_clipboard_notify(Fl_Clipboard_Notify_Handler h);
+  /** Returns non 0 if the clipboard contains data matching \p type.
+   \p type can be Fl::clipboard_plain_text or Fl::clipboard_image.
+   */
+  static int clipboard_contains(const char *type);
+  /**  Denotes plain textual data
+   */
+  static char const * const clipboard_plain_text;
+  /**  Denotes image data
+   */
+  static char const * const clipboard_image;
+
   /**
     Initiate a Drag And Drop operation. The selection buffer should be
     filled with relevant data before calling this method. FLTK will
Index: FL/Fl_Copy_Surface.H
===================================================================
--- FL/Fl_Copy_Surface.H	(revision 0)
+++ FL/Fl_Copy_Surface.H	(revision 0)
@@ -0,0 +1,114 @@
+#ifndef Fl_Copy_Surface_H
+#define Fl_Copy_Surface_H
+
+#include <FL/Fl_Paged_Device.H>
+#include <FL/Fl_Printer.H>
+
+#if defined(__APPLE__)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+/** Supports copying of graphical data to the clipboard.
+ 
+ <br> After creation of an Fl_Copy_Surface object, call set_current() on it, and all subsequent graphics requests
+ will be recorded in the clipboard. It's possible to draw widgets (using Fl_Copy_Surface::draw()
+ ) or to use any of the \ref fl_drawings or the \ref fl_attributes.
+ Finally, delete the Fl_Copy_Surface object to load the clipboard with the graphical data.
+ <br> Fl_GL_Window 's can be copied to the clipboard as well. 
+ <br> Usage example:
+ \code
+ Fl_Widget *g = ...; // a widget you want to copy to the clipboard
+ Fl_Copy_Surface *copy_surf = new Fl_Copy_Surface(g->w(), g->h()); // create an Fl_Copy_Surface object
+ copy_surf->set_current(); // direct graphics requests to the clipboard
+ fl_color(FL_WHITE); fl_rectf(0, 0, g->w(), g->h()); // draw a white background
+ copy_surf->draw(g); // draw the g widget in the clipboard
+ delete copy_surf; // after this, the clipboard is loaded
+ Fl_Display_Device::display_device()->set_current();  // direct graphics requests back to the display
+ \endcode
+ Platform details:
+ \li MSWindows: Transparent RGB images copy without transparency.
+ The graphical data is copied to the clipboard as an 'enhanced metafile'.
+ \li Mac OS: Mac OS X 10.4 or higher is necessary. The graphical data is copied to the 
+ clipboard (a.k.a. pasteboard) in 2 'flavors': 
+ 1) in vectorial form as PDF data; 2) in bitmap form as a TIFF image. Applications to which the 
+ clipboard content is pasted can use the flavor that suits them best.
+ \li X11: the graphical data is copied to the clipboard as an image in BMP format.
+*/
+class Fl_Copy_Surface : public Fl_Surface_Device {
+private:
+  int width;
+  int height;
+  Fl_Paged_Device *helper;
+#ifdef __APPLE__
+  CFMutableDataRef pdfdata;
+  CGContextRef oldgc;
+  CGContextRef gc;
+  void prepare_copy_pdf_and_tiff(int w, int h);
+  void complete_copy_pdf_and_tiff();
+  void init_PDF_context(int w, int h);
+  static size_t MyPutBytes(void* info, const void* buffer, size_t count);
+#elif defined(WIN32)
+  HDC oldgc;
+  HDC gc;
+#else // Xlib
+  Fl_Offscreen xid;
+  Window oldwindow;
+  Fl_Surface_Device *_ss;
+#endif
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_Copy_Surface(int w, int h);
+  ~Fl_Copy_Surface();
+  void set_current();
+  void draw(Fl_Widget* widget, int delta_x = 0, int delta_y = 0);
+};
+
+#if defined(__APPLE__)
+
+/* Mac class to reimplement Fl_Paged_Device::printable_rect() */
+class Fl_Quartz_Surface : public Fl_System_Printer {
+protected:
+  int width;
+  int height;
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_Quartz_Surface(int w, int h);
+  virtual int printable_rect(int *w, int *h);
+  virtual ~Fl_Quartz_Surface() {};
+};
+
+#elif defined(WIN32)
+
+/* Win class to implement translate()/untranslate() */
+class Fl_GDI_Surface : public Fl_Paged_Device {
+  int width;
+  int height;
+  int depth;
+  POINT origins[10];
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_GDI_Surface();
+  virtual void translate(int x, int y);
+  virtual void untranslate();
+  virtual ~Fl_GDI_Surface();
+};
+
+#elif !defined(FL_DOXYGEN)
+
+/* Xlib class to implement translate()/untranslate() */
+class Fl_Xlib_Surface : public Fl_Paged_Device {
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_Xlib_Surface();
+  virtual void translate(int x, int y);
+  virtual void untranslate();
+  virtual ~Fl_Xlib_Surface();
+};
+
+#endif
+
+#endif // Fl_Copy_Surface_H
Index: FL/Fl_Image_Surface.H
===================================================================
--- FL/Fl_Image_Surface.H	(revision 0)
+++ FL/Fl_Image_Surface.H	(revision 0)
@@ -0,0 +1,67 @@
+#ifndef Fl_Image_Surface_H
+#define Fl_Image_Surface_H
+
+#include <FL/Fl_Copy_Surface.H>
+#include <FL/Fl_Image.H>
+
+
+/** Directs all graphics requests to an Fl_Image.
+ 
+ After creation of an Fl_Image_Surface object, call set_current() on it, and all subsequent graphics requests
+ will be recorded in the image. It's possible to draw widgets (using Fl_Image_Surface::draw()) 
+ or to use any of the \ref fl_drawings or the \ref fl_attributes.
+ Finally, call image() on the object to obtain a newly allocated Fl_Image object.
+ <br> Fl_GL_Window objects can be drawn in the image as well. 
+ 
+ <br> Usage example:
+ \code
+ Fl_Widget *g = ...; // a widget you want to draw in an image
+ Fl_Image_Surface *img_surf = new Fl_Image_Surface(g->w(), g->h()); // create an Fl_Image_Surface object
+ img_surf->set_current(); // direct graphics requests to the image
+ fl_color(FL_WHITE); fl_rectf(0, 0, g->w(), g->h()); // draw a white background
+ img_surf->draw(g); // draw the g widget in the image
+ Fl_Image* image = img_surf->image(); // get the resulting image
+ delete img_surf; // delete the img_surf object
+ Fl_Display_Device::display_device()->set_current();  // direct graphics requests back to the display
+ \endcode
+*/
+class Fl_Image_Surface : public Fl_Surface_Device {
+private:
+  Fl_Offscreen offscreen;
+  int width;
+  int height;
+  Fl_Paged_Device *helper;
+#ifdef __APPLE__
+#elif defined(WIN32)
+  HDC _sgc; 
+  Window _sw; 
+  Fl_Surface_Device *_ss;
+  int _savedc;
+#else
+  Fl_Surface_Device *previous;
+  Window pre_window;
+#endif
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_Image_Surface(int w, int h);
+  ~Fl_Image_Surface();
+  void set_current();
+  void draw(Fl_Widget*, int delta_x = 0, int delta_y = 0);
+  Fl_Image *image();
+};
+
+#ifdef __APPLE__
+/* Mac class to implement translate()/untranslate() for a flipped bitmap graphics context */
+class Fl_Quartz_Flipped_Surface : public Fl_Quartz_Surface {
+public:
+  static const char *class_id;
+  const char *class_name() {return class_id;};
+  Fl_Quartz_Flipped_Surface(int w, int h);
+  void translate(int x, int y);
+  void untranslate();
+  virtual ~Fl_Quartz_Flipped_Surface() {};
+};
+#endif 
+
+#endif // Fl_Image_Surface_H
Index: test/clipboard.cxx
===================================================================
--- test/clipboard.cxx	(revision 0)
+++ test/clipboard.cxx	(revision 0)
@@ -0,0 +1,146 @@
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Image.H>
+#include <FL/Fl_Text_Buffer.H>
+#include <FL/Fl_Text_Display.H>
+#include <FL/Fl_Tabs.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+
+/* Displays and follows the content of the clipboard with either image or text data
+ */
+
+Fl_Box *image_box;
+Fl_Box *image_size;
+Fl_Text_Display *display;
+
+class chess : public Fl_Box { // a box with a chess-like pattern below its image
+public:
+  chess(int x, int y, int w, int h) : Fl_Box(FL_FLAT_BOX,x,y,w,h,0) {
+    align(FL_ALIGN_CENTER | FL_ALIGN_CLIP);
+  }
+  void draw() {
+    draw_box();
+    Fl_Image *im = image();
+    if (im) { // draw the chess pattern below the box centered image
+      int X = x() + (w()-im->w())/2, Y = y() + (h()-im->h())/2, W = im->w(), H = im->h();
+      fl_push_clip(X,Y,W,H);
+      fl_push_clip(x(),y(),w(),h());
+      fl_color(FL_WHITE); fl_rectf(X,Y,W,H);
+      fl_color(FL_LIGHT2);
+      const int side = 4, side2 = 2*side;
+      for (int j=Y; j<Y+H; j+=side) {
+	for (int i=X + (j-Y)%side2; i<X+W; i+=side2) {
+	  fl_rectf(i,j,side,side);
+	}
+      }
+      fl_pop_clip();
+      fl_pop_clip();
+      }
+    draw_label(); // draw the box image
+  }
+} *chess_obj;
+
+class clipboard_viewer : public Fl_Tabs { // use tabs to display as appropriate the image or textual content of the clipboard
+public:
+  clipboard_viewer(int x, int y, int w, int h) : Fl_Tabs(x,y,w,h) {};
+  virtual int handle(int event) {
+    if (event != FL_PASTE) return Fl_Tabs::handle(event);
+    if (strcmp(Fl::event_clipboard_type(), Fl::clipboard_image) == 0) { // an image is being pasted
+      Fl_Image *im = (Fl_Image*)Fl::event_clipboard(); // get it as an Fl_Image object
+      if (!im) return 1;
+      char title[300];
+      sprintf(title, "%dx%d",im->w(), im->h()); // display the image original size
+#ifdef WIN32
+      OpenClipboard(NULL); // display extra technical info about clipboard content
+      char *p=title + strlen(title);
+      int format = EnumClipboardFormats(0);
+      if (format && format < CF_MAX) { sprintf(p, " %d",format); p += strlen(p); }
+      while (format) {
+	format = EnumClipboardFormats(format);
+	if (format && format < CF_MAX) { sprintf(p, " %d",format); p += strlen(p); }
+      }
+      HANDLE h;
+      if (h = GetClipboardData(CF_DIB)) {
+	LPBITMAPINFO lpBI = (LPBITMAPINFO)GlobalLock(h);
+	sprintf(p, " biBitCount=%d biCompression=%d biClrUsed=%d",
+		lpBI->bmiHeader.biBitCount, lpBI->bmiHeader.biCompression, lpBI->bmiHeader.biClrUsed);
+	}
+      CloseClipboard();
+#endif
+      float scale_x =  (float)im->w() / image_box->w(); // rescale the image if larger than the display box
+      float scale_y =  (float)im->h() / image_box->h();
+      float scale = scale_x;
+      if (scale_y > scale) scale = scale_y;
+      if (scale > 1) {
+	Fl_Image *im2 = im->copy(im->w()/scale, im->h()/scale);
+	delete im;
+	im = im2;
+	}
+      Fl_Image *oldim = image_box->image();
+      if (oldim) delete oldim;
+      image_box->image(im); // show the scaled image
+      image_size->copy_label(title);
+      value(image_box->parent());
+      window()->redraw();
+      }
+    else { // text is being pasted
+      display->buffer()->text(Fl::event_text());
+      value(display);
+      display->redraw();
+      }
+    return 1;
+    }
+} *tabs;
+
+
+void cb(Fl_Widget *wid, clipboard_viewer *tabs)
+{
+  if (Fl::clipboard_contains(Fl::clipboard_image)) {
+    Fl::paste(*tabs, 1, Fl::clipboard_image); // try to find image in the clipboard
+    return;
+    }
+  if (Fl::clipboard_contains(Fl::clipboard_plain_text)) Fl::paste(*tabs, 1, Fl::clipboard_plain_text); // also try to find text
+}
+
+void clip_callback(int source, void *data) { // called after clipboard was changed or at application activation
+  if ( source == 1 ) cb(NULL, (clipboard_viewer *)data);
+}
+
+int main()
+{
+#if !(defined(__APPLE__) || defined(WIN32))
+  extern void fl_register_images();
+  fl_register_images(); // required to allow pasting of images
+#endif
+  Fl_Window* win = new Fl_Window(500, 550, "clipboard viewer");
+  tabs = new clipboard_viewer(0, 0, 500, 500);
+  Fl_Group *g = new Fl_Group( 5, 30, 490, 460, Fl::clipboard_image); // g will display the image form
+  g->box(FL_FLAT_BOX);
+  image_box = new chess(5, 30, 490, 450);
+  image_size = new Fl_Box(FL_NO_BOX, 5, 485, 490, 10, 0);
+  g->end();
+  g->selection_color(FL_INACTIVE_COLOR);
+  
+  Fl_Text_Buffer *buffer = new Fl_Text_Buffer();
+  display = new Fl_Text_Display(5,30,490, 460, Fl::clipboard_plain_text); // display will display the text form
+  display->buffer(buffer);
+  display->selection_color(FL_INACTIVE_COLOR);
+  tabs->end();
+  tabs->resizable(display);
+  
+  Fl_Group *g2 = new Fl_Group( 10,510,200,25);
+  Fl_Button *refresh = new Fl_Button(10,510,200,25, "Refresh from clipboard");
+  refresh->callback((Fl_Callback*)cb, tabs);
+  g2->end();
+  g2->resizable(NULL);
+  win->end();
+  win->resizable(tabs);
+  win->show();
+#if defined(__APPLE__) || defined(WIN32)
+  clip_callback(1, tabs); // use clipboard content at start
+#endif
+  Fl::add_clipboard_notify(clip_callback, tabs); // will update with new clipboard content immediately or at application activation
+  return Fl::run();
+}
Index: test/Makefile
===================================================================
--- test/Makefile	(revision 10113)
+++ test/Makefile	(working copy)
@@ -31,6 +31,7 @@
 	buttons.cxx \
 	cairo_test.cxx \
 	checkers.cxx \
+	clipboard.cxx \
 	clock.cxx \
 	colbrowser.cxx \
 	color_chooser.cxx \
@@ -106,6 +107,7 @@
 	buttons$(EXEEXT) \
 	cairo_test$(EXEEXT) \
 	checkers$(EXEEXT) \
+	clipboard$(EXEEXT) \
 	clock$(EXEEXT) \
 	colbrowser$(EXEEXT) \
 	color_chooser$(EXEEXT) \
@@ -304,6 +306,8 @@
 	$(CXX) $(ARCHFLAGS) $(CXXFLAGS) $(LDFLAGS) checkers.o -o $@ $(LINKFLTK) $(LDLIBS)
 	$(OSX_ONLY) $(INSTALL_BIN) checkers$(EXEEXT) checkers.app/Contents/MacOS
 
+clipboard$(EXEEXT): clipboard.o
+
 clock$(EXEEXT): clock.o
 
 colbrowser$(EXEEXT): colbrowser.o
Index: test/device.cxx
===================================================================
--- test/device.cxx	(revision 10113)
+++ test/device.cxx	(working copy)
@@ -21,6 +21,7 @@
 
 #include <FL/Fl_Overlay_Window.H>
 #include <FL/Fl_Light_Button.H>
+#include <FL/Fl_Radio_Round_Button.H>
 #include <FL/fl_draw.H>
 #include <FL/Fl_Clock.H>
 #include "pixmaps/porsche.xpm"
@@ -30,9 +31,9 @@
 
 
 #include <FL/Fl_Printer.H>
+#include <FL/Fl_Copy_Surface.H>
+#include <FL/Fl_Image_Surface.H>
 
-//#include "fl_printer_chooser.H"
-
 #include <FL/Fl_File_Chooser.H>
 #include <FL/fl_draw.H>
 
@@ -551,17 +552,47 @@
 }
 
 
-void print(Fl_Widget *, void *w) {
-  Fl_Widget * g = (Fl_Widget *)w;
+Fl_Widget *target;
+const  char *operation;
+
+void copy(Fl_Widget *, void *data) {
+  if (strcmp(operation, "Fl_Image_Surface") == 0) {
+    Fl_Image_Surface *rgb_surf = new Fl_Image_Surface(target->w()+20, target->h()+10);
+    rgb_surf->set_current();
+    fl_color(FL_BLUE);fl_rectf(0,0,1000,1000);
+    rgb_surf->draw(target,10,5);
+    Fl_Image *img = rgb_surf->image();
+    delete rgb_surf;
+    Fl_Display_Device::display_device()->set_current();
+    Fl_Window* g2 = new Fl_Window(img->w(), img->h());
+    Fl_Box *b = new Fl_Box(FL_NO_BOX,0,0,img->w(), img->h(),0);
+    b->image(img);
+    g2->end();
+    g2->show();
+    return;
+  }
   
-  Fl_Printer * p = new Fl_Printer();
-  if (!p->start_job(1)) {
-    p->start_page();
-    p->print_window(g->window());
-    p->end_page();
-    p->end_job();
+  
+  if (strcmp(operation, "Fl_Copy_Surface") == 0) {
+    Fl_Copy_Surface *copy_surf = new Fl_Copy_Surface(target->w()+10, target->h()+20);
+    copy_surf->set_current();
+    fl_color(FL_YELLOW);fl_rectf(0,0,1000,1000);
+    copy_surf->draw(target, 5, 10);
+    delete copy_surf;
+    Fl_Display_Device::display_device()->set_current();  
+    }
+  
+  if (strcmp(operation, "Fl_Printer") == 0) {
+    Fl_Printer * p = new Fl_Printer();
+    if (!p->start_job(1)) {
+      p->start_page();
+      if (target->as_window()) p->print_window(target->as_window());
+      else p->print_widget(target);
+      p->end_page();
+      p->end_job();
+    }
+    delete p;
   }
-  delete p;
 }
 
 /*void print2(Fl_Widget *, void *w) {
@@ -598,6 +629,16 @@
 };
 
 
+void target_cb(Fl_Widget* wid, void *data)
+{
+  target = (Fl_Widget*)data;
+}
+
+void operation_cb(Fl_Widget* wid, void *data)
+{
+  operation = wid->label();
+}
+
 int main(int argc, char ** argv) {
   
   //Fl::scheme("plastic");
@@ -650,7 +691,8 @@
   
   //Fl_Button but7(, 480, 120, 30, "Engraved box");
   //but7.box(FL_ENGRAVED_BOX);
-  { Fl_Group* o = new Fl_Group(360, 495, 120, 40);
+  Fl_Group *group;
+  { Fl_Group* o = new Fl_Group(360, 495, 120, 40); group=o;
     o->box(FL_UP_BOX);
     { Fl_Group* o = new Fl_Group(365, 500, 110, 30);
       o->box(FL_THIN_UP_FRAME);
@@ -673,12 +715,27 @@
   tx.hide();
   
   c2->end();
-  Fl_Button *b4 = new Fl_Button(10,5, 150, 25, "Print");
-  b4->callback(print,c2);
-  /*Fl_Button *b5 = new Fl_Button(165,5, 90, 25, "Print");
-   b5->tooltip("This is a tooltip");
-   b5->callback(print2,c2);*/
   
+  Fl_Radio_Round_Button *rb;
+  Fl_Window *w3 = new Fl_Window(2,5,w2->w()-10,55);
+  w3->box(FL_DOWN_BOX);
+  Fl_Group *g1 = new Fl_Group(w3->x(),w3->y(),w3->w(),w3->h());
+  rb = new Fl_Radio_Round_Button(5,5,150,12, "Fl_Image_Surface"); 
+  rb->set(); rb->callback(operation_cb, NULL); operation = rb->label();
+  rb = new Fl_Radio_Round_Button(5,22,150,12, "Fl_Copy_Surface"); rb->callback(operation_cb, NULL);
+  rb = new Fl_Radio_Round_Button(5,39,150,12, "Fl_Printer"); rb->callback(operation_cb, NULL);
+  g1->end();
+  
+  Fl_Group *g2 = new Fl_Group(w3->x(),w3->y(),w3->w(),w3->h());
+  rb = new Fl_Radio_Round_Button(170,5,150,12, "Window"); 
+  rb->set(); rb->callback(target_cb, w2); target = w2;
+  rb = new Fl_Radio_Round_Button(170,22,150,12, "Sub-window"); rb->callback(target_cb, w3);
+  rb = new Fl_Radio_Round_Button(170,39,150,12, "Group"); rb->callback(target_cb, group);
+  g2->end();
+  Fl_Button *b4 = new Fl_Button(330, (w3->h() - 25)/2, 150, 25, "GO");
+  b4->callback((Fl_Callback*)copy,NULL);
+  w3->end();
+  
   w2->end();
   w2->show(argc, argv);
   
