summaryrefslogtreecommitdiff
path: root/src/Fl_Screen_Driver.cxx
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2016-04-03 06:51:09 +0000
committerManolo Gouy <Manolo>2016-04-03 06:51:09 +0000
commitf1ffe2f1fee001ffb3c9327c6c09f5e5d9dc91de (patch)
tree58a67c3e8a8f8d651e358efc70d04747321c251b /src/Fl_Screen_Driver.cxx
parentc88af210e775d90d2537f4277909bb081a9c064a (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.cxx126
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$".
//