From 2404122a7f79c3adeda322eba60d26e3d8470acf Mon Sep 17 00:00:00 2001 From: Hyoyoung Chang Date: Mon, 18 Oct 2010 17:14:15 +0900 Subject: [PATCH] add screencapture feature --- CMakeLists.txt | 3 + debian/control | 2 +- src/scrcapture.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/scrcapture.h | 18 ++++ src/xcnphandler.c | 33 +++++++ 5 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 src/scrcapture.c create mode 100644 src/scrcapture.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f0b489c..90aabde 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ SET(SRCS src/cbhm_main.c src/clipdrawer.c src/storage.c src/xcnphandler.c + src/scrcapture.c ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) @@ -15,6 +16,8 @@ pkg_check_modules(pkgs REQUIRED elementary appcore-efl appcore-common x11 ecore- FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) +#for XV extension screenshot +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -L/usr/lib -lscreenshot") #SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -finstrument-functions") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") diff --git a/debian/control b/debian/control index 8931780..84b0a92 100755 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: cbhm Section: devel Priority: extra Maintainer: Hyoyoung Chang -Build-Depends: debhelper (>= 5), libelm-dev, libappcore-efl-dev, libappcore-common-dev, libx11-dev, libecore-dev, libslp-utilx-dev +Build-Depends: debhelper (>= 5), libelm-dev, libappcore-efl-dev, libappcore-common-dev, libx11-dev, libecore-dev, libslp-utilx-dev, x11-xserver-utils-ex Standards-Version: 0.1.1 Package: cbhm diff --git a/src/scrcapture.c b/src/scrcapture.c new file mode 100644 index 0000000..6c450ce --- /dev/null +++ b/src/scrcapture.c @@ -0,0 +1,282 @@ +#include "xcnphandler.h" +#include "scrcapture.h" + +#include +#include + +#include +#include + +#include + +inline static Ecore_X_Display *get_display(void) +{ + return ecore_x_display_get(); +} + +static int get_window_attribute(Window id, int *depth, Visual **visual, int *width, int *height) +{ +// assert(id); + XWindowAttributes attr; + + printf("XGetWindowAttributes"); + if (!XGetWindowAttributes(get_display(), id, &attr)) { + return -1; + } + + if (attr.map_state == IsViewable && attr.class == InputOutput) { + *depth = attr.depth; + *width = attr.width; + *height= attr.height; + *visual= attr.visual; + } + + return 0; +} + +static Window _get_parent_window( Window id ) +{ + Window root; + Window parent; + Window* children; + unsigned int num; + + fprintf(stderr, "XQeuryTree\n"); + + if (!XQueryTree(get_display(), id, &root, &parent, &children, &num)) + { + return 0; + } + + if( children ) { + fprintf(stderr, "XFree\n"); + XFree(children); + } + + return parent; +} + +static Window find_capture_available_window( Window id, Visual** visual, int* depth, int* width, int* height ) +{ + XWindowAttributes attr; + Window parent = id; + Window orig_id = id; + + if( id == 0 ) { + return (Window) -1; + } + + do { + id = parent; + fprintf(stderr, "## find_capture - XGetWindowAttributes\n"); + + if (!XGetWindowAttributes(get_display(), id, &attr)) + { + return (Window) -1; + } + + parent = _get_parent_window( id ); + + if( attr.map_state == IsViewable + && attr.override_redirect == True + && attr.class == InputOutput && parent == attr.root ) + { + *depth = attr.depth; + *width = attr.width; + *height = attr.height; + *visual = attr.visual; + return id; + } + } while( parent != attr.root && parent != 0 ); //Failed finding a redirected window + + + fprintf(stderr, "## find_capture - cannot find id\n"); + XGetWindowAttributes( get_display(), orig_id, &attr ); + *depth = attr.depth; + *width = attr.width; + *height = attr.height; + *visual = attr.visual; + + return (Window) 0; + +} + +char *scrcapture_screen_capture(Window oid, int *size) +{ + XImage *xim; + XShmSegmentInfo si; + Pixmap pix; + int depth; + int width; + int height; + Visual *visual; + char *captured_image; + Window id; + + id = find_capture_available_window(ecore_x_window_focus_get(), &visual, &depth, &width, &height); + + if (id == 0 || id == -1 || id == oid) + { + fprintf(stderr, "Window : 0x%lX\n", id); + if (get_window_attribute(id, &depth, &visual, &width, &height) < 0) + { + fprintf(stderr, "Failed to get the attributes from 0x%x\n", (unsigned int)id); + return NULL; + } + } + + fprintf(stderr, "WxH : %dx%d\n", width, height); + fprintf(stderr, "Depth : %d\n", depth >> 3); + + // NOTE: just add one more depth.... + si.shmid = shmget(IPC_PRIVATE, width * height * ((depth >> 3)+1), IPC_CREAT | 0666); + if (si.shmid < 0) { + fprintf(stderr, "## error at shmget\n"); + return NULL; + } + si.readOnly = False; + si.shmaddr = shmat(si.shmid, NULL, 0); + if (si.shmaddr == (char*)-1) { + shmdt(si.shmaddr); + shmctl(si.shmid, IPC_RMID, 0); + fprintf(stderr, "## can't get shmat\n"); + return NULL; + } + +/* + if (!need_redirecting) { + Window border; + if (get_border_window(id, &border) < 0) { + need_redirecting = 1; + printf("Failed to find a border, forcely do redirecting\n"); + } else { + id = border; + printf("Border window is found, use it : 0x%X\n", (unsigned int)id); + } + } + + if (need_redirecting) { + printf("XCompositeRedirectWindow"); + XCompositeRedirectWindow(get_display(), id, CompositeRedirectManual); + } +*/ + + fprintf(stderr, "XShmCreateImage\n"); + xim = XShmCreateImage(get_display(), visual, depth, ZPixmap, NULL, &si, width, height); + if (!xim) { + shmdt(si.shmaddr); + shmctl(si.shmid, IPC_RMID, 0); + +/* + if (need_redirecting) { + printf("XCompositeUnredirectWindow"); + XCompositeUnredirectWindow(get_display(), id, CompositeRedirectManual); + } +*/ + return NULL; + } + + *size = xim->bytes_per_line * xim->height; + fprintf(stderr, "## size = %d\n", *size); + xim->data = si.shmaddr; + + fprintf(stderr,"XCompositeNameWindowPixmap\n"); + pix = XCompositeNameWindowPixmap(get_display(), id); + + fprintf(stderr,"XShmAttach\n"); + XShmAttach(get_display(), &si); + + fprintf(stderr,"XShmGetImage\n"); + XShmGetImage(get_display(), pix, xim, 0, 0, 0xFFFFFFFF); + + //XUnmapWindow(disp, id); + //XMapWindow(disp, id); + fprintf(stderr,"XSync\n"); + XSync(get_display(), False); + + fprintf(stderr, "## data dump - start\n"); + + int i = 0; + for (i = 0; i < (*size/1000); i++) + { + fprintf(stderr, "%X", xim->data[i]); + if ((i % 24) == 0) + fprintf(stderr, "\n"); + } + + fprintf(stderr, "## data end - start\n"); + + //sleep(1); + // We can optimize this! + captured_image = calloc(1, *size); + if (captured_image) { + memcpy(captured_image, xim->data, *size); + } else { + perror("calloc"); + } + + fprintf(stderr,"XShmDetach"); + XShmDetach(get_display(), &si); + fprintf(stderr,"XFreePixmap\n"); + XFreePixmap(get_display(), pix); + fprintf(stderr,"XDestroyImage\n"); + XDestroyImage(xim); + +/* + if (need_redirecting) { + printf("XCompositeUnredirectWindow"); + XCompositeUnredirectWindow(get_display(), id, CompositeRedirectManual); + } +*/ + + shmdt(si.shmaddr); + shmctl(si.shmid, IPC_RMID, 0); + return captured_image; +} + +char *scrcapture_capture_screen_by_x11(Window xid, int *size) +{ + XImage *xim; + int depth; + int width; + int height; + Visual *visual; + char *captured_image; + + + fprintf(stderr, "Window : 0x%lX\n", xid); + if (get_window_attribute(xid, &depth, &visual, &width, &height) < 0) + { + fprintf(stderr, "Failed to get the attributes from 0x%x\n", (unsigned int)xid); + return NULL; + } + + fprintf(stderr, "WxH : %dx%d\n", width, height); + fprintf(stderr, "Depth : %d\n", depth >> 3); + + xim = XGetImage (get_display(), xid, 0, 0, + width, height, AllPlanes, ZPixmap); + + *size = xim->bytes_per_line * xim->height; + + captured_image = calloc(1, *size); + if (captured_image) { + memcpy(captured_image, xim->data, *size); + } else { + perror("calloc"); + } + + return captured_image; +} + +char *scrcapture_capture_screen_by_xv_ext(int width, int height) +{ + char *captured_image; + + captured_image = createScreenShot(480, 800); +} + +void scrcapture_release_screen_by_xv_ext(const char *s) +{ + releaseScreenShot(s); +} diff --git a/src/scrcapture.h b/src/scrcapture.h new file mode 100644 index 0000000..3cdb931 --- /dev/null +++ b/src/scrcapture.h @@ -0,0 +1,18 @@ +#ifndef _scrcapture_h_ +#define _scrcapture_h_ + +#include +#include +#include +#include +#include + +// XV extension API - start +const char* createScreenShot(int width, int height); +void releaseScreenShot(const char *ss); +// XV extension API - end + +char *scrcapture_screen_capture_by_x11(Window xid, int *size); +char *scrcapture_screen_capture_by_xv_ext(int width, int height); + +#endif // _scrcapture_h_ diff --git a/src/xcnphandler.c b/src/xcnphandler.c index aa76c35..40b792c 100755 --- a/src/xcnphandler.c +++ b/src/xcnphandler.c @@ -507,6 +507,39 @@ static int _xclient_msg_cb(void *data, int ev_type, void *event) else if (strcmp("show", ev->data.b) == 0) { clipdrawer_activate_view(ad); + +/* +#include "scrcapture.h" + + int imgsize, width, height; + char *img = NULL; + Evas_Object *capture = evas_object_image_add(ad->evas); +// img = scrcapture_capture_screen_by_xv_ext(); + img = scrcapture_capture_screen_by_x11(DefaultRootWindow(g_disp), &imgsize); + + if (capture == NULL) + { + fprintf(stderr, "##capture fail\n"); + return TRUE; + } + + width = 480; height = 800; + evas_object_image_data_set( capture, NULL ); + evas_object_image_size_set( capture, width, height); + evas_object_image_data_set( capture, img ); + evas_object_image_data_update_add(capture, 0, 0, width, height); + evas_object_resize(capture, width, height); + +// elm_win_resize_object_add(ad->win_main, capture); + + if (!evas_object_image_save( capture, "/tmp/ss.png", NULL, NULL)) + { + fprintf(stderr, "##save fail\n"); + return TRUE; + } + + evas_object_del(capture); +*/ } XFlush(g_disp); -- 2.7.4