From eeb65bef23b2d269ea38474c04a55ffca5c6e63e Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Sun, 10 Jan 2016 19:08:16 +0000 Subject: 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 --- FL/Fl_Image_Surface.H | 1 + FL/Fl_Paged_Device.H | 12 +--- FL/mac.H | 1 + FL/win32.H | 1 + FL/x.H | 1 + src/Fl_Copy_Surface.cxx | 14 +--- src/Fl_Image_Surface.cxx | 49 ++++++++----- src/Fl_Paged_Device.cxx | 41 ++++++++++- src/Fl_cocoa.mm | 179 +++++++++++++++++++++++------------------------ src/Fl_win32.cxx | 129 ++++++++++++++++++---------------- src/Fl_x.cxx | 83 ++++++++++------------ test/device.cxx | 27 +++++-- 12 files changed, 295 insertions(+), 243 deletions(-) diff --git a/FL/Fl_Image_Surface.H b/FL/Fl_Image_Surface.H index 955576610..d6ed05e55 100644 --- a/FL/Fl_Image_Surface.H +++ b/FL/Fl_Image_Surface.H @@ -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__ diff --git a/FL/Fl_Paged_Device.H b/FL/Fl_Paged_Device.H index 9dd6b7d8d..968f87b74 100644 --- a/FL/Fl_Paged_Device.H +++ b/FL/Fl_Paged_Device.H @@ -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. diff --git a/FL/mac.H b/FL/mac.H index a8a6fc271..31ff624fd 100644 --- a/FL/mac.H +++ b/FL/mac.H @@ -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); diff --git a/FL/win32.H b/FL/win32.H index 657a66d9f..c7f689ede 100644 --- a/FL/win32.H +++ b/FL/win32.H @@ -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; diff --git a/FL/x.H b/FL/x.H index 2358ed003..5f3d80279 100644 --- a/FL/x.H +++ b/FL/x.H @@ -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: diff --git a/src/Fl_Copy_Surface.cxx b/src/Fl_Copy_Surface.cxx index 1f0b654c5..a0b942b67 100644 --- a/src/Fl_Copy_Surface.cxx +++ b/src/Fl_Copy_Surface.cxx @@ -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__) diff --git a/src/Fl_Image_Surface.cxx b/src/Fl_Image_Surface.cxx index b73561fe4..79f5c28d3 100644 --- a/src/Fl_Image_Surface.cxx +++ b/src/Fl_Image_Surface.cxx @@ -34,31 +34,27 @@ 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__) -#elif defined(WIN32) -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - gc = 0; - if (!fl_gc) { // 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__ + 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 + gc = 0; + if (!fl_gc) { // 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; + } + offscreen = fl_create_offscreen(w, h); 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$". diff --git a/src/Fl_Paged_Device.cxx b/src/Fl_Paged_Device.cxx index f3b5f21fe..eae08ef62 100644 --- a/src/Fl_Paged_Device.cxx +++ b/src/Fl_Paged_Device.cxx @@ -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$". // diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index f605df0f4..45dd10fc0 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -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()) diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 2ae1e6145..ea4a43fac 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -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) -{ - 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) +/* 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) { - 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; + 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 - Window save_win = fl_window; 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 diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index f860f9b71..c8a7620eb 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -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 diff --git a/test/device.cxx b/test/device.cxx index 1ad26890f..971e4eee7 100644 --- a/test/device.cxx +++ b/test/device.cxx @@ -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); -- cgit v1.2.3