diff --git a/src/Fl_Screen_Driver.H b/src/Fl_Screen_Driver.H index 511f892d2..05924812c 100644 --- a/src/Fl_Screen_Driver.H +++ b/src/Fl_Screen_Driver.H @@ -136,16 +136,17 @@ public: // we no longer need the on-screen keyboard; it's up to the system to hide it virtual void release_keyboard() { } - // read raw image from a window or an offscreen buffer - /* Member function read_win_rectangle() supports the public function - fl_read_image() which captures pixel data either from - the current window or from an offscreen buffer. - - With fl_read_image() and for capture from a window, the returned pixel array - also contains data from any embedded sub-window. + /* Member function read_win_rectangle() supports public functions + fl_read_image() and fl_capture_window_part() which capture pixel data from + a window (or also from an offscreen buffer with fl_read_image). - In the case of read_win_rectangle() and for capture from a window, only data - from the current window is collected. + If 'may_capture_subwins' is true, an implementation may or may not capture + also the content of subwindows embedded in 'win'. If subwindows were captured, + *'did_capture_subwins' is returned set to true. If read_win_rectangle() + is called with 'may_capture_subwins' set to true, 'did_capture_subwins' should + be set before the call to the address of a boolean set to false. + The implementation of this virtual function for the macOS platform has the + capability of capturing subwindows when asked for. A platform may also use its read_win_rectangle() implementation to capture window decorations (e.g., title bar). In that case, it is called by @@ -153,7 +154,8 @@ public: win is the window to capture from, or NULL to capture from the current offscreen */ - virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win) {return NULL;} + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, + bool may_capture_subwins = false, bool *did_capture_subwins = NULL) {return NULL;} static void write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y); static Fl_RGB_Image *traverse_to_gl_subwindows(Fl_Group *g, int x, int y, int w, int h, Fl_RGB_Image *full_img); diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index cc54d53cb..c18cd40d3 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -190,17 +190,18 @@ Image depths can differ between "to" and "from". Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, int x, int y, int w, int h, Fl_RGB_Image *full_img) { + bool captured_subwin = false; if ( g->as_gl_window() ) { Fl_Device_Plugin *plugin = Fl_Device_Plugin::opengl_plugin(); if (!plugin) return full_img; full_img = plugin->rectangle_capture(g, x, y, w, h); } else if ( g->as_window() ) { - full_img = Fl::screen_driver()->read_win_rectangle(x, y, w, h, g->as_window()); + full_img = Fl::screen_driver()->read_win_rectangle(x, y, w, h, g->as_window(), true, &captured_subwin); } if (!full_img) return NULL; float full_img_scale = (full_img && w > 0 ? float(full_img->data_w())/w : 1); - int n = g->children(); + int n = (captured_subwin ? 0 : g->children()); for (int i = 0; i < n; i++) { Fl_Widget *c = g->child(i); if ( !c->visible() || !c->as_group()) continue; diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index c99d73aab..226d093e3 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -4255,13 +4255,13 @@ static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, #endif } } - if (!bitmap) return nil; + if (!capture_subwins || !bitmap) return bitmap; // capture also subwindows NSArray *children = [fl_xid(win) childWindows]; // 10.2 NSEnumerator *enumerator = [children objectEnumerator]; id child; - while (capture_subwins && ((child = [enumerator nextObject]) != nil)) { + while ((child = [enumerator nextObject]) != nil) { if (![child isKindOfClass:[FLWindow class]]) continue; Fl_Window *sub = [(FLWindow*)child getFl_Window]; CGRect rsub = CGRectMake(sub->x(), win->h() -(sub->y()+sub->h()), sub->w(), sub->h()); @@ -4272,7 +4272,9 @@ static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, win->h() - clip.origin.y - sub->y() - clip.size.height, clip.size.width, clip.size.height); if (childbitmap) { // if bitmap is high res and childbitmap is not, childbitmap must be rescaled - if ([bitmap pixelsWide] > w && [childbitmap pixelsWide] == clip.size.width) childbitmap = scale_nsbitmapimagerep(childbitmap, 2); + if (!win->as_gl_window() && Fl_Cocoa_Window_Driver::driver(win)->mapped_to_retina() && sub->as_gl_window() && !Fl::use_high_res_GL()) { + childbitmap = scale_nsbitmapimagerep(childbitmap, 2); + } write_bitmap_inside(bitmap, w*s, childbitmap, (clip.origin.x - x)*s, (win->h() - clip.origin.y - clip.size.height - y)*s ); } diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H index 2b329367b..faf5b8520 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H @@ -99,7 +99,7 @@ public: virtual APP_SCALING_CAPABILITY rescalable() { return SYSTEMWIDE_APP_SCALING; } virtual float scale(int n) {return scale_;} virtual void scale(int n, float f) { scale_ = f;} - virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win); + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins); private: float scale_; }; diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index d3ec31fdf..34e1c80fd 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -339,7 +339,8 @@ void Fl_Cocoa_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &h height = CGBitmapContextGetHeight(off); } -Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window) +Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window, + bool may_capture_subwins, bool *did_capture_subwins) { int bpp, bpr, depth = 4; uchar *base, *p; @@ -374,7 +375,8 @@ Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, in bpr = 0; } else { // read from window Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, false); + CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, may_capture_subwins); + if (did_capture_subwins) *did_capture_subwins = may_capture_subwins; if (!cgimg) { return NULL; } diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index 09beb1108..11a923331 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -75,7 +75,7 @@ public: virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int dnd(int unused); virtual int compose(int &del); - virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win); + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins); Fl_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win); virtual int get_mouse(int &x, int &y); virtual void enable_im(); diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 5eff35d9d..edbfba577 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -488,7 +488,8 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle( int Y, // I - Top position int w, // I - Width of area to read int h, // I - Height of area to read - Fl_Window *win) // I - window to capture from or NULL to capture from current offscreen + Fl_Window *win, // I - window to capture from or NULL to capture from current offscreen + bool may_capture_subwins, bool *did_capture_subwins) { float s = Fl_Surface_Device::surface()->driver()->scale(); int ws, hs; diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.H b/src/drivers/X11/Fl_X11_Screen_Driver.H index 7b14d4375..09b043c71 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.H +++ b/src/drivers/X11/Fl_X11_Screen_Driver.H @@ -95,7 +95,7 @@ public: virtual int compose(int &del); virtual void compose_reset(); virtual int text_display_can_leak(); - virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win); + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins); virtual int get_mouse(int &x, int &y); virtual void enable_im(); virtual void disable_im(); diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/src/drivers/X11/Fl_X11_Screen_Driver.cxx index ed703f78d..d13562ea9 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -745,7 +745,7 @@ extern "C" { } } -Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win) +Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins) { XImage *image; // Captured image int i, maxindex; // Looping vars