1) Replicate in branch-1.3-porting all recent changes of branch-1.3

2) Advance branch-1.3-porting with new function Fl_X::capture_titlebar_and_borders()
that contains all the platform-specific code of all operations related to drawing
window borders and title bars. What is platform-specific and what is not
is therefore much clearer, to ease porting.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11002 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2016-01-10 19:08:16 +00:00
parent acc5080653
commit eeb65bef23
12 changed files with 298 additions and 246 deletions

View File

@ -70,6 +70,7 @@ public:
void set_current();
void draw(Fl_Widget*, int delta_x = 0, int delta_y = 0);
Fl_RGB_Image *image();
void draw_decorated_window(Fl_Window* win, int delta_x = 0, int delta_y = 0);
};
#ifdef __APPLE__

View File

@ -36,17 +36,9 @@
or Fl_PostScript_File_Device instead.
*/
class FL_EXPORT Fl_Paged_Device : public Fl_Surface_Device {
#ifdef __APPLE__
// not needed
#elif defined(WIN32)
friend class Fl_Copy_Surface;
void draw_decorated_window(Fl_Window *win, int x_offset, int y_offset, Fl_Surface_Device *toset);
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: define member variables to support Fl_Copy_Surface in Fl_Paged_Device"
#else // X11
friend class Fl_Copy_Surface;
void draw_decorated_window(Fl_Window *win, int x_offset, int y_offset, Fl_Surface_Device *toset);
#endif
friend class Fl_Image_Surface;
void draw_decorated_window(Fl_Window *win, int x_offset, int y_offset);
public:
/**
\brief Possible page formats.

View File

@ -199,6 +199,7 @@ public:
void set_icons() {};
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right);
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 Fl_Region intersect_region_and_rect(Fl_Region current, int x,int y,int w, int h);

View File

@ -90,6 +90,7 @@ public:
void set_icons();
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right);
static Fl_X* make(Fl_Window*);
};
extern FL_EXPORT UINT fl_wake_msg;

1
FL/x.H
View File

@ -147,6 +147,7 @@ public:
void set_icons();
int set_cursor(Fl_Cursor);
int set_cursor(const Fl_RGB_Image*, int, int);
void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right);
static void make_xid(Fl_Window*,XVisualInfo* =fl_visual, Colormap=fl_colormap);
static Fl_X* set_xid(Fl_Window*, Window);
// kludges to get around protection:

View File

@ -89,7 +89,7 @@ Fl_Copy_Surface::Fl_Copy_Surface(int w, int h) : Fl_Surface_Device(NULL)
int vdots = GetDeviceCaps(hdc, VERTRES);
ReleaseDC(NULL, hdc);
float factorw = (100. * hmm) / hdots;
float factorh = (100. * vmm) / vdots + 0.5;
float factorh = (100. * vmm) / vdots;
RECT rect; rect.left = 0; rect.top = 0; rect.right = w * factorw; rect.bottom = h * factorh;
gc = CreateEnhMetaFile (NULL, NULL, &rect, NULL);
@ -217,20 +217,10 @@ void Fl_Copy_Surface::prepare_copy_pdf_and_tiff(int w, int h)
#endif // __APPLE__
#if !defined(__APPLE__)
/** Copies a window and its borders and title bar to the clipboard. */
void Fl_Copy_Surface::draw_decorated_window(Fl_Window* win, int delta_x, int delta_y)
{
#if defined(WIN32)
helper->draw_decorated_window(win, delta_x, delta_y, this);
#elif defined(__APPLE__)
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: do you want to draw a window border around a printout"
#else
helper->draw_decorated_window(win, delta_x, delta_y, this);
#endif
helper->draw_decorated_window(win, delta_x, delta_y);
}
#endif
#if defined(WIN32)
#elif defined(__APPLE__)

View File

@ -34,8 +34,17 @@ const char *Fl_Image_Surface::class_id = "Fl_Image_Surface";
Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
width = w;
height = h;
#if defined(__APPLE__)
#ifdef __APPLE__
offscreen = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w, h);
helper = new Fl_Quartz_Flipped_Surface_(width, height);
driver(helper->driver());
CGContextSaveGState(offscreen);
CGContextTranslateCTM(offscreen, 0, height);
CGContextScaleCTM(offscreen, 1.0f, -1.0f);
#elif defined(WIN32)
offscreen = fl_create_offscreen(w, h);
helper = new Fl_GDI_Surface_();
driver(helper->driver());
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: implement Fl_Image_Surface"
#else
@ -44,21 +53,8 @@ Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
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());
CGContextSaveGState(offscreen);
CGContextTranslateCTM(offscreen, 0, height);
CGContextScaleCTM(offscreen, 1.0f, -1.0f);
#elif defined(WIN32)
helper = new Fl_GDI_Surface_();
driver(helper->driver());
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: implement Fl_Image_Surface"
#else
helper = new Fl_Xlib_Surface_();
driver(helper->driver());
#endif
@ -67,14 +63,18 @@ Fl_Image_Surface::Fl_Image_Surface(int w, int h) : Fl_Surface_Device(NULL) {
/** The destructor.
*/
Fl_Image_Surface::~Fl_Image_Surface() {
fl_delete_offscreen(offscreen);
#ifdef __APPLE__
void *data = CGBitmapContextGetData((CGContextRef)offscreen);
free(data);
CGContextRelease((CGContextRef)offscreen);
delete (Fl_Quartz_Flipped_Surface_*)helper;
#elif defined(WIN32)
fl_delete_offscreen(offscreen);
delete (Fl_GDI_Surface_*)helper;
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: implement Fl_Image_Surface"
#else
fl_delete_offscreen(offscreen);
if (gc) { XFreeGC(fl_display, gc); fl_gc = 0; }
delete (Fl_Xlib_Surface_*)helper;
#endif
@ -86,9 +86,13 @@ Fl_Image_Surface::~Fl_Image_Surface() {
Fl_RGB_Image* Fl_Image_Surface::image()
{
unsigned char *data;
int depth = 3, ld = 0;
#ifdef __APPLE__
CGContextFlush(offscreen);
data = fl_read_image(NULL, 0, 0, width, height, 0);
ld = CGBitmapContextGetBytesPerRow(offscreen);
data = (uchar*)malloc(ld * height);
memcpy(data, (uchar *)CGBitmapContextGetData(offscreen), ld * height);
depth = 4;
fl_gc = 0;
#elif defined(WIN32)
fl_pop_clip();
@ -106,7 +110,7 @@ Fl_RGB_Image* Fl_Image_Surface::image()
fl_window = pre_window;
previous->set_current();
#endif
Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height);
Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height, depth, ld);
image->alloc_array = 1;
return image;
}
@ -168,7 +172,18 @@ void Fl_Quartz_Flipped_Surface_::untranslate() {
const char *Fl_Quartz_Flipped_Surface_::class_id = "Fl_Quartz_Flipped_Surface_";
#endif // __APPLE__
#endif
/** Draws a window and its borders and title bar to the image drawing surface.
\param win an FLTK window 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 window's title bar
*/
void Fl_Image_Surface::draw_decorated_window(Fl_Window* win, int delta_x, int delta_y)
{
helper->draw_decorated_window(win, delta_x, delta_y);
}
//
// End of "$Id$".

View File

@ -60,9 +60,7 @@ void Fl_Paged_Device::print_widget(Fl_Widget* widget, int delta_x, int delta_y)
fl_push_clip(0, 0, widget->w(), widget->h() );
#ifdef __APPLE__ // for Mac OS X 10.6 and above, make window with rounded bottom corners
if ( fl_mac_os_version >= 100600 && driver()->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
CGContextRestoreGState(fl_gc);
Fl_X::clip_to_rounded_corners(fl_gc, widget->w(), widget->h());
CGContextSaveGState(fl_gc);
}
#endif
}
@ -296,6 +294,45 @@ const Fl_Paged_Device::page_format Fl_Paged_Device::page_formats[NO_PAGE_FORMATS
{ 297, 684, "Env10"} // envelope
};
void Fl_Paged_Device::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset)
{
Fl_RGB_Image *top, *left, *bottom, *right;
#if defined(FL_PORTING)
# pragma message "FL_PORTING: implement Fl_X::capture_titlebar_and_borders"
#endif
Fl_X::i(win)->capture_titlebar_and_borders(top, left, bottom, right);
int wsides = left ? left->w() : 0;
int toph = top ? top->h() : 0;
if (top) {
#ifdef __APPLE__
top->draw(x_offset, y_offset); // draw with transparency
#else
fl_draw_image(top->array, x_offset, y_offset, top->w(), top->h(), top->d());
#endif // __APPLE__
delete top;
}
if (left) {
fl_draw_image(left->array, x_offset, y_offset + toph, left->w(), left->h(), left->d());
delete left;
}
if (right) {
fl_draw_image(right->array, x_offset + win->w() + wsides, y_offset + toph, right->w(), right->h(), right->d());
delete right;
}
if (bottom) {
fl_draw_image(bottom->array, x_offset, y_offset + toph + win->h(), bottom->w(), bottom->h(), bottom->d());
delete bottom;
}
this->print_widget(win, x_offset + wsides, y_offset + toph);
}
#if !defined(__APPLE__) // Mac OS version in Fl_Cocoa.mm
void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
{
draw_decorated_window(win, x_offset, y_offset);
}
#endif
//
// End of "$Id$".
//

View File

@ -3851,45 +3851,6 @@ int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
}
@end
void Fl_Copy_Surface::draw_decorated_window(Fl_Window* win, int delta_x, int delta_y)
{
int bx, by, bt;
get_window_frame_sizes(bx, by, bt);
draw(win, 0, bt); // draw the window content
if (win->border()) {
// draw the window title bar
CGContextSaveGState(gc);
CGContextTranslateCTM(gc, 0, bt);
CGContextScaleCTM(gc, 1, -1);
Fl_X::clip_to_rounded_corners(gc, win->w(), bt);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
CALayer *layer = fl_mac_os_version >= 101000 ?
[[[fl_xid(win) standardWindowButton:NSWindowCloseButton] superview] layer] : nil; // 10.5
if (layer) {
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
// for unknown reason, rendering the layer to the Fl_Copy_Surface pdf graphics context does not work;
// we use an auxiliary bitmap context
CGContextRef auxgc = CGBitmapContextCreate(NULL, win->w(), bt, 8, 0, cspace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(cspace);
CGContextClearRect(auxgc, CGRectMake(0, 0, win->w(), bt));
CGContextTranslateCTM(auxgc, 0, bt);
CGContextScaleCTM(auxgc, 1, -1);
[layer renderInContext:auxgc]; // 10.5
fl_draw_image((uchar*)CGBitmapContextGetData(auxgc), 0, 0, win->w(), bt, 4, CGBitmapContextGetBytesPerRow(auxgc));
CGContextRelease(auxgc);
} else
#endif
{
CGImageRef img = Fl_X::CGImage_from_window_rect(win, 0, -bt, win->w(), bt);
CGContextDrawImage(gc, CGRectMake(0, 0, win->w(), bt), img);
CFRelease(img);
}
CGContextRestoreGState(gc);
}
}
static void createAppleMenu(void)
{
static BOOL donethat = NO;
@ -4423,46 +4384,98 @@ void Fl_X::clip_to_rounded_corners(CGContextRef gc, int w, int h) {
CGContextClip(gc);
}
static CALayer *get_titlebar_layer(Fl_Window *win)
{
// a compilation warning appears with SDK 10.5, so we require SDK 10.6 instead
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
return fl_mac_os_version >= 101000 ? [[[fl_xid(win) standardWindowButton:NSWindowCloseButton] superview] layer] : nil; // 10.5
#else
return nil;
#endif
}
static void draw_layer_to_context(CALayer *layer, CGContextRef gc, int w, int h)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
CGContextSaveGState(gc);
Fl_X::clip_to_rounded_corners(gc, w, h);
CGContextSetRGBFillColor(gc, .79, .79, .79, 1.); // equiv. to FL_DARK1
CGContextFillRect(gc, CGRectMake(0, 0, w, h));
[layer renderInContext:gc]; // 10.5
CGContextRestoreGState(gc);
#endif
}
/* Returns images of the capture of the window title-bar.
On the Mac OS platform, left, bottom and right are returned NULL; top is returned with depth 4.
*/
void Fl_X::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right)
{
left = bottom = right = NULL;
int htop = w->decorated_h() - w->h();
CALayer *layer = get_titlebar_layer(w);
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
uchar *rgba = new uchar[4 * w->w() * htop];
CGContextRef auxgc = CGBitmapContextCreate(rgba, w->w(), htop, 8, 4 * w->w(), cspace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(cspace);
CGRect rect = CGRectMake(0, 0, w->w(), htop);
if (layer) {
draw_layer_to_context(layer, auxgc, w->w(), htop);
} else {
CGImageRef img = Fl_X::CGImage_from_window_rect(w, 0, -htop, w->w(), htop);
CGContextSaveGState(auxgc);
Fl_X::clip_to_rounded_corners(auxgc, w->w(), htop);
CGContextDrawImage(auxgc, rect, img);
CGContextRestoreGState(auxgc);
CFRelease(img);
}
top = new Fl_RGB_Image(rgba, w->w(), htop, 4);
top->alloc_array = 1;
CGContextRelease(auxgc);
}
void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
{
if (!win->shown() || win->parent() || !win->border() || !win->visible()) {
this->print_widget(win, x_offset, y_offset);
return;
}
int bx, by, bt, bpp;
int bx, by, bt;
get_window_frame_sizes(bx, by, bt);
BOOL to_quartz = (this->driver()->class_name() == Fl_Quartz_Graphics_Driver::class_id);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
// a compilation warning appears with SDK 10.5, so we require SDK 10.6 instead
if (fl_mac_os_version >= 101000) {
CALayer *layer = [[[fl_xid(win) standardWindowButton:NSWindowCloseButton] superview] layer]; // 10.5
if (layer) { // if program is linked with 10.10, title bar uses a layer
if (to_quartz) { // to Quartz printer
CGContextSaveGState(fl_gc);
CGContextTranslateCTM(fl_gc, x_offset - 0.5, y_offset + bt - 0.5);
CGContextScaleCTM(fl_gc, 1, -1);
Fl_X::clip_to_rounded_corners(fl_gc, win->w(), bt);
[layer renderInContext:fl_gc]; // 10.5 // print all title bar
CGContextRestoreGState(fl_gc);
}
else { // to PostScript
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB ();
CGContextRef gc = CGBitmapContextCreate(NULL, win->w(), bt, 8, 0, cspace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(cspace);
CGContextClearRect(gc, CGRectMake(0, 0, win->w(), bt));
Fl_X::clip_to_rounded_corners(gc, win->w(), bt);
[layer renderInContext:gc]; // 10.5 // draw all title bar to bitmap
Fl_RGB_Image *image = new Fl_RGB_Image((const uchar*)CGBitmapContextGetData(gc), win->w(), bt, 4,
CGBitmapContextGetBytesPerRow(gc)); // 10.2
image->draw(x_offset, y_offset); // draw title bar to PostScript
delete image;
CGContextRelease(gc);
}
this->print_widget(win, x_offset, y_offset + bt);
return;
CALayer *layer = get_titlebar_layer(win);
if (layer) { // if title bar uses a layer
if (to_quartz) { // to Quartz printer
CGContextSaveGState(fl_gc);
CGContextTranslateCTM(fl_gc, 0, bt);
CGContextScaleCTM(fl_gc, 1, -1);
draw_layer_to_context(layer, fl_gc, win->w(), bt);
CGContextRestoreGState(fl_gc);
}
else {
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB ();
CGContextRef gc = CGBitmapContextCreate(NULL, 2*win->w(), 2*bt, 8, 0, cspace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(cspace);
CGContextScaleCTM(gc, 2, 2);
draw_layer_to_context(layer, gc, win->w(), bt);
Fl_RGB_Image *image = new Fl_RGB_Image((const uchar*)CGBitmapContextGetData(gc), 2*win->w(), 2*bt, 4,
CGBitmapContextGetBytesPerRow(gc)); // 10.2
int ori_x, ori_y;
origin(&ori_x, &ori_y);
scale(0.5);
origin(2*ori_x, 2*ori_y);
image->draw(2*x_offset, 2*y_offset); // draw title bar as double resolution image
scale(1);
origin(ori_x, ori_y);
delete image;
CGContextRelease(gc);
}
this->print_widget(win, x_offset, y_offset + bt);
return;
}
#endif
Fl_Display_Device::display_device()->set_current(); // send win to front and make it current
const char *title = win->label();
win->label(""); // temporarily set a void window title
@ -4470,27 +4483,12 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
fl_gc = NULL;
Fl::check();
// capture the window title bar with no title
CGImageRef img = NULL;
unsigned char *bitmap = NULL;
if (to_quartz)
img = Fl_X::CGImage_from_window_rect(win, 0, -bt, win->w(), bt);
else
bitmap = Fl_X::bitmap_from_window_rect(win, 0, -bt, win->w(), bt, &bpp);
Fl_RGB_Image *top, *left, *bottom, *right;
Fl_X::i(win)->capture_titlebar_and_borders(top, left, bottom, right);
win->label(title); // put back the window title
this->set_current(); // back to the Fl_Paged_Device
if (img && to_quartz) { // print the title bar
CGRect rect = CGRectMake(x_offset, y_offset, win->w(), bt);
Fl_X::q_begin_image(rect, 0, 0, win->w(), bt);
CGContextDrawImage(fl_gc, rect, img);
Fl_X::q_end_image();
CFRelease(img);
}
else if(!to_quartz) {
Fl_RGB_Image *rgb = new Fl_RGB_Image(bitmap, win->w(), bt, bpp);
rgb->draw(x_offset, y_offset);
delete rgb;
delete[] bitmap;
}
top->draw(x_offset, y_offset); // print the title bar
delete top;
if (title) { // print the window title
const int skip = 65; // approx width of the zone of the 3 window control buttons
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
@ -4498,8 +4496,8 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
// the exact font is LucidaGrande 13 pts (and HelveticaNeueDeskInterface-Regular with 10.10)
NSGraphicsContext *current = [NSGraphicsContext currentContext];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:fl_gc flipped:YES]];//10.4
NSDictionary *attr = [NSDictionary dictionaryWithObject:[NSFont titleBarFontOfSize:0]
forKey:NSFontAttributeName];
NSDictionary *attr = [NSDictionary dictionaryWithObject:[NSFont titleBarFontOfSize:0]
forKey:NSFontAttributeName];
NSString *title_s = [fl_xid(win) title];
NSSize size = [title_s sizeWithAttributes:attr];
int x = x_offset + win->w()/2 - size.width/2;
@ -4525,7 +4523,6 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
this->print_widget(win, x_offset, y_offset + bt); // print the window inner part
}
/* Returns the address of a Carbon function after dynamically loading the Carbon library if needed.
Supports old Mac OS X versions that may use a couple of Carbon calls:
GetKeys used by OS X 10.3 or before (in Fl::get_key())

View File

@ -1546,7 +1546,7 @@ static int fake_X_wm_style(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, in
W = r.right - r.left;
H = r.bottom - r.top;
bx = w->x() - r.left;
by = r.bottom - w->y() - w->h(); // height of the bootm frame
by = r.bottom - w->y() - w->h(); // height of the bottom frame
bt = w->y() - r.top - by; // height of top caption bar
xoff = bx;
yoff = by + bt;
@ -2697,81 +2697,90 @@ FL_EXPORT Window fl_xid_(const Fl_Window *w) {
return temp ? temp->xid : 0;
}
static RECT border_width_title_bar_height(Fl_Window *win, int &bx, int &by, int &bt)
{
RECT r = {0,0,0,0};
bx = by = bt = 0;
if (win->shown() && !win->parent() && win->border() && win->visible()) {
static HMODULE dwmapi_dll = LoadLibrary("dwmapi.dll");
typedef HRESULT (WINAPI* DwmGetWindowAttribute_type)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
static DwmGetWindowAttribute_type DwmGetWindowAttribute = dwmapi_dll ?
(DwmGetWindowAttribute_type)GetProcAddress(dwmapi_dll, "DwmGetWindowAttribute") : NULL;
int need_r = 1;
if (DwmGetWindowAttribute) {
const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9;
if ( DwmGetWindowAttribute(fl_xid(win), DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK ) {
need_r = 0;
}
}
if (need_r) {
GetWindowRect(fl_xid(win), &r);
}
bx = (r.right - r.left - win->w())/2;
by = bx;
bt = r.bottom - r.top - win->h() - 2*by;
}
return r;
}
int Fl_Window::decorated_w()
{
if (!shown() || parent() || !border() || !visible()) return w();
int X, Y, bt, bx, by;
Fl_X::fake_X_wm(this, X, Y, bt, bx, by);
int bt, bx, by;
border_width_title_bar_height(this, bx, by, bt);
return w() + 2 * bx;
}
int Fl_Window::decorated_h()
{
if (!shown() || parent() || !border() || !visible()) return h();
int X, Y, bt, bx, by;
Fl_X::fake_X_wm(this, X, Y, bt, bx, by);
int bt, bx, by;
border_width_title_bar_height(this, bx, by, bt);
return h() + bt + 2 * by;
}
void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders.
On the WIN32 platform, this function exploits a feature of fl_read_image() which, when called
with NULL first argument and when fl_gc is set to the screen device context, captures the window decoration.
*/
void Fl_X::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right)
{
if (!win->shown() || win->parent() || !win->border() || !win->visible())
print_widget(win, x_offset, y_offset);
else
draw_decorated_window(win, x_offset, y_offset, this);
}
void Fl_Paged_Device::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset, Fl_Surface_Device *toset)
{
static HMODULE dwmapi_dll = LoadLibrary("dwmapi.dll");
typedef HRESULT (WINAPI* DwmGetWindowAttribute_type)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
static DwmGetWindowAttribute_type DwmGetWindowAttribute = 0;
static const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9;
int bt, bx, by; // compute the window border sizes
RECT r;
int need_r = 1;
if (dwmapi_dll) {
if (!DwmGetWindowAttribute) DwmGetWindowAttribute = (DwmGetWindowAttribute_type)GetProcAddress(dwmapi_dll, "DwmGetWindowAttribute");
if (DwmGetWindowAttribute) {
if ( DwmGetWindowAttribute(fl_xid(win), DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK ) {
need_r = 0;
}
}
}
if (need_r) {
GetWindowRect(fl_xid(win), &r);
}
bx = (r.right - r.left - win->w())/2;
by = bx;
bt = r.bottom - r.top - win->h() - 2*by;
int ww = win->w() + 2 * bx;
int wh = win->h() + bt + 2 * by;
Fl_Display_Device::display_device()->set_current(); // make window current
win->show();
Fl::check();
win->make_current();
top = left = bottom = right = NULL;
if (!w->shown() || w->parent() || !w->border() || !w->visible()) return;
int wsides, hbottom, bt;
RECT r = border_width_title_bar_height(w, wsides, hbottom, bt);
int htop = bt + hbottom;
HDC save_gc = fl_gc;
fl_gc = GetDC(NULL); // get the screen device context
// capture the 4 window sides from screen
Window save_win = fl_window;
Fl_Surface_Device *previous = Fl_Surface_Device::surface();
Fl_Display_Device::display_device()->set_current();
w->show();
Fl::check();
w->make_current();
fl_gc = GetDC(NULL); // get the screen device context
int ww = w->w() + 2 * wsides;
// capture the 4 window sides from screen
fl_window = NULL; // force use of read_win_rectangle() by fl_read_image()
uchar *top_image = fl_read_image(NULL, r.left, r.top, ww, bt + by);
uchar *left_image = bx ? fl_read_image(NULL, r.left, r.top, bx, wh) : NULL;
uchar *right_image = bx ? fl_read_image(NULL, r.right - bx, r.top, bx, wh) : NULL;
uchar *bottom_image = by ? fl_read_image(NULL, r.left, r.bottom-by, ww, by) : NULL;
uchar *rgb;
if (htop) {
rgb = fl_read_image(NULL, r.left, r.top, ww, htop);
top = new Fl_RGB_Image(rgb, ww, htop, 3);
top->alloc_array = 1;
}
if (wsides) {
rgb = fl_read_image(NULL, r.left, r.top + htop, wsides, w->h());
left = new Fl_RGB_Image(rgb, wsides, w->h(), 3);
left->alloc_array = 1;
rgb = fl_read_image(NULL, r.right - wsides, r.top + htop, wsides, w->h());
right = new Fl_RGB_Image(rgb, wsides, w->h(), 3);
right->alloc_array = 1;
rgb = fl_read_image(NULL, r.left, r.bottom-hbottom, ww, hbottom);
bottom = new Fl_RGB_Image(rgb, ww, hbottom, 3);
bottom->alloc_array = 1;
}
ReleaseDC(NULL, fl_gc);
fl_window = save_win;
ReleaseDC(NULL, fl_gc); fl_gc = save_gc;
toset->set_current();
// print the 4 window sides
fl_draw_image(top_image, x_offset, y_offset, ww, bt + by, 3); delete[] top_image;
if (left_image) { fl_draw_image(left_image, x_offset, y_offset, bx, wh, 3); delete left_image; }
if (right_image) { fl_draw_image(right_image, x_offset + win->w() + bx, y_offset, bx, wh, 3); delete right_image; }
if (bottom_image) { fl_draw_image(bottom_image, x_offset, y_offset + win->h() + bt + by, ww, by, 3); delete bottom_image; }
// print the window inner part
this->print_widget(win, x_offset + bx, y_offset + bt + by);
fl_gc = GetDC(fl_xid(win));
ReleaseDC(fl_xid(win), fl_gc);
}
fl_gc = save_gc;
previous->Fl_Surface_Device::set_current();
}
#ifdef USE_PRINT_BUTTON
// to test the Fl_Printer class creating a "Print front window" button in a separate window

View File

@ -3021,59 +3021,52 @@ int Fl_Window::decorated_w()
return w;
}
void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
{
if (!win->shown() || win->parent() || !win->border() || !win->visible()) {
this->print_widget(win, x_offset, y_offset);
return;
}
draw_decorated_window(win, x_offset, y_offset, this);
}
void Fl_Paged_Device::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset, Fl_Surface_Device *toset)
/* Returns images of the captures of the window title-bar, and the left, bottom and right window borders
(or NULL if a particular border is absent).
Returned images can be deleted after use. Their depth and size may be platform-dependent.
The top and bottom images extend from left of the left border to right of the right border.
On the X11 platform, this function exploits a feature of fl_read_image() which, when called
with negative 4th argument, captures the window decoration.
*/
void Fl_X::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right)
{
top = left = bottom = right = NULL;
if (w->decorated_h() == w->h()) return;
Window from = fl_window;
Fl_Surface_Device *previous = Fl_Surface_Device::surface();
Fl_Display_Device::display_device()->set_current();
win->show();
w->show();
Fl::check();
win->make_current();
Window root, parent, *children, child_win, from;
w->make_current();
Window root, parent, *children, child_win;
unsigned n = 0;
int bx, bt, do_it;
from = fl_window;
do_it = (XQueryTree(fl_display, fl_window, &root, &parent, &children, &n) != 0 &&
XTranslateCoordinates(fl_display, fl_window, parent, 0, 0, &bx, &bt, &child_win) == True);
int do_it;
int wsides, htop;
do_it = (XQueryTree(fl_display, fl_window, &root, &parent, &children, &n) != 0 &&
XTranslateCoordinates(fl_display, fl_window, parent, 0, 0, &wsides, &htop, &child_win) == True);
if (n) XFree(children);
// hack to bypass STR #2648: when compiz is used, root and parent are the same window
// and I don't know where to find the window decoration
if (do_it && root == parent) do_it = 0;
if (!do_it) {
this->set_current();
this->print_widget(win, x_offset, y_offset);
return;
}
int hbottom = wsides;
fl_window = parent;
uchar *top_image = 0, *left_image = 0, *right_image = 0, *bottom_image = 0;
top_image = fl_read_image(NULL, 0, 0, - (win->w() + 2 * bx), bt);
if (bx) {
left_image = fl_read_image(NULL, 0, bt, -bx, win->h() + bx);
right_image = fl_read_image(NULL, win->w() + bx, bt, -bx, win->h() + bx);
bottom_image = fl_read_image(NULL, 0, bt + win->h(), -(win->w() + 2*bx), bx);
uchar *rgb;
if (htop) {
rgb = fl_read_image(NULL, 0, 0, - (w->w() + 2 * wsides), htop);
top = new Fl_RGB_Image(rgb, w->w() + 2 * wsides, htop, 3);
top->alloc_array = 1;
}
if (wsides) {
rgb = fl_read_image(NULL, 0, htop, -wsides, w->h());
left = new Fl_RGB_Image(rgb, wsides, w->h(), 3);
left->alloc_array = 1;
rgb = fl_read_image(NULL, w->w() + wsides, htop, -wsides, w->h());
right = new Fl_RGB_Image(rgb, wsides, w->h(), 3);
right->alloc_array = 1;
rgb = fl_read_image(NULL, 0, htop + w->h(), -(w->w() + 2*wsides), hbottom);
bottom = new Fl_RGB_Image(rgb, w->w() + 2*wsides, hbottom, 3);
bottom->alloc_array = 1;
}
fl_window = from;
toset->set_current();
if (top_image) {
fl_draw_image(top_image, x_offset, y_offset, win->w() + 2 * bx, bt, 3);
delete[] top_image;
}
if (bx) {
if (left_image) fl_draw_image(left_image, x_offset, y_offset + bt, bx, win->h() + bx, 3);
if (right_image) fl_draw_image(right_image, x_offset + win->w() + bx, y_offset + bt, bx, win->h() + bx, 3);
if (bottom_image) fl_draw_image(bottom_image, x_offset, y_offset + bt + win->h(), win->w() + 2*bx, bx, 3);
if (left_image) delete[] left_image;
if (right_image) delete[] right_image;
if (bottom_image) delete[] bottom_image;
}
this->print_widget( win, x_offset + bx, y_offset + bt );
previous->Fl_Surface_Device::set_current();
}
#ifdef USE_PRINT_BUTTON

View File

@ -551,15 +551,30 @@ 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);
Fl_Image_Surface *rgb_surf;
int W, H, decorated;
if (target->as_window() && !target->parent()) {
W = target->as_window()->decorated_w();
H = target->as_window()->decorated_h();
decorated = 1;
}
else {
W = target->w();
H = target->h();
decorated = 0;
}
rgb_surf = new Fl_Image_Surface(W, H);
rgb_surf->set_current();
fl_color(FL_BLUE);fl_rectf(0,0,1000,1000);
rgb_surf->draw(target,10,5);
if (decorated)
rgb_surf->draw_decorated_window(target->as_window());
else
rgb_surf->draw(target);
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);
Fl_Window* g2 = new Fl_Window(img->w()+10, img->h()+10);
g2->color(FL_YELLOW);
Fl_Box *b = new Fl_Box(FL_NO_BOX,5,5,img->w(), img->h(),0);
b->image(img);
g2->end();
g2->show();
@ -709,7 +724,7 @@ int main(int argc, char ** argv) {
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 = new Fl_Radio_Round_Button(170,5,150,12, "Decorated 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);