From c02a64c9fccf90046af891025b8ba799ba27976d Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 9 Jun 2015 09:55:04 +0900 Subject: [PATCH] support screenshot for wayland Change-Id: I02270c68d5b9573f91bedb0f00cf1c3c17ee3936 --- src/efl_util.c | 726 +++++++++++++++++++++++++++++++- src/screenshooter-client-protocol.h | 66 +++ src/screenshooter-protocol.c | 25 ++ src/tizen-buffer-pool-client-protocol.h | 194 +++++++++ src/tizen-buffer-pool-protocol.c | 47 +++ 5 files changed, 1049 insertions(+), 9 deletions(-) create mode 100644 src/screenshooter-client-protocol.h create mode 100644 src/screenshooter-protocol.c create mode 100644 src/tizen-buffer-pool-client-protocol.h create mode 100644 src/tizen-buffer-pool-protocol.c diff --git a/src/efl_util.c b/src/efl_util.c index 8a1a603..3b72a1e 100644 --- a/src/efl_util.c +++ b/src/efl_util.c @@ -20,10 +20,23 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #if X11 +#include +#include +#include +#include +#include #include #include #endif /* end of X11 */ @@ -33,6 +46,8 @@ #include #include "tizen_notification-client-protocol.h" #include "tizen_window_screen-client-protocol.h" +#include "tizen-buffer-pool-client-protocol.h" +#include "screenshooter-client-protocol.h" #endif /* end of WAYLAND */ /* callback handler index */ @@ -49,6 +64,7 @@ typedef struct _Efl_Util_Callback_Info void *data; } Efl_Util_Callback_Info; +#if WAYLAND typedef struct _Efl_Util_Wl_Surface_Lv_Info { void *surface; /* wl_surface */ @@ -63,6 +79,13 @@ typedef struct _Efl_Util_Wl_Surface_Scr_Mode_Info Eina_Bool wait_for_done; } Efl_Util_Wl_Surface_Scr_Mode_Info; +typedef struct _Efl_Util_Wl_Output_Info +{ + struct wl_output *output; + int offset_x, offset_y, width, height; +} Efl_Util_Wl_Output_Info; +#endif + typedef struct _Efl_Util_Data { /* x11 related stuffs */ @@ -97,6 +120,12 @@ typedef struct _Efl_Util_Data struct tizen_window_screen *proto; Eina_Hash *hash; } scr_mode; + struct + { + struct screenshooter *screenshooter; + struct tizen_buffer_pool *buffer_pool; + Eina_List *output_list; + } shot; #endif /* end of WAYLAND */ } wl; } Efl_Util_Data; @@ -119,7 +148,8 @@ static Efl_Util_Data _eflutil = #if WAYLAND NULL, { NULL, NULL }, /* tizen_notification protocol */ - { NULL, NULL } /* tizen_window_screen protocol */ + { NULL, NULL }, /* tizen_window_screen protocol */ + { NULL, NULL, NULL } /* screenshooter protocol */ #endif /* end of WAYLAND */ } }; @@ -330,6 +360,8 @@ _wl_init(void) if (_eflutil.wl.init) return EINA_TRUE; + ecore_wl_init(NULL); + _eflutil.wl.dpy = ecore_wl_display_get(); EINA_SAFETY_ON_NULL_RETURN_VAL(_eflutil.wl.dpy, EINA_FALSE); @@ -344,6 +376,62 @@ _wl_init(void) } static void +_cb_wl_output_geometry(void *data, struct wl_output *wl_output, int x, int y, + int physical_width, int physical_height, int subpixel, + const char *make, const char *model, int transform) +{ + Efl_Util_Wl_Output_Info *output = wl_output_get_user_data(wl_output); + if (wl_output == output->output) + { + output->offset_x = x; + output->offset_y = y; + } +} + +static void +_cb_wl_output_mode(void *data, struct wl_output *wl_output, uint32_t flags, + int width, int height, int refresh) +{ + Efl_Util_Wl_Output_Info *output = wl_output_get_user_data(wl_output); + if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) + { + output->width = width; + output->height = height; + } +} + +static void +_cb_wl_output_done(void *data, struct wl_output *wl_output) +{ +} + +static void +_cb_wl_output_scale(void *data, struct wl_output *wl_output, int32_t factor) +{ +} + +static const struct wl_output_listener output_listener = +{ + _cb_wl_output_geometry, + _cb_wl_output_mode, + _cb_wl_output_done, + _cb_wl_output_scale +}; + +static void +_cb_wl_screenshot_done(void *data, struct screenshooter *screenshooter) +{ + Eina_Bool *shot_done = (Eina_Bool*)data; + if (shot_done) + *shot_done = EINA_TRUE; +} + +static const struct screenshooter_listener screenshooter_listener = +{ + _cb_wl_screenshot_done +}; + +static void _cb_wl_reg_global(void *data, struct wl_registry *reg, unsigned int name, @@ -382,6 +470,25 @@ _cb_wl_reg_global(void *data, _eflutil.wl.scr_mode.hash = eina_hash_pointer_new(free); _eflutil.wl.scr_mode.proto = proto; } + else if (strcmp(interface, "wl_output") == 0) + { + Efl_Util_Wl_Output_Info *output = calloc(1, sizeof(Efl_Util_Wl_Output_Info)); + EINA_SAFETY_ON_NULL_RETURN(output); + + _eflutil.wl.shot.output_list = eina_list_append(_eflutil.wl.shot.output_list, output); + + output->output = wl_registry_bind(reg, name, &wl_output_interface, version); + wl_output_add_listener(output->output, &output_listener, output); + } + else if (strcmp(interface, "tizen_buffer_pool") == 0) + { + _eflutil.wl.shot.buffer_pool = wl_registry_bind(reg, name, &tizen_buffer_pool_interface, 1); + } + else if (strcmp(interface, "screenshooter") == 0) + { + _eflutil.wl.shot.screenshooter = wl_registry_bind(reg, name, &screenshooter_interface, version); + screenshooter_add_listener(_eflutil.wl.shot.screenshooter, &screenshooter_listener, NULL); + } } static void @@ -1018,21 +1125,622 @@ efl_util_input_generate_touch(int idx, return EFL_UTIL_ERROR_NONE; } -API efl_util_screenshot_h -efl_util_screenshot_initialize(int width, - int height) +struct _efl_util_screenshot_h +{ + int width; + int height; + +#if X11 + Ecore_X_Display *dpy; + int internal_display; + int screen; + Window root; + Pixmap pixmap; + GC gc; + Atom atom_capture; + + /* port */ + int port; + + /* damage */ + Damage damage; + int damage_base; + + /* dri2 */ + int eventBase, errorBase; + int dri2Major, dri2Minor; + char *driver_name, *device_name; + drm_magic_t magic; + + /* drm */ + int drm_fd; +#endif + + Eina_Bool shot_done; + + /* tbm bufmgr */ + tbm_bufmgr bufmgr; +}; + +/* scrrenshot handle */ +static efl_util_screenshot_h g_screenshot; + +#if X11 +#define FOURCC(a,b,c,d) (((unsigned)d&0xff)<<24 | ((unsigned)c&0xff)<<16 | ((unsigned)b&0xff)<<8 | ((unsigned)a&0xff)) +#define FOURCC_RGB32 FOURCC('R','G','B','4') +#define TIMEOUT_CAPTURE 3 + +/* x error handling */ +static Bool g_efl_util_x_error_caught; + +static int +_efl_util_screenshot_x_error_handle(Display *dpy, XErrorEvent *ev) { + if (!g_screenshot || (dpy != g_screenshot->dpy)) + return 0; + + g_efl_util_x_error_caught = True; + return 0; } -API tbm_surface_h -efl_util_screenshot_take_tbm_surface(efl_util_screenshot_h screenshot) +static int +_efl_util_screenshot_get_port(Display *dpy, unsigned int id, Window win) { - return 0; + unsigned int ver, rev, req_base, evt_base, err_base; + unsigned int adaptors; + XvAdaptorInfo *ai = NULL; + XvImageFormatValues *fo = NULL; + int formats; + int i, j, p; + + if (XvQueryExtension(dpy, &ver, &rev, &req_base, &evt_base, &err_base) != Success) + { + fprintf(stderr, "[screenshot] fail: no XV extension. \n"); + return -1; + } + + if (XvQueryAdaptors(dpy, win, &adaptors, &ai) != Success) + { + fprintf(stderr, "[screenshot] fail: query adaptors. \n"); + return -1; + } + + EINA_SAFETY_ON_NULL_RETURN_VAL(ai, -1); + + for (i = 0; i < adaptors; i++) + { + int support_format = False; + + if (!(ai[i].type & XvInputMask) || + !(ai[i].type & XvStillMask)) + continue; + + p = ai[i].base_id; + + fo = XvListImageFormats(dpy, p, &formats); + for (j = 0; j < formats; j++) + if (fo[j].id == (int)id) + support_format = True; + + if (fo) + XFree(fo); + + if (!support_format) + continue; + + for (; p < ai[i].base_id + ai[i].num_ports; p++) + { + if (XvGrabPort(dpy, p, 0) == Success) + { + XvFreeAdaptorInfo(ai); + return p; + } + } + } + + XvFreeAdaptorInfo(ai); + + XSync(dpy, False); + + return -1; } -API int -efl_util_screenshot_deinitialize(efl_util_screenshot_h screenshot) +static int _efl_util_screenshot_get_best_size(Display *dpy, int port, int width, int height, unsigned int *best_width, unsigned int *best_height) +{ + XErrorHandler old_handler = NULL; + + Atom atom_capture = XInternAtom(dpy, "_USER_WM_PORT_ATTRIBUTE_CAPTURE", False); + + g_efl_util_x_error_caught = False; + old_handler = XSetErrorHandler(_efl_util_screenshot_x_error_handle); + + XvSetPortAttribute(dpy, port, atom_capture, 1); + XSync(dpy, False); + + g_efl_util_x_error_caught = False; + XSetErrorHandler(old_handler); + + XvQueryBestSize(dpy, port, 0, 0, 0, width, height, best_width, best_height); + if (best_width <= 0 || best_height <= 0) + return 0; + + return 1; +} +#endif + +API efl_util_screenshot_h efl_util_screenshot_initialize(int width, int height) +{ +#if X11 + efl_util_screenshot_h screenshot = NULL; + int depth = 0; + int damage_err_base = 0; + unsigned int best_width = 0; + unsigned int best_height = 0; + + EINA_SAFETY_ON_FALSE_GOTO(width > 0, fail_param); + EINA_SAFETY_ON_FALSE_GOTO(height > 0, fail_param); + + if (g_screenshot != NULL) + { + if (g_screenshot->width != width || g_screenshot->height != height) + { + // TODO: recreate pixmap and update information + if (!_efl_util_screenshot_get_best_size(screenshot->dpy, screenshot->port, width, height, &best_width, &best_height)) + { + set_last_result(EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL); + return NULL; + } + + g_screenshot->width = width; + g_screenshot->height = height; + } + + return g_screenshot; + } + + screenshot = calloc(1, sizeof(struct _efl_util_screenshot_h)); + EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_memory); + + /* set dpy */ + screenshot->dpy = ecore_x_display_get(); + if (!screenshot->dpy) + { + screenshot->dpy = XOpenDisplay(0); + EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_init); + + /* for XCloseDisplay at denitialization */ + screenshot->internal_display = 1; + } + + /* set screen */ + screenshot->screen = DefaultScreen(screenshot->dpy); + + /* set root window */ + screenshot->root = DefaultRootWindow(screenshot->dpy); + + /* initialize capture adaptor */ + screenshot->port = _efl_util_screenshot_get_port(screenshot->dpy, FOURCC_RGB32, screenshot->root); + EINA_SAFETY_ON_FALSE_GOTO(screenshot->port > 0, fail_init); + + /* get the best size */ + _efl_util_screenshot_get_best_size(screenshot->dpy, screenshot->port, width, height, &best_width, &best_height); + EINA_SAFETY_ON_FALSE_GOTO(best_width > 0, fail_init); + EINA_SAFETY_ON_FALSE_GOTO(best_height > 0, fail_init); + + /* set the width and the height */ + screenshot->width = best_width; + screenshot->height = best_height; + + /* create a pixmap */ + depth = DefaultDepth(screenshot->dpy, screenshot->screen); + screenshot->pixmap = XCreatePixmap(screenshot->dpy, screenshot->root, screenshot->width, screenshot->height, depth); + EINA_SAFETY_ON_FALSE_GOTO(screenshot->pixmap > 0, fail_init); + + screenshot->gc = XCreateGC(screenshot->dpy, screenshot->pixmap, 0, 0); + EINA_SAFETY_ON_NULL_GOTO(screenshot->gc, fail_init); + + XSetForeground(screenshot->dpy, screenshot->gc, 0xFF000000); + XFillRectangle(screenshot->dpy, screenshot->pixmap, screenshot->gc, 0, 0, width, height); + + /* initialize damage */ + if (!XDamageQueryExtension(screenshot->dpy, &screenshot->damage_base, &damage_err_base)) + goto fail_init; + + screenshot->damage = XDamageCreate(screenshot->dpy, screenshot->pixmap, XDamageReportNonEmpty); + EINA_SAFETY_ON_FALSE_GOTO(screenshot->damage > 0, fail_init); + + /* initialize dri3 and dri2 */ + if (!DRI2QueryExtension(screenshot->dpy, &screenshot->eventBase, &screenshot->errorBase)) + { + fprintf(stderr, "[screenshot] fail: DRI2QueryExtention\n"); + goto fail_init; + } + + if (!DRI2QueryVersion(screenshot->dpy, &screenshot->dri2Major, &screenshot->dri2Minor)) + { + fprintf(stderr, "[screenshot] fail: DRI2QueryVersion\n"); + goto fail_init; + } + + if (!DRI2Connect(screenshot->dpy, screenshot->root, &screenshot->driver_name, &screenshot->device_name)) + { + fprintf(stderr, "[screenshot] fail: DRI2Connect\n"); + goto fail_init; + } + + screenshot->drm_fd = open(screenshot->device_name, O_RDWR); + EINA_SAFETY_ON_FALSE_GOTO(screenshot->drm_fd >= 0, fail_init); + + if (drmGetMagic(screenshot->drm_fd, &screenshot->magic)) + { + fprintf(stderr, "[screenshot] fail: drmGetMagic\n"); + goto fail_init; + } + + if (!DRI2Authenticate(screenshot->dpy, screenshot->root, screenshot->magic)) + { + fprintf(stderr, "[screenshot] fail: DRI2Authenticate\n"); + goto fail_init; + } + + if (!drmAuthMagic(screenshot->drm_fd, screenshot->magic)) + { + fprintf(stderr, "[screenshot] fail: drmAuthMagic\n"); + goto fail_init; + } + + DRI2CreateDrawable(screenshot->dpy, screenshot->pixmap); + + /* tbm bufmgr */ + screenshot->bufmgr = tbm_bufmgr_init(screenshot->drm_fd); + EINA_SAFETY_ON_NULL_GOTO(screenshot->bufmgr, fail_init); + + XFlush(screenshot->dpy); + + g_screenshot = screenshot; + set_last_result(EFL_UTIL_ERROR_NONE); + + return g_screenshot; +#endif + +#if WAYLAND + efl_util_screenshot_h screenshot = NULL; + + if (!_eflutil.wl.shot.screenshooter) + { + int ret = 0; + _wl_init(); + while (!_eflutil.wl.shot.screenshooter && ret != -1) + ret = wl_display_dispatch(_eflutil.wl.dpy); + EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.shot.screenshooter, fail_init); + EINA_SAFETY_ON_NULL_GOTO(_eflutil.wl.shot.buffer_pool, fail_init); + } + + EINA_SAFETY_ON_FALSE_GOTO(width > 0, fail_param); + EINA_SAFETY_ON_FALSE_GOTO(height > 0, fail_param); + + if (g_screenshot) + { + if (g_screenshot->width != width || g_screenshot->height != height) + { + g_screenshot->width = width; + g_screenshot->height = height; + } + + return g_screenshot; + } + + screenshot = calloc(1, sizeof(struct _efl_util_screenshot_h)); + EINA_SAFETY_ON_NULL_GOTO(screenshot, fail_memory); + + screenshot->width = width; + screenshot->height = height; + + screenshot->bufmgr = tbm_bufmgr_init(-1); + EINA_SAFETY_ON_NULL_GOTO(screenshot->bufmgr, fail_init); + + g_screenshot = screenshot; + set_last_result(EFL_UTIL_ERROR_NONE); + + screenshooter_set_user_data(_eflutil.wl.shot.screenshooter, &screenshot->shot_done); + + return g_screenshot; +#endif +fail_param: + if (screenshot) + efl_util_screenshot_deinitialize(screenshot); + set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER); + return NULL; +fail_memory: + if (screenshot) + efl_util_screenshot_deinitialize(screenshot); + set_last_result(EFL_UTIL_ERROR_OUT_OF_MEMORY); + return NULL; +fail_init: + if (screenshot) + efl_util_screenshot_deinitialize(screenshot); + set_last_result(EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL); + return NULL; +} + +API int efl_util_screenshot_deinitialize(efl_util_screenshot_h screenshot) { +#if X11 + if (!screenshot) + return EFL_UTIL_ERROR_INVALID_PARAMETER; + + /* tbm bufmgr */ + if (screenshot->bufmgr) + tbm_bufmgr_deinit(screenshot->bufmgr); + + DRI2DestroyDrawable(screenshot->dpy, screenshot->pixmap); + + /* dri2 */ + if (screenshot->drm_fd) + close(screenshot->drm_fd); + if (screenshot->driver_name) + free(screenshot->driver_name); + if (screenshot->device_name) + free(screenshot->device_name); + + /* xv */ + if (screenshot->port > 0 && screenshot->pixmap > 0) + XvStopVideo(screenshot->dpy, screenshot->port, screenshot->pixmap); + + /* damage */ + if (screenshot->damage) + XDamageDestroy(screenshot->dpy, screenshot->damage); + + /* gc */ + if (screenshot->gc) + XFreeGC(screenshot->dpy, screenshot->gc); + + /* pixmap */ + if (screenshot->pixmap > 0) + XFreePixmap(screenshot->dpy, screenshot->pixmap); + + /* port */ + if (screenshot->port > 0) + XvUngrabPort(screenshot->dpy, screenshot->port, 0); + + XSync(screenshot->dpy, False); + + /* dpy */ + if (screenshot->internal_display ==1 && screenshot->dpy) + XCloseDisplay(screenshot->dpy); + + free(screenshot); + g_screenshot = NULL; + return EFL_UTIL_ERROR_NONE; +#endif +#if WAYLAND + if (!screenshot) + return EFL_UTIL_ERROR_NONE; + + if (screenshot->bufmgr) + tbm_bufmgr_deinit(screenshot->bufmgr); + + free(screenshot); + g_screenshot = NULL; + + if (_eflutil.wl.shot.screenshooter) + screenshooter_set_user_data(_eflutil.wl.shot.screenshooter, NULL); + + return EFL_UTIL_ERROR_NONE; +#endif +} + + +API tbm_surface_h efl_util_screenshot_take_tbm_surface(efl_util_screenshot_h screenshot) +{ +#if X11 + XEvent ev = {0,}; + XErrorHandler old_handler = NULL; + unsigned int attachment = DRI2BufferFrontLeft; + int nbufs = 0; + DRI2Buffer *bufs = NULL; + tbm_bo t_bo = NULL; + tbm_surface_h t_surface = NULL; + int buf_width = 0; + int buf_height = 0; + tbm_surface_info_s surf_info; + int i; + + if (screenshot != g_screenshot) + { + set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER); + return NULL; + } + + /* for flush other pending requests and pending events */ + XSync(screenshot->dpy, 0); + + g_efl_util_x_error_caught = False; + old_handler = XSetErrorHandler(_efl_util_screenshot_x_error_handle); + + /* dump here */ + XvPutStill(screenshot->dpy, screenshot->port, screenshot->pixmap, screenshot->gc, + 0, 0, screenshot->width, screenshot->height, + 0, 0, screenshot->width, screenshot->height); + + XSync(screenshot->dpy, 0); + + if (g_efl_util_x_error_caught) + { + g_efl_util_x_error_caught = False; + XSetErrorHandler(old_handler); + goto fail; + } + + g_efl_util_x_error_caught = False; + XSetErrorHandler(old_handler); + + if (XPending(screenshot->dpy)) + XNextEvent(screenshot->dpy, &ev); + else + { + int fd = ConnectionNumber(screenshot->dpy); + fd_set mask; + struct timeval tv; + int ret; + + FD_ZERO(&mask); + FD_SET(fd, &mask); + + tv.tv_usec = 0; + tv.tv_sec = TIMEOUT_CAPTURE; + + ret = select(fd + 1, &mask, 0, 0, &tv); + if (ret < 0) + fprintf(stderr, "[screenshot] fail: select.\n"); + else if (ret == 0) + fprintf(stderr, "[screenshot] fail: timeout(%d sec)!\n", TIMEOUT_CAPTURE); + else if (XPending(screenshot->dpy)) + XNextEvent(screenshot->dpy, &ev); + else + fprintf(stderr, "[screenshot] fail: not passed a event!\n"); + } + + /* check if the capture is done by xserver and pixmap has got the captured image */ + if (ev.type == (screenshot->damage_base + XDamageNotify)) + { + XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&ev; + if (damage_ev->drawable == screenshot->pixmap) + { + /* Get DRI2 FrontLeft buffer of the pixmap */ + bufs = DRI2GetBuffers(screenshot->dpy, screenshot->pixmap, &buf_width, &buf_height, &attachment, 1, &nbufs); + if (!bufs) + { + fprintf(stderr, "[screenshot] fail: DRI2GetBuffers\n"); + goto fail; + } + + t_bo = tbm_bo_import(screenshot->bufmgr, bufs[0].name); + if (!t_bo) + { + fprintf(stderr, "[screenshot] fail: import tbm_bo!\n"); + goto fail; + } + + surf_info.width = buf_width; + surf_info.height = buf_height; + surf_info.format = TBM_FORMAT_XRGB8888; + surf_info.bpp = 32; + surf_info.size = bufs->pitch * surf_info.height; + surf_info.num_planes = 1; + for (i = 0; i < surf_info.num_planes; i++) + { + surf_info.planes[i].size = bufs->pitch * surf_info.height; + surf_info.planes[i].stride = bufs->pitch; + surf_info.planes[i].offset = 0; + } + t_surface = tbm_surface_internal_create_with_bos(&surf_info, &t_bo, 1); + if (!t_surface) + { + fprintf(stderr, "[screenshot] fail: get tbm_surface!\n"); + goto fail; + } + + tbm_bo_unref(t_bo); + free(bufs); + + XDamageSubtract(screenshot->dpy, screenshot->damage, None, None ); + + set_last_result(EFL_UTIL_ERROR_NONE); + + return t_surface; + } + + XDamageSubtract(screenshot->dpy, screenshot->damage, None, None ); + } + +fail: + + if (t_bo) + tbm_bo_unref(t_bo); + if (bufs) + free(bufs); + + set_last_result(EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL); + + return NULL; +#endif + +#if WAYLAND + tbm_bo t_bo = NULL; + tbm_surface_h t_surface = NULL; + struct wl_buffer *buffer = NULL; + tbm_surface_info_s info; + Efl_Util_Wl_Output_Info *output; + int ret = 0; + + if (screenshot != g_screenshot) + { + set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER); + return NULL; + } + + output = eina_list_nth(_eflutil.wl.shot.output_list, 0); + if (!output) + { + fprintf(stderr, "[screenshot] fail: no output for screenshot\n"); + goto fail; + } + + t_surface = tbm_surface_create(screenshot->width, screenshot->height, TBM_FORMAT_XRGB8888); + if (!t_surface) + { + fprintf(stderr, "[screenshot] fail: tbm_surface_create\n"); + goto fail; + } + + t_bo = tbm_surface_internal_get_bo(t_surface, 0); + if (!t_bo) + { + fprintf(stderr, "[screenshot] fail: no tbm_bo for screenshot\n"); + goto fail; + } + + tbm_surface_get_info(t_surface, &info); + + buffer = + tizen_buffer_pool_create_buffer(_eflutil.wl.shot.buffer_pool, + tbm_bo_export(t_bo), + info.width, info.height, + info.planes[0].stride, + TIZEN_BUFFER_POOL_FORMAT_XRGB8888); + if (!buffer) + { + fprintf(stderr, "[screenshot] fail: create wl_buffer for screenshot\n"); + goto fail; + } + + screenshooter_shoot(_eflutil.wl.shot.screenshooter, output->output, buffer); + + screenshot->shot_done = EINA_FALSE; + while (!screenshot->shot_done && ret != -1) + ret = wl_display_dispatch(_eflutil.wl.dpy); + + if (ret == -1) + { + fprintf(stderr, "[screenshot] fail: screenshooter_shoot\n"); + goto fail; + } + + wl_buffer_destroy(buffer); + + return t_surface; + +fail: + if (t_surface) + tbm_surface_destroy(t_surface); + if (buffer); + wl_buffer_destroy(buffer); + + set_last_result(EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL); + + return NULL; +#endif } diff --git a/src/screenshooter-client-protocol.h b/src/screenshooter-client-protocol.h new file mode 100644 index 0000000..8782ca1 --- /dev/null +++ b/src/screenshooter-client-protocol.h @@ -0,0 +1,66 @@ +#ifndef SCREENSHOOTER_CLIENT_PROTOCOL_H +#define SCREENSHOOTER_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct screenshooter; + +extern const struct wl_interface screenshooter_interface; + +struct screenshooter_listener { + /** + * done - (none) + */ + void (*done)(void *data, + struct screenshooter *screenshooter); +}; + +static inline int +screenshooter_add_listener(struct screenshooter *screenshooter, + const struct screenshooter_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) screenshooter, + (void (**)(void)) listener, data); +} + +#define SCREENSHOOTER_SHOOT 0 + +static inline void +screenshooter_set_user_data(struct screenshooter *screenshooter, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) screenshooter, user_data); +} + +static inline void * +screenshooter_get_user_data(struct screenshooter *screenshooter) +{ + return wl_proxy_get_user_data((struct wl_proxy *) screenshooter); +} + +static inline void +screenshooter_destroy(struct screenshooter *screenshooter) +{ + wl_proxy_destroy((struct wl_proxy *) screenshooter); +} + +static inline void +screenshooter_shoot(struct screenshooter *screenshooter, struct wl_output *output, struct wl_buffer *buffer) +{ + wl_proxy_marshal((struct wl_proxy *) screenshooter, + SCREENSHOOTER_SHOOT, output, buffer); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/screenshooter-protocol.c b/src/screenshooter-protocol.c new file mode 100644 index 0000000..4e497f1 --- /dev/null +++ b/src/screenshooter-protocol.c @@ -0,0 +1,25 @@ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_buffer_interface; +extern const struct wl_interface wl_output_interface; + +static const struct wl_interface *types[] = { + &wl_output_interface, + &wl_buffer_interface, +}; + +static const struct wl_message screenshooter_requests[] = { + { "shoot", "oo", types + 0 }, +}; + +static const struct wl_message screenshooter_events[] = { + { "done", "", types + 0 }, +}; + +WL_EXPORT const struct wl_interface screenshooter_interface = { + "screenshooter", 1, + 1, screenshooter_requests, + 1, screenshooter_events, +}; diff --git a/src/tizen-buffer-pool-client-protocol.h b/src/tizen-buffer-pool-client-protocol.h new file mode 100644 index 0000000..781d0a8 --- /dev/null +++ b/src/tizen-buffer-pool-client-protocol.h @@ -0,0 +1,194 @@ +#ifndef TIZEN_BUFFER_POOL_CLIENT_PROTOCOL_H +#define TIZEN_BUFFER_POOL_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct tizen_buffer_pool; + +extern const struct wl_interface tizen_buffer_pool_interface; + +#ifndef TIZEN_BUFFER_POOL_ERROR_ENUM +#define TIZEN_BUFFER_POOL_ERROR_ENUM +enum tizen_buffer_pool_error { + TIZEN_BUFFER_POOL_ERROR_INVALID_FORMAT = 0, + TIZEN_BUFFER_POOL_ERROR_INVALID_NAME = 1, +}; +#endif /* TIZEN_BUFFER_POOL_ERROR_ENUM */ + +#ifndef TIZEN_BUFFER_POOL_CAPABILITY_ENUM +#define TIZEN_BUFFER_POOL_CAPABILITY_ENUM +enum tizen_buffer_pool_capability { + TIZEN_BUFFER_POOL_CAPABILITY_DEFAULT = 0, + TIZEN_BUFFER_POOL_CAPABILITY_VIDEO = 0x1, + TIZEN_BUFFER_POOL_CAPABILITY_SCREENMIRROR = 0x2, +}; +#endif /* TIZEN_BUFFER_POOL_CAPABILITY_ENUM */ + +#ifndef TIZEN_BUFFER_POOL_FORMAT_ENUM +#define TIZEN_BUFFER_POOL_FORMAT_ENUM +enum tizen_buffer_pool_format { + TIZEN_BUFFER_POOL_FORMAT_C8 = 0x20203843, + TIZEN_BUFFER_POOL_FORMAT_RGB332 = 0x38424752, + TIZEN_BUFFER_POOL_FORMAT_BGR233 = 0x38524742, + TIZEN_BUFFER_POOL_FORMAT_XRGB4444 = 0x32315258, + TIZEN_BUFFER_POOL_FORMAT_XBGR4444 = 0x32314258, + TIZEN_BUFFER_POOL_FORMAT_RGBX4444 = 0x32315852, + TIZEN_BUFFER_POOL_FORMAT_BGRX4444 = 0x32315842, + TIZEN_BUFFER_POOL_FORMAT_ARGB4444 = 0x32315241, + TIZEN_BUFFER_POOL_FORMAT_ABGR4444 = 0x32314241, + TIZEN_BUFFER_POOL_FORMAT_RGBA4444 = 0x32314152, + TIZEN_BUFFER_POOL_FORMAT_BGRA4444 = 0x32314142, + TIZEN_BUFFER_POOL_FORMAT_XRGB1555 = 0x35315258, + TIZEN_BUFFER_POOL_FORMAT_XBGR1555 = 0x35314258, + TIZEN_BUFFER_POOL_FORMAT_RGBX5551 = 0x35315852, + TIZEN_BUFFER_POOL_FORMAT_BGRX5551 = 0x35315842, + TIZEN_BUFFER_POOL_FORMAT_ARGB1555 = 0x35315241, + TIZEN_BUFFER_POOL_FORMAT_ABGR1555 = 0x35314241, + TIZEN_BUFFER_POOL_FORMAT_RGBA5551 = 0x35314152, + TIZEN_BUFFER_POOL_FORMAT_BGRA5551 = 0x35314142, + TIZEN_BUFFER_POOL_FORMAT_RGB565 = 0x36314752, + TIZEN_BUFFER_POOL_FORMAT_BGR565 = 0x36314742, + TIZEN_BUFFER_POOL_FORMAT_RGB888 = 0x34324752, + TIZEN_BUFFER_POOL_FORMAT_BGR888 = 0x34324742, + TIZEN_BUFFER_POOL_FORMAT_XRGB8888 = 0x34325258, + TIZEN_BUFFER_POOL_FORMAT_XBGR8888 = 0x34324258, + TIZEN_BUFFER_POOL_FORMAT_RGBX8888 = 0x34325852, + TIZEN_BUFFER_POOL_FORMAT_BGRX8888 = 0x34325842, + TIZEN_BUFFER_POOL_FORMAT_ARGB8888 = 0x34325241, + TIZEN_BUFFER_POOL_FORMAT_ABGR8888 = 0x34324241, + TIZEN_BUFFER_POOL_FORMAT_RGBA8888 = 0x34324152, + TIZEN_BUFFER_POOL_FORMAT_BGRA8888 = 0x34324142, + TIZEN_BUFFER_POOL_FORMAT_XRGB2101010 = 0x30335258, + TIZEN_BUFFER_POOL_FORMAT_XBGR2101010 = 0x30334258, + TIZEN_BUFFER_POOL_FORMAT_RGBX1010102 = 0x30335852, + TIZEN_BUFFER_POOL_FORMAT_BGRX1010102 = 0x30335842, + TIZEN_BUFFER_POOL_FORMAT_ARGB2101010 = 0x30335241, + TIZEN_BUFFER_POOL_FORMAT_ABGR2101010 = 0x30334241, + TIZEN_BUFFER_POOL_FORMAT_RGBA1010102 = 0x30334152, + TIZEN_BUFFER_POOL_FORMAT_BGRA1010102 = 0x30334142, + TIZEN_BUFFER_POOL_FORMAT_YUYV = 0x56595559, + TIZEN_BUFFER_POOL_FORMAT_YVYU = 0x55595659, + TIZEN_BUFFER_POOL_FORMAT_UYVY = 0x59565955, + TIZEN_BUFFER_POOL_FORMAT_VYUY = 0x59555956, + TIZEN_BUFFER_POOL_FORMAT_AYUV = 0x56555941, + TIZEN_BUFFER_POOL_FORMAT_NV12 = 0x3231564e, + TIZEN_BUFFER_POOL_FORMAT_NV21 = 0x3132564e, + TIZEN_BUFFER_POOL_FORMAT_NV16 = 0x3631564e, + TIZEN_BUFFER_POOL_FORMAT_NV61 = 0x3136564e, + TIZEN_BUFFER_POOL_FORMAT_YUV410 = 0x39565559, + TIZEN_BUFFER_POOL_FORMAT_YVU410 = 0x39555659, + TIZEN_BUFFER_POOL_FORMAT_YUV411 = 0x31315559, + TIZEN_BUFFER_POOL_FORMAT_YVU411 = 0x31315659, + TIZEN_BUFFER_POOL_FORMAT_YUV420 = 0x32315559, + TIZEN_BUFFER_POOL_FORMAT_YVU420 = 0x32315659, + TIZEN_BUFFER_POOL_FORMAT_YUV422 = 0x36315559, + TIZEN_BUFFER_POOL_FORMAT_YVU422 = 0x36315659, + TIZEN_BUFFER_POOL_FORMAT_YUV444 = 0x34325559, + TIZEN_BUFFER_POOL_FORMAT_YVU444 = 0x34325659, + TIZEN_BUFFER_POOL_FORMAT_ST12 = 0x32315453, + TIZEN_BUFFER_POOL_FORMAT_SN12 = 0x32314e53, +}; +#endif /* TIZEN_BUFFER_POOL_FORMAT_ENUM */ + +struct tizen_buffer_pool_listener { + /** + * device - (none) + * @name: (none) + */ + void (*device)(void *data, + struct tizen_buffer_pool *tizen_buffer_pool, + const char *name); + /** + * authenticated - (none) + */ + void (*authenticated)(void *data, + struct tizen_buffer_pool *tizen_buffer_pool); + /** + * capabilities - (none) + * @value: (none) + */ + void (*capabilities)(void *data, + struct tizen_buffer_pool *tizen_buffer_pool, + uint32_t value); + /** + * format - (none) + * @format: (none) + */ + void (*format)(void *data, + struct tizen_buffer_pool *tizen_buffer_pool, + uint32_t format); +}; + +static inline int +tizen_buffer_pool_add_listener(struct tizen_buffer_pool *tizen_buffer_pool, + const struct tizen_buffer_pool_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) tizen_buffer_pool, + (void (**)(void)) listener, data); +} + +#define TIZEN_BUFFER_POOL_AUTHENTICATE 0 +#define TIZEN_BUFFER_POOL_CREATE_BUFFER 1 +#define TIZEN_BUFFER_POOL_CREATE_PLANAR_BUFFER 2 + +static inline void +tizen_buffer_pool_set_user_data(struct tizen_buffer_pool *tizen_buffer_pool, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) tizen_buffer_pool, user_data); +} + +static inline void * +tizen_buffer_pool_get_user_data(struct tizen_buffer_pool *tizen_buffer_pool) +{ + return wl_proxy_get_user_data((struct wl_proxy *) tizen_buffer_pool); +} + +static inline void +tizen_buffer_pool_destroy(struct tizen_buffer_pool *tizen_buffer_pool) +{ + wl_proxy_destroy((struct wl_proxy *) tizen_buffer_pool); +} + +static inline void +tizen_buffer_pool_authenticate(struct tizen_buffer_pool *tizen_buffer_pool, uint32_t id) +{ + wl_proxy_marshal((struct wl_proxy *) tizen_buffer_pool, + TIZEN_BUFFER_POOL_AUTHENTICATE, id); +} + +static inline struct wl_buffer * +tizen_buffer_pool_create_buffer(struct tizen_buffer_pool *tizen_buffer_pool, uint32_t name, int32_t width, int32_t height, uint32_t stride, uint32_t format) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) tizen_buffer_pool, + TIZEN_BUFFER_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, name, width, height, stride, format); + + return (struct wl_buffer *) id; +} + +static inline struct wl_buffer * +tizen_buffer_pool_create_planar_buffer(struct tizen_buffer_pool *tizen_buffer_pool, int32_t width, int32_t height, uint32_t format, uint32_t name0, int32_t offset0, int32_t stride0, uint32_t name1, int32_t offset1, int32_t stride1, uint32_t name2, int32_t offset2, int32_t stride2) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) tizen_buffer_pool, + TIZEN_BUFFER_POOL_CREATE_PLANAR_BUFFER, &wl_buffer_interface, NULL, width, height, format, name0, offset0, stride0, name1, offset1, stride1, name2, offset2, stride2); + + return (struct wl_buffer *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/tizen-buffer-pool-protocol.c b/src/tizen-buffer-pool-protocol.c new file mode 100644 index 0000000..7df3bc5 --- /dev/null +++ b/src/tizen-buffer-pool-protocol.c @@ -0,0 +1,47 @@ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_buffer_interface; + +static const struct wl_interface *types[] = { + NULL, + &wl_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static const struct wl_message tizen_buffer_pool_requests[] = { + { "authenticate", "u", types + 0 }, + { "create_buffer", "nuiiuu", types + 1 }, + { "create_planar_buffer", "niiuuiiuiiuii", types + 7 }, +}; + +static const struct wl_message tizen_buffer_pool_events[] = { + { "device", "s", types + 0 }, + { "authenticated", "", types + 0 }, + { "capabilities", "u", types + 0 }, + { "format", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface tizen_buffer_pool_interface = { + "tizen_buffer_pool", 1, + 3, tizen_buffer_pool_requests, + 4, tizen_buffer_pool_events, +}; -- 2.7.4