Added copy/paste from/to FLTK applications of graphical data.

Added Fl_Image_Surface class to draw into an Fl_Image object.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10159 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy
2014-05-23 16:47:21 +00:00
parent 85af2efe09
commit 07dd8ba328
17 changed files with 1747 additions and 169 deletions
+4
View File
@@ -1,5 +1,9 @@
CHANGES IN FLTK 1.3.3 RELEASED: MMM DD YYYY
- added class Fl_Copy_Surface allowing to copy graphical data to the clipboard
in a cross-platform way.
- added support for pasting graphical data from the clipboard to an FLTK widget.
- added class Fl_Image_Surface allowing to draw into an Fl_Image object.
- removed constraint that lines are limited to 1024 chars in widget labels and browser lines (STR #2990).
- fix crash if Fl_Window::flush() was called, but window not shown() (STR #3028).
- new method Fl::scheme_is(const char *name) returns 1 if current scheme is name.
+68 -10
View File
@@ -137,6 +137,8 @@ public: // should be private!
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 @@ public: // should be private!
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.
*/
@@ -729,6 +733,16 @@ public:
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();
@@ -763,19 +777,39 @@ public:
/**
Copies the data pointed to by \p stuff to the selection buffer
(\p destination is 0) or
the clipboard (\p destination is 1); \p len is the number of relevant
bytes in \p stuff.
the clipboard (\p destination is 1).
\p len is the number of relevant bytes in \p stuff.
\p type is always Fl::clipboard_plain_text.
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, at present, intended only to copy UTF-8 encoded textual data.
To copy graphical data, use the Fl_Copy_Surface class. The \p type argument may allow
in the future to copy other kinds of data.
*/
static void copy(const char* stuff, int len, int destination = 0); // platform dependent
#if FLTK_ABI_VERSION >= 10303 || defined(FL_DOXYGEN)
static void copy(const char* stuff, int len, int destination = 0, const char *type = Fl::clipboard_plain_text); // platform dependent
#else
static void copy(const char* stuff, int len, int destination, const char *type);
static void copy(const char* stuff, int len, int destination = 0);
#endif
#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
@@ -786,8 +820,21 @@ public:
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.
*/
static void paste(Fl_Widget &receiver, int source /*=0*/); // platform dependent
\par Platform details for image data:
\li Unix/Linux platform: Image data in PNG or BMP formats are recognized. Requires linking with the fltk_images library.
\li MSWindows platform: Both bitmap and vectorial (Enhanced metafile) data from clipboard
can be pasted as image data.
\li Mac OS X platform: Both bitmap (TIFF) and vectorial (PDF) data from clipboard
can be pasted as image data.
*/
#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
@@ -815,6 +862,17 @@ public:
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
+135
View File
@@ -0,0 +1,135 @@
//
// "$Id: Fl_Copy_Surface.H 9869 2013-04-09 20:11:28Z greg.ercolano $"
//
// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#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: 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 (or PICT for Mac OS 10.3).
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
//
// End of "$Id: $".
//
+90
View File
@@ -0,0 +1,90 @@
//
// "$Id: Fl_Image_Surface.H 9869 2013-04-09 20:11:28Z greg.ercolano $"
//
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#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;
GC gc;
#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
//
// End of "$Id: $".
//
+1
View File
@@ -145,6 +145,7 @@ public:
void set_cursor(Fl_Cursor);
static CGImageRef CGImage_from_window_rect(Fl_Window *win, int x, int y, int w, int h);
static unsigned char *bitmap_from_window_rect(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel);
static CFDataRef CGBitmapContextToTIFF(CGContextRef c);
static Fl_Region intersect_region_and_rect(Fl_Region current, int x,int y,int w, int h);
static CGContextRef watch_cursor_image(void);
static CGContextRef help_cursor_image(void);
+2 -1
View File
@@ -5,7 +5,8 @@ SHELL = /bin/sh
.SILENT:
# Executables
ALL = howto-add_fd-and-popen$(EXEEXT) \
ALL = clipboard$(EXEEXT) \
howto-add_fd-and-popen$(EXEEXT) \
howto-browser-with-icons$(EXEEXT) \
howto-drag-and-drop$(EXEEXT) \
howto-parse-args$(EXEEXT) \
+168
View File
@@ -0,0 +1,168 @@
//
// "$Id: clipboard.cxx 9869 2013-04-09 20:11:28Z greg.ercolano $"
//
// Clipboard display test application for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#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();
}
//
// End of "$Id: $".
//
+12
View File
@@ -329,6 +329,8 @@
7F66B1DA12BB924C00C67B59 /* Fl_Native_File_Chooser_MAC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F66B1D712BB924C00C67B59 /* Fl_Native_File_Chooser_MAC.mm */; };
7F66B1DB12BB924C00C67B59 /* Fl_Quartz_Printer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F66B1D812BB924C00C67B59 /* Fl_Quartz_Printer.mm */; };
7F74F393190D7F0500C56950 /* fl_gleam.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 299E717718BC503400FF83F2 /* fl_gleam.cxx */; };
7F76E016192FAD420071728B /* Fl_Copy_Surface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 7F76E015192FAD420071728B /* Fl_Copy_Surface.cxx */; };
7F76E018192FAD590071728B /* Fl_Image_Surface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 7F76E017192FAD590071728B /* Fl_Image_Surface.cxx */; };
7FFDE4AD171D8AA3008753A3 /* Fl_Sys_Menu_Bar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7FFDE4AC171D8AA3008753A3 /* Fl_Sys_Menu_Bar.mm */; };
812129561A1981D6DEFBCBFB /* Fl_Positioner.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 05BBBFE4BED0452E5D6A81F7 /* Fl_Positioner.cxx */; };
812761E94039F13357F56EE6 /* fltk_png.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 98A16A4EC098BA7DB21E13DC /* fltk_png.framework */; };
@@ -4338,6 +4340,10 @@
7F66B1D612BB924C00C67B59 /* Fl_cocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Fl_cocoa.mm; path = ../../src/Fl_cocoa.mm; sourceTree = SOURCE_ROOT; };
7F66B1D712BB924C00C67B59 /* Fl_Native_File_Chooser_MAC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Fl_Native_File_Chooser_MAC.mm; path = ../../src/Fl_Native_File_Chooser_MAC.mm; sourceTree = SOURCE_ROOT; };
7F66B1D812BB924C00C67B59 /* Fl_Quartz_Printer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Fl_Quartz_Printer.mm; path = ../../src/Fl_Quartz_Printer.mm; sourceTree = SOURCE_ROOT; };
7F76E015192FAD420071728B /* Fl_Copy_Surface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Fl_Copy_Surface.cxx; path = ../../src/Fl_Copy_Surface.cxx; sourceTree = SOURCE_ROOT; };
7F76E017192FAD590071728B /* Fl_Image_Surface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Fl_Image_Surface.cxx; path = ../../src/Fl_Image_Surface.cxx; sourceTree = SOURCE_ROOT; };
7F76E019192FAD740071728B /* Fl_Copy_Surface.H */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Fl_Copy_Surface.H; path = ../../FL/Fl_Copy_Surface.H; sourceTree = SOURCE_ROOT; };
7F76E01A192FAD840071728B /* Fl_Image_Surface.H */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Fl_Image_Surface.H; path = ../../FL/Fl_Image_Surface.H; sourceTree = SOURCE_ROOT; };
7F784151AF1B748D0F3DB1C0 /* forms.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = forms.cxx; path = ../../test/forms.cxx; sourceTree = SOURCE_ROOT; };
7FAC914955D699539F73B996 /* bitmap.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bitmap.cxx; path = ../../test/bitmap.cxx; sourceTree = SOURCE_ROOT; };
7FC91721DA7888C8A1FD762E /* input_choice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = input_choice.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -5459,6 +5465,7 @@
4D55C9FE101986BC47029A16 /* Fl_Choice.cxx */,
F5CAE7DC565B8398F02ED7BA /* Fl_Clock.cxx */,
058BCBC36ADE724A418F1C43 /* Fl_Color_Chooser.cxx */,
7F76E015192FAD420071728B /* Fl_Copy_Surface.cxx */,
E9893274B0B6C5F24730235F /* Fl_Counter.cxx */,
D9A7DCBAFF41CBC3DCB67C6F /* Fl_Device.cxx */,
3AFC31503AB99F6D00BAC647 /* Fl_Dial.cxx */,
@@ -5471,6 +5478,7 @@
806103D71A8CD0075BF8E1DA /* Fl_Group.cxx */,
790419B5A0AD64D66F9B19E1 /* Fl_Help_View.cxx */,
6DCFF326B588B1B27618F28C /* Fl_Image.cxx */,
7F76E017192FAD590071728B /* Fl_Image_Surface.cxx */,
63CB19652C470F1E58DCF01E /* Fl_Input.cxx */,
D531F77A15AACC9E297B4490 /* Fl_Input_.cxx */,
BA7B1E9C7AA7316E98D369C2 /* Fl_Light_Button.cxx */,
@@ -6219,6 +6227,7 @@
C8AE10A8DDF53B8B27E3215A /* Fl_Choice.H */,
9BCF393F94482AE7C7421397 /* Fl_Clock.H */,
2CD1EF8B4BFD0820E9A42641 /* Fl_Color_Chooser.H */,
7F76E019192FAD740071728B /* Fl_Copy_Surface.H */,
CE97D58B5B0F1A2A7DB2A3FF /* Fl_Counter.H */,
82863AEFE086C3469C386C22 /* Fl_Device.H */,
02C21BB31E7DDFE9E76F4997 /* Fl_Dial.H */,
@@ -6241,6 +6250,7 @@
AE1717E43F50EBA343960B1E /* Fl_Hor_Slider.H */,
5B8BFBDF9C48A998F0781C9E /* Fl_Hor_Value_Slider.H */,
332598626430923370C48554 /* Fl_Image.H */,
7F76E01A192FAD840071728B /* Fl_Image_Surface.H */,
EFEEE679374D7E4191873447 /* Fl_Input.H */,
A5166C3C9311628F6E450095 /* Fl_Input_.H */,
648E9C3B61328280244FCCA5 /* Fl_Input_Choice.H */,
@@ -9515,6 +9525,8 @@
299CB8A2848CB844BCEC7829 /* Fl_Paged_Device.cxx in Sources */,
7F74F393190D7F0500C56950 /* fl_gleam.cxx in Sources */,
01C68DB0192C6089000BD75C /* Fl_sleep.cxx in Sources */,
7F76E016192FAD420071728B /* Fl_Copy_Surface.cxx in Sources */,
7F76E018192FAD590071728B /* Fl_Image_Surface.cxx in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+12
View File
@@ -328,6 +328,8 @@
7F66B1D912BB924C00C67B59 /* Fl_cocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F66B1D612BB924C00C67B59 /* Fl_cocoa.mm */; };
7F66B1DA12BB924C00C67B59 /* Fl_Native_File_Chooser_MAC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F66B1D712BB924C00C67B59 /* Fl_Native_File_Chooser_MAC.mm */; };
7F66B1DB12BB924C00C67B59 /* Fl_Quartz_Printer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F66B1D812BB924C00C67B59 /* Fl_Quartz_Printer.mm */; };
7FA5C2BE192FAEBB00519823 /* Fl_Copy_Surface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 7FA5C2BD192FAEBB00519823 /* Fl_Copy_Surface.cxx */; };
7FA5C2C0192FAECA00519823 /* Fl_Image_Surface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 7FA5C2BF192FAECA00519823 /* Fl_Image_Surface.cxx */; };
7FDBB8F416B2D1EA00AE76EF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7F92032516B1A90A000FC50F /* Localizable.strings */; };
7FDBB8F516B2D1EE00AE76EF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7F92032216B1A909000FC50F /* Localizable.strings */; };
7FDBB8F616B2D1FA00AE76EF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7F92031F16B1A909000FC50F /* Localizable.strings */; };
@@ -4334,6 +4336,10 @@
7F92032016B1A909000FC50F /* German */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = German; path = Localizable.strings; sourceTree = "<group>"; };
7F92032316B1A90A000FC50F /* Italian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Italian; path = Localizable.strings; sourceTree = "<group>"; };
7F92032616B1A90A000FC50F /* Spanish */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Spanish; path = Localizable.strings; sourceTree = "<group>"; };
7FA5C2BD192FAEBB00519823 /* Fl_Copy_Surface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Fl_Copy_Surface.cxx; path = ../../src/Fl_Copy_Surface.cxx; sourceTree = SOURCE_ROOT; };
7FA5C2BF192FAECA00519823 /* Fl_Image_Surface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Fl_Image_Surface.cxx; path = ../../src/Fl_Image_Surface.cxx; sourceTree = SOURCE_ROOT; };
7FA5C2C1192FAEE300519823 /* Fl_Image_Surface.H */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Fl_Image_Surface.H; path = ../../FL/Fl_Image_Surface.H; sourceTree = SOURCE_ROOT; };
7FA5C2C2192FAEF200519823 /* Fl_Copy_Surface.H */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Fl_Copy_Surface.H; path = ../../FL/Fl_Copy_Surface.H; sourceTree = SOURCE_ROOT; };
7FAC914955D699539F73B996 /* bitmap.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bitmap.cxx; path = ../../test/bitmap.cxx; sourceTree = SOURCE_ROOT; };
7FC91721DA7888C8A1FD762E /* input_choice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = input_choice.app; sourceTree = BUILT_PRODUCTS_DIR; };
7FFDE551171D8D0D008753A3 /* Fl_Sys_Menu_Bar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Fl_Sys_Menu_Bar.mm; path = ../../src/Fl_Sys_Menu_Bar.mm; sourceTree = SOURCE_ROOT; };
@@ -5453,6 +5459,7 @@
4D55C9FE101986BC47029A16 /* Fl_Choice.cxx */,
F5CAE7DC565B8398F02ED7BA /* Fl_Clock.cxx */,
058BCBC36ADE724A418F1C43 /* Fl_Color_Chooser.cxx */,
7FA5C2BD192FAEBB00519823 /* Fl_Copy_Surface.cxx */,
E9893274B0B6C5F24730235F /* Fl_Counter.cxx */,
D9A7DCBAFF41CBC3DCB67C6F /* Fl_Device.cxx */,
3AFC31503AB99F6D00BAC647 /* Fl_Dial.cxx */,
@@ -5465,6 +5472,7 @@
806103D71A8CD0075BF8E1DA /* Fl_Group.cxx */,
790419B5A0AD64D66F9B19E1 /* Fl_Help_View.cxx */,
6DCFF326B588B1B27618F28C /* Fl_Image.cxx */,
7FA5C2BF192FAECA00519823 /* Fl_Image_Surface.cxx */,
63CB19652C470F1E58DCF01E /* Fl_Input.cxx */,
D531F77A15AACC9E297B4490 /* Fl_Input_.cxx */,
BA7B1E9C7AA7316E98D369C2 /* Fl_Light_Button.cxx */,
@@ -6258,6 +6266,7 @@
C8AE10A8DDF53B8B27E3215A /* Fl_Choice.H */,
9BCF393F94482AE7C7421397 /* Fl_Clock.H */,
2CD1EF8B4BFD0820E9A42641 /* Fl_Color_Chooser.H */,
7FA5C2C2192FAEF200519823 /* Fl_Copy_Surface.H */,
CE97D58B5B0F1A2A7DB2A3FF /* Fl_Counter.H */,
82863AEFE086C3469C386C22 /* Fl_Device.H */,
02C21BB31E7DDFE9E76F4997 /* Fl_Dial.H */,
@@ -6280,6 +6289,7 @@
AE1717E43F50EBA343960B1E /* Fl_Hor_Slider.H */,
5B8BFBDF9C48A998F0781C9E /* Fl_Hor_Value_Slider.H */,
332598626430923370C48554 /* Fl_Image.H */,
7FA5C2C1192FAEE300519823 /* Fl_Image_Surface.H */,
EFEEE679374D7E4191873447 /* Fl_Input.H */,
A5166C3C9311628F6E450095 /* Fl_Input_.H */,
648E9C3B61328280244FCCA5 /* Fl_Input_Choice.H */,
@@ -9552,6 +9562,8 @@
CE14EC6653D4EF4779992758 /* is_right2left.c in Sources */,
9DD7A2B6D63D30C07781F446 /* is_spacing.c in Sources */,
299CB8A2848CB844BCEC7829 /* Fl_Paged_Device.cxx in Sources */,
7FA5C2BE192FAEBB00519823 /* Fl_Copy_Surface.cxx in Sources */,
7FA5C2C0192FAECA00519823 /* Fl_Image_Surface.cxx in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+17 -1
View File
@@ -104,6 +104,8 @@ int Fl::damage_,
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 @@ Fl_Window *Fl::modal_; // topmost modal() window
#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...
//
@@ -1635,12 +1640,23 @@ void Fl::selection(Fl_Widget &owner, const char* text, int len) {
/** 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);
}
void Fl::copy(const char* stuff, int len, int destination) {
Fl::copy(stuff, len, destination, Fl::clipboard_plain_text);
}
#endif
////////////////////////////////////////////////////////////////
#include <FL/fl_draw.H>
+399
View File
@@ -0,0 +1,399 @@
//
// "$Id: Fl_Copy_Surface.cxx 9869 2013-04-09 20:11:28Z greg.ercolano $"
//
// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#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);
}
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);
PasteboardPutItemFlavor(clipboard, (PasteboardItemID)1, CFSTR("public.tiff"),
Fl_X::CGBitmapContextToTIFF(gc), kPasteboardFlavorNoFlags);
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 {
int offset_x, offset_y; // translation between user and graphical coordinates: graphical = user + offset
int depth; // depth of translation stack
int stack_x[20], stack_y[20]; // translation stack allowing cumulative translations
public:
static const char *class_id;
const char *class_name() {return class_id;};
Fl_translated_Xlib_Graphics_Driver_() {
offset_x = 0; offset_y = 0;
depth = 0;
}
virtual ~Fl_translated_Xlib_Graphics_Driver_() {};
void translate_all(int dx, int dy) { // reversibly 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 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_Xlib_Graphics_Driver::draw(str, n, x+offset_x, y+offset_y);
}
void draw(int angle, const char *str, int n, int x, int y) {
Fl_Xlib_Graphics_Driver::draw(angle, str, n, x+offset_x, y+offset_y);
}
void rtl_draw(const char* str, int n, int x, int y) {
Fl_Xlib_Graphics_Driver::rtl_draw(str, n, x+offset_x, y+offset_y);
}
void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
XP += offset_x; YP += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw(pxm, XP, YP, WP,HP,cx,cy);
untranslate_all();
}
void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
XP += offset_x; YP += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw(bm, XP, YP, WP,HP,cx,cy);
untranslate_all();
}
void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
XP += offset_x; YP += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw(img, XP, YP, WP,HP,cx,cy);
untranslate_all();
}
void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0) {
X += offset_x; Y += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw_image(buf, X, Y, W,H,D,L);
untranslate_all();
}
void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3) {
X += offset_x; Y += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw_image(cb, data, X, Y, W,H,D);
untranslate_all();
}
void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0) {
X += offset_x; Y += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw_image_mono(buf, X, Y, W,H,D,L);
untranslate_all();
}
void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1) {
X += offset_x; Y += offset_y;
translate_all(-offset_x, -offset_y);
Fl_Xlib_Graphics_Driver::draw_image_mono(cb, data, X, Y, W,H,D);
untranslate_all();
}
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) {
Fl_Xlib_Graphics_Driver::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_Xlib_Graphics_Driver::push_clip(x+offset_x, y+offset_y, w, h);
}
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_Surface_::~Fl_Xlib_Surface_() {
delete driver();
}
const char *Fl_Xlib_Surface_::class_id = "Fl_Xlib_Surface_";
#endif
//
// End of "$Id: $".
//
+158
View File
@@ -0,0 +1,158 @@
//
// "$Id: Fl_Image_Surface.cxx 9869 2013-04-09 20:11:28Z greg.ercolano $"
//
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2014 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#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;
#if !(defined(__APPLE__) || defined(WIN32))
gc = 0;
if (!fl_display) { // allows use of this class before any window is shown
fl_open_display();
gc = XCreateGC(fl_display, RootWindow(fl_display, fl_screen), 0, 0);
fl_gc = gc;
}
#endif
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
if (gc) { XFreeGC(fl_display, gc); fl_gc = 0; }
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, 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__
//
// End of "$Id: $".
//
+180 -45
View File
@@ -2803,8 +2803,9 @@ static void clipboard_check(void)
* create a selection
* stuff: pointer to selected data
* len: size of selected data
* type: always "plain/text" for now
*/
void Fl::copy(const char *stuff, int len, int clipboard) {
void Fl::copy(const char *stuff, int len, int clipboard, const char *type) {
if (!stuff || len<0) return;
if (len+1 > fl_selection_buffer_length[clipboard]) {
delete[] fl_selection_buffer[clipboard];
@@ -2824,56 +2825,171 @@ void Fl::copy(const char *stuff, int len, int clipboard) {
}
}
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 {
vectorial = [NSPICTImageRep imageRepWithData:data];
rect = [(NSPICTImageRep*)vectorial boundingBox]; // in pixel, no scaling required
}
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) {
void Fl::paste(Fl_Widget &receiver, int clipboard, const char *type) {
if (type[0] == 0) type = Fl::clipboard_plain_text;
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);
}
else {
[data getBytes:fl_selection_buffer[1]];
}
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:
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;
@@ -3045,6 +3161,25 @@ static NSImage *CGBitmapContextToNSImage(CGContextRef c)
return [image autorelease];
}
CFDataRef Fl_X::CGBitmapContextToTIFF(CGContextRef c)
{ // the returned value is autoreleased
unsigned char *pdata = (unsigned char *)CGBitmapContextGetData(c);
NSBitmapImageRep *imagerep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pdata
pixelsWide:CGBitmapContextGetWidth(c)
pixelsHigh:CGBitmapContextGetHeight(c)
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:CGBitmapContextGetBytesPerRow(c)
bitsPerPixel:CGBitmapContextGetBitsPerPixel(c)];
NSData* tiff = [imagerep TIFFRepresentation];
[imagerep release];
return (CFDataRef)tiff;
}
static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() )
{
if (cursor == nil) {
@@ -3531,10 +3666,10 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
[title_s drawWithRect:r options:(NSStringDrawingOptions)0 attributes:attr]; // 10.4
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
[NSGraphicsContext setCurrentContext:current];
}
else
}
else
#endif
{
{
fl_font(FL_HELVETICA, 14); // the exact font is LucidaGrande 13 pts
fl_color(FL_BLACK);
int x = x_offset + win->w()/2 - fl_width(title)/2;
@@ -3542,7 +3677,7 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
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
}
+122 -26
View File
@@ -567,7 +567,7 @@ void fl_update_clipboard(void) {
}
// call this when you create a selection:
void Fl::copy(const char *stuff, int len, int clipboard) {
void Fl::copy(const char *stuff, int len, int clipboard, const char *type) {
if (!stuff || len<0) return;
// Convert \n -> \r\n (for old apps like Notepad, DOS)
@@ -589,13 +589,11 @@ void Fl::copy(const char *stuff, int len, int clipboard) {
}
// 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 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
}
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;
+300 -39
View File
@@ -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 @@ static Atom fl_XaText;
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 @@ void fl_open_display(Display* d) {
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 @@ void Fl::get_mouse(int &xx, int &yy) {
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; //TODO: allow copy/paste of image within same app
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 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
// 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;
@@ -859,7 +916,7 @@ static int get_xwinprop(Window wnd, Atom prop, long max_length,
////////////////////////////////////////////////////////////////
// Code for copying to clipboard and DnD out of the program:
void Fl::copy(const char *stuff, int len, int clipboard) {
void Fl::copy(const char *stuff, int len, int clipboard, const char *type) {
if (!stuff || len<0) return;
if (len+1 > fl_selection_buffer_length[clipboard]) {
delete[] fl_selection_buffer[clipboard];
@@ -870,6 +927,77 @@ void Fl::copy(const char *stuff, int len, int clipboard) {
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);
}
@@ -1047,6 +1175,62 @@ static int wasXExceptionRaised() {
}
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)
{
@@ -1139,6 +1323,7 @@ int fl_handle(const XEvent& thisevent)
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 @@ int fl_handle(const XEvent& thisevent)
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 @@ int fl_handle(const XEvent& thisevent)
}
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 @@ int fl_handle(const XEvent& thisevent)
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 @@ int fl_handle(const XEvent& thisevent)
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,51 @@ int fl_handle(const XEvent& thisevent)
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 { // 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 {
e.property = 0;
}
}
} 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 +1778,13 @@ int fl_handle(const XEvent& thisevent)
// 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,
+2
View File
@@ -31,6 +31,7 @@ CPPFILES = \
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 @@ CPPFILES = \
Fl_Group.cxx \
Fl_Help_View.cxx \
Fl_Image.cxx \
Fl_Image_Surface.cxx \
Fl_Input.cxx \
Fl_Input_.cxx \
Fl_Light_Button.cxx \
+77 -47
View File
@@ -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,8 +31,8 @@
#include <FL/Fl_Printer.H>
//#include "fl_printer_chooser.H"
#include <FL/Fl_Copy_Surface.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/fl_draw.H>
@@ -448,7 +449,6 @@ class MyWidget5: public Fl_Box{
protected:
void draw(){
Fl_Box::draw();
//fl_push_clip(x(),y(),w(),h());
fl_push_matrix();
fl_translate(x(),y());
@@ -512,11 +512,6 @@ protected:
fl_end_complex_polygon();
fl_pop_matrix();
// fl_color(FL_BLACK);
// fl_line_style(0);
//fl_pop_clip();
};
public:
MyWidget5(int x, int y):Fl_Box(x,y,230,250, "Complex (double) drawings:\nBlue ellipse may not be\ncorrectly transformed\ndue to non-orthogonal\ntransformation"){
@@ -551,37 +546,53 @@ void make_image() {
}
void print(Fl_Widget *, void *w) {
Fl_Widget * g = (Fl_Widget *)w;
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();
}
delete p;
}
Fl_Widget *target;
const char *operation;
/*void print2(Fl_Widget *, void *w) {
Fl_Widget * g = (Fl_Widget *)w;
Fl_Printer * p = fl_printer_chooser();
if(!p) return;
p->page(Fl_Printer::A4);
// fitting inside margins 1 inch wide
p->place(g, FL_INCH, FL_INCH, p->page_width() - 2 * FL_INCH, p->page_height() - 2 * FL_INCH, FL_ALIGN_CENTER);
Fl_Device * c = p->set_current();
fl_draw(g);
c->set_current();
delete p;
};*/
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;
}
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;
}
}
class My_Button:public Fl_Button{
protected:
void draw(){
// Fl_Button::draw();
if (type() == FL_HIDDEN_BUTTON) return;
Fl_Color col = value() ? selection_color() : color();
draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col);
@@ -598,15 +609,22 @@ public:
};
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");
//Fl::scheme("plastic");
Fl_Window * w2 = new Fl_Window(500,560,"Graphics test");
Fl_Group *c2 =new Fl_Group(3, 43, 494, 514 );
new MyWidget(10,140);
@@ -643,14 +661,12 @@ int main(int argc, char ** argv) {
but5.labelfont(FL_BOLD|FL_ITALIC);
but5.labeltype(FL_SHADOW_LABEL);
but5.box(FL_ROUND_UP_BOX);
// but5.selection_color(FL_WHITE);
Fl_Button but6(360, 460, 120, 30, "Plastic");
but6.box(FL_PLASTIC_UP_BOX);
//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,16 +689,30 @@ int main(int argc, char ** argv) {
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);
Fl::run();
return 0;
}