Fix a case when fl_read_window() did not capture subwindows correctly.

The case was under macOS with a non-GL parent window mapped to a retina display
containing a GL subwindow and if the app did not call Fl::use_high_res_GL(1).
This commit is contained in:
ManoloFLTK 2019-08-21 12:01:01 +02:00
parent 5255640e7a
commit 33eb87940d
9 changed files with 30 additions and 22 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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 );
}

View File

@ -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_;
};

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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