diff options
| author | Manolo Gouy <Manolo> | 2016-04-03 06:51:09 +0000 |
|---|---|---|
| committer | Manolo Gouy <Manolo> | 2016-04-03 06:51:09 +0000 |
| commit | f1ffe2f1fee001ffb3c9327c6c09f5e5d9dc91de (patch) | |
| tree | 58a67c3e8a8f8d651e358efc70d04747321c251b /src/Fl_Screen_Driver.cxx | |
| parent | c88af210e775d90d2537f4277909bb081a9c064a (diff) | |
Rewrite fl_read_image.cxx under the driver model.
Files fl_read_image_mac.cxx and fl_read_image_win32.cxx are no longer used;
their content is now in Fl_XXX_Screen_Driver.cxx
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11516 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Screen_Driver.cxx')
| -rw-r--r-- | src/Fl_Screen_Driver.cxx | 126 |
1 files changed, 123 insertions, 3 deletions
diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index 083922c89..f2071d3cc 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -16,11 +16,13 @@ // http://www.fltk.org/str.php // - -#include "config_lib.h" #include <FL/Fl_Screen_Driver.H> +#include <FL/Fl_Image.H> #include <FL/Fl.H> - +#include <FL/x.H> // for fl_window +#include <FL/Fl_Plugin.H> +#include <FL/Fl_Group.H> +#include <FL/Fl_Window.H> char Fl_Screen_Driver::bg_set = 0; char Fl_Screen_Driver::bg2_set = 0; @@ -149,6 +151,124 @@ void Fl_Screen_Driver::compose_reset() { Fl::compose_state = 0; } +uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int alpha) { + if (w < 0 || fl_find(fl_window) == 0) { // read from off_screen buffer or title bar and frame + return read_win_rectangle(p, X, Y, w, h, alpha); + } + Fl_RGB_Image *img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL); + uchar *image_data = (uchar*)img->array; + img->alloc_array = 0; + delete img; + return image_data; +} + +void Fl_Screen_Driver::write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y) +/* Copy the image "from" inside image "to" with its top-left angle at coordinates to_x, to_y. +Image depth can differ between "to" and "from". +*/ +{ + int to_ld = (to->ld() == 0? to->w() * to->d() : to->ld()); + int from_ld = (from->ld() == 0? from->w() * from->d() : from->ld()); + uchar *tobytes = (uchar*)to->array + to_y * to_ld + to_x * to->d(); + const uchar *frombytes = from->array; + for (int i = 0; i < from->h(); i++) { + if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d()); + else { + for (int j = 0; j < from->w(); j++) { + memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d()); + } + } + tobytes += to_ld; + frombytes += from_ld; + } +} + + +/* Captures rectangle x,y,w,h from a mapped window or GL window. + All sub-GL-windows that intersect x,y,w,h, and their subwindows, are also captured. + + Arguments when this function is initially called: + g: a window or GL window + p: as in fl_read_image() + x,y,w,h: a rectangle in window g's coordinates + alpha: as in fl_read_image() + full_img: NULL + + Arguments when this function recursively calls itself: + g: an Fl_Group + p: as above + x,y,w,h: a rectangle in g's coordinates if g is a window, or in g's parent window coords if g is a group + alpha: as above + full_img: NULL, or a previously captured image that encompasses the x,y,w,h rectangle and that + will be partially overwritten with the new capture + + Return value: + An Fl_RGB_Image* of depth 4 if alpha>0 or 3 if alpha = 0 containing the captured pixels. + */ +Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, + Fl_RGB_Image *full_img) +{ + if ( g->as_gl_window() ) { + Fl_Plugin_Manager pm("fltk:device"); + Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org"); + if (!pi) return full_img; + Fl_RGB_Image *img = pi->rectangle_capture(g, x, y, w, h); + if (full_img) full_img = img; + else { + uchar *data = ( p ? p : new uchar[img->w() * img->h() * (alpha?4:3)] ); + full_img = new Fl_RGB_Image(data, img->w(), img->h(), alpha?4:3); + if (!p) full_img->alloc_array = 1; + if (alpha) memset(data, alpha, img->w() * img->h() * 4); + write_image_inside(full_img, img, 0, 0); + delete img; + } + } + else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) { + // the starting window or one inside a GL window + if (full_img) g->as_window()->make_current(); + uchar *image_data; + int alloc_img = (full_img != NULL || p == NULL); // false means use p, don't alloc new memory for image + // on Darwin + X11, read_win_rectangle() sometimes returns NULL when there are subwindows, + // thus the call is repeated + do image_data = Fl::screen_driver()->read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha); while (!image_data); + full_img = new Fl_RGB_Image(image_data, w, h, alpha?4:3); + if (alloc_img) full_img->alloc_array = 1; + } + int n = g->children(); + for (int i = 0; i < n; i++) { + Fl_Widget *c = g->child(i); + if ( !c->visible() || !c->as_group()) continue; + if ( c->as_window() ) { + int origin_x = x; // compute intersection of x,y,w,h and the c window + if (x < c->x()) origin_x = c->x(); + int origin_y = y; + if (y < c->y()) origin_y = c->y(); + int width = c->w(); + if (origin_x + width > c->x() + c->w()) width = c->x() + c->w() - origin_x; + if (origin_x + width > x + w) width = x + w - origin_x; + int height = c->w(); + if (origin_y + height > c->y() + c->h()) height = c->y() + c->h() - origin_y; + if (origin_y + height > y + h) height = y + h - origin_y; + if (width > 0 && height > 0) { + Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), p, origin_x - c->x(), + origin_y - c->y(), width, height, alpha, full_img); + if (img == full_img) continue; + int top; + if (c->as_gl_window()) { + top = origin_y - y; + } else { + top = full_img->h() - (origin_y - y + img->h()); + } + write_image_inside(full_img, img, origin_x - x, top); + delete img; + } + } + else traverse_to_gl_subwindows(c->as_group(), p, x, y, w, h, alpha, full_img); + } + return full_img; +} + + // // End of "$Id$". // |
