Add one argument to Fl_Screen_Driver::read_win_rectangle()

The new argument gives the window to be captured, or NULL to indicate capture
from the current offscreen.
Calling this function becomes easier because less dependent on global variables.
This commit is contained in:
ManoloFLTK
2019-06-06 18:28:49 +02:00
parent 50b1c08780
commit 94fffb701c
15 changed files with 42 additions and 44 deletions

View File

@@ -150,8 +150,10 @@ public:
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
Fl_XXX_Window_Driver::capture_titlebar_and_borders().
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) {return NULL;}
virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win) {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

@@ -196,8 +196,7 @@ Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, int x, in
full_img = plugin->rectangle_capture(g, x, y, w, h);
}
else if ( g->as_window() ) {
if (Fl_Window::current() != g) g->as_window()->make_current();
full_img = Fl::screen_driver()->read_win_rectangle(x, y, w, h);
full_img = Fl::screen_driver()->read_win_rectangle(x, y, w, h, g->as_window());
}
if (!full_img) return NULL;
float full_img_scale = (full_img && w > 0 ? float(full_img->data_w())/w : 1);

View File

@@ -2719,14 +2719,14 @@ void Fl_WinAPI_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image *&top, F
// capture the 4 window sides from screen
Fl_WinAPI_Screen_Driver *dr = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver();
if (htop) {
top = dr->read_win_rectangle_unscaled(r.left, r.top, r.right - r.left, htop);
top = dr->read_win_rectangle_unscaled(r.left, r.top, r.right - r.left, htop, 0);
if (scaling != 1)
top->scale(ww, htop / scaling, 0, 1);
}
if (wsides) {
left = dr->read_win_rectangle_unscaled(r.left, r.top + htop, wsides, h() * scaling);
right = dr->read_win_rectangle_unscaled(r.right - wsides, r.top + htop, wsides, h() * scaling);
bottom = dr->read_win_rectangle_unscaled(r.left, r.bottom - hbottom, ww, hbottom);
left = dr->read_win_rectangle_unscaled(r.left, r.top + htop, wsides, h() * scaling, 0);
right = dr->read_win_rectangle_unscaled(r.right - wsides, r.top + htop, wsides, h() * scaling, 0);
bottom = dr->read_win_rectangle_unscaled(r.left, r.bottom - hbottom, ww, hbottom, 0);
if (scaling != 1) {
left->scale(wsides, h(), 0, 1);
right->scale(wsides, h(), 0, 1);

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);
virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win);
private:
float scale_;
};

View File

@@ -339,11 +339,11 @@ 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_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window)
{
int bpp, bpr, depth = 4;
uchar *base, *p;
if (!fl_window) { // read from offscreen buffer
if (!window) { // read from offscreen buffer
float s = 1;
CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context
base = (uchar *)CGBitmapContextGetData(src); // get data
@@ -373,7 +373,7 @@ 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(Fl_Window::current());
Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window);
CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, false);
if (!cgimg) {
return NULL;

View File

@@ -89,7 +89,7 @@ void Fl_GDI_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image()
{
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height);
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height, 0);
return image;
}

View File

@@ -75,8 +75,8 @@ 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_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h);
virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win);
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();
virtual void disable_im();

View File

@@ -501,7 +501,8 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle(
int X, // I - Left position
int Y, // I - Top position
int w, // I - Width of area to read
int h) // I - Height 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
{
float s = Fl_Surface_Device::surface()->driver()->scale();
int ws, hs;
@@ -512,10 +513,10 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle(
if (ws < 1) ws = 1;
if (hs < 1) hs = 1;
}
return read_win_rectangle_unscaled(X*s, Y*s, ws, hs);
return read_win_rectangle_unscaled(X*s, Y*s, ws, hs, win);
}
Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h)
Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win)
{
int d = 3; // Depth of image
int alpha = 0; uchar *p = NULL;
@@ -569,6 +570,7 @@ Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y,
bi.bmiHeader.biClrImportant = 0;
// copy bitmap from original DC (Window, Fl_Offscreen, ...)
if (win && Fl_Window::current() != win) win->make_current();
HDC gc = (HDC)fl_graphics_driver->gc();
HDC hdc = CreateCompatibleDC(gc);
HBITMAP hbm = CreateCompatibleBitmap(gc,w,h);

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);
virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win);
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_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win)
{
XImage *image; // Captured image
int i, maxindex; // Looping vars
@@ -772,12 +772,14 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
int allow_outside = w < 0; // negative w allows negative X or Y, that is, window frame
if (w < 0) w = - w;
float s = allow_outside ? Fl::screen_driver()->scale(Fl_Window::current()->screen_num()) : Fl_Surface_Device::surface()->driver()->scale();
Window xid = (win && !allow_outside ? fl_xid(win) : fl_window);
float s = allow_outside ? Fl::screen_driver()->scale(win->screen_num()) : Fl_Surface_Device::surface()->driver()->scale();
int ws = w * s, hs = h * s, Xs = X*s, Ys = Y*s;
# ifdef __sgi
if (XReadDisplayQueryExtension(fl_display, &i, &i)) {
image = XReadDisplay(fl_display, fl_window, Xs, Ys, ws, hs, 0, NULL);
image = XReadDisplay(fl_display, xid, Xs, Ys, ws, hs, 0, NULL);
} else
# else
image = 0;
@@ -788,11 +790,8 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
int dx, dy, sx, sy, sw, sh;
Window child_win;
Fl_Window *win;
if (allow_outside) win = Fl_Window::current();
else win = fl_find(fl_window);
if (win) {
XTranslateCoordinates(fl_display, fl_window,
XTranslateCoordinates(fl_display, xid,
RootWindow(fl_display, fl_screen), Xs, Ys, &dx, &dy, &child_win);
// screen dimensions
Fl::screen_xywh(sx, sy, sw, sh, Fl_Window_Driver::driver(win)->screen_num());
@@ -811,7 +810,7 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
// however, if the window is obscured etc. the function will still fail. Make sure we
// catch the error and continue, otherwise an exception will be thrown.
XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
image = XGetImage(fl_display, fl_window, Xs, Ys, ws, hs, AllPlanes, ZPixmap);
image = XGetImage(fl_display, xid, Xs, Ys, ws, hs, AllPlanes, ZPixmap);
XSetErrorHandler(old_handler);
} else {
// image is crossing borders, determine visible region
@@ -831,7 +830,7 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
}
XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
XImage *subimg = XGetSubImage(fl_display, fl_window, Xs + noffx, Ys + noffy,
XImage *subimg = XGetSubImage(fl_display, xid, Xs + noffx, Ys + noffy,
nw, nh, AllPlanes, ZPixmap, image, noffx, noffy);
XSetErrorHandler(old_handler);
if (!subimg) {

View File

@@ -392,16 +392,14 @@ void Fl_X11_Window_Driver::free_icons() {
This function exploits a feature of Fl_X11_Screen_Driver::read_win_rectangle() which,
when called with negative 3rd argument, captures the window decoration.
Other requirements to capture the window decoration:
- fl_window is the parent window of the top window
- Fl_Window::current() is the top window
Other requirement to capture the window decoration:
fl_window is the parent window of the top window
*/
void Fl_X11_Window_Driver::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 (pWindow->decorated_h() == h()) return;
Window from = fl_window;
Fl_Window *oldcurrent = Fl_Window::current();
Window root, parent, *children, child_win, xid = fl_xid(pWindow);
unsigned n = 0;
int do_it;
@@ -414,25 +412,23 @@ void Fl_X11_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_R
float s = Fl::screen_driver()->scale(screen_num());
htop /= s; wsides /= s;
fl_window = parent;
current(pWindow);
if (htop) {
top = Fl::screen_driver()->read_win_rectangle(0, 0, - (w() + 2 * wsides), htop);
top = Fl::screen_driver()->read_win_rectangle(0, 0, - (w() + 2 * wsides), htop, pWindow);
if (top) top->scale(w() + 2 * wsides, htop, 0, 1);
}
if (wsides) {
left = Fl::screen_driver()->read_win_rectangle(0, htop, -wsides, h());
left = Fl::screen_driver()->read_win_rectangle(0, htop, -wsides, h(), pWindow);
if (left) {
left->scale(wsides, h(), 0, 1);
}
right = Fl::screen_driver()->read_win_rectangle(w() + wsides, htop, -wsides, h());
right = Fl::screen_driver()->read_win_rectangle(w() + wsides, htop, -wsides, h(), pWindow);
if (right) {
right->scale(wsides, h(), 0, 1);
}
bottom = Fl::screen_driver()->read_win_rectangle(0, htop + h(), -(w() + 2*wsides), hbottom);
bottom = Fl::screen_driver()->read_win_rectangle(0, htop + h(), -(w() + 2*wsides), hbottom, pWindow);
if (bottom) {
bottom->scale(w() + 2*wsides, wsides, 0, 1);
} }
current(oldcurrent);
fl_window = from;
}

View File

@@ -64,7 +64,7 @@ Fl_Xlib_Copy_Surface_Driver::~Fl_Xlib_Copy_Surface_Driver() {
driver()->pop_clip();
bool need_push = !is_current();
if (need_push) Fl_Surface_Device::push_current(this);
Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(0, 0, width, height);
Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0);
if (need_push) Fl_Surface_Device::pop_current();
Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1);
delete rgb;

View File

@@ -74,7 +74,7 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image()
{
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height);
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0);
return image;
}

View File

@@ -68,19 +68,19 @@ static void draw_current_rect() {
if (s_bgE) { delete s_bgE; s_bgE = 0; }
if (s_bgW) { delete s_bgW; s_bgW = 0; }
if (pw>0 && ph>0) {
s_bgE = Fl::screen_driver()->read_win_rectangle( px+pw-1, py, 1, ph);
s_bgE = Fl::screen_driver()->read_win_rectangle( px+pw-1, py, 1, ph, Fl_Window::current());
if(s_bgE && s_bgE->w() && s_bgE->h()) {
s_bgE->scale(1, ph,0,1);
}
s_bgW = Fl::screen_driver()->read_win_rectangle( px, py, 1, ph);
s_bgW = Fl::screen_driver()->read_win_rectangle( px, py, 1, ph, Fl_Window::current());
if(s_bgW && s_bgW->w() && s_bgW->h()) {
s_bgW->scale(1, ph,0,1);
}
s_bgS = Fl::screen_driver()->read_win_rectangle( px, py+ph-1, pw, 1);
s_bgS = Fl::screen_driver()->read_win_rectangle( px, py+ph-1, pw, 1, Fl_Window::current());
if(s_bgS && s_bgS->w() && s_bgS->h()) {
s_bgS->scale(pw, 1,0,1);
}
s_bgN = Fl::screen_driver()->read_win_rectangle( px, py, pw, 1);
s_bgN = Fl::screen_driver()->read_win_rectangle( px, py, pw, 1, Fl_Window::current());
if(s_bgN && s_bgN->w() && s_bgN->h()) {
s_bgN->scale(pw, 1,0,1);
}

View File

@@ -43,7 +43,7 @@ uchar *fl_read_image(uchar *p, int X, int Y, int w, int h, int alpha) {
uchar *image_data = NULL;
Fl_RGB_Image *img;
if (fl_find(fl_window) == 0) { // read from off_screen buffer
img = Fl::screen_driver()->read_win_rectangle(X, Y, w, h);
img = Fl::screen_driver()->read_win_rectangle(X, Y, w, h, 0);
if (!img) {
return NULL;
}