#include <Evas_Engine_Buffer.h>
#include <wayland-client.h>
-#include "wayland-api.h"
+#include <wayland-tbm-client.h>
+#include <tbm_bufmgr.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tizen-extension-client-protocol.h>
+#include <screenshooter-client-protocol.h>
+
#include "real_functions.h"
#include "daprobe.h"
#include "dahelper.h"
#define CAPTURE_TIMEOUT 2.0
#define MAX_PATH_LENGTH 256
-struct screenshot_data {
- struct wl_shm *shm;
+struct efl_data {
+ struct wl_display *wl_display;
+ struct wl_registry *wl_registry;
struct screenshooter *screenshooter;
struct wl_list output_list;
int min_x, min_y, max_x, max_y;
int buffer_copy_done;
+ int width, height;
};
struct screenshooter_output {
screenshot_done(void *data,
struct screenshooter __attribute__((unused)) *screenshooter)
{
- struct screenshot_data *sdata = data;
+ struct efl_data *sdata = data;
sdata->buffer_copy_done = 1;
}
uint32_t name, const char *interface,
uint32_t __attribute__((unused)) version)
{
- struct screenshot_data *sdata = data;
+ struct efl_data *sdata = data;
if (strcmp(interface, "wl_output") == 0) {
struct screenshooter_output *output = malloc(sizeof(*output));
if (output) {
- PRINTMSG("allocate %p", output);
output->output = wl_registry_bind(registry, name,
&wl_output_interface,
1);
&output_listener,
output);
}
- } else if (strcmp(interface, "wl_shm") == 0) {
- sdata->shm = wl_registry_bind(registry, name,
- &wl_shm_interface, 1);
} else if (strcmp(interface, "screenshooter") == 0) {
sdata->screenshooter = wl_registry_bind(registry, name,
&screenshooter_interface,
1);
+ screenshooter_add_listener(sdata->screenshooter,
+ &screenshooter_listener,
+ sdata);
}
}
NULL
};
-static struct wl_buffer *
-create_shm_buffer(struct wl_shm *shm, int width, int height, void **data_out)
-{
- char filename[] = "/tmp/wayland-shm-XXXXXX";
- struct wl_shm_pool *pool;
- struct wl_buffer *buffer;
- int fd, size, stride;
- void *data;
-
- stride = width * 4;
- size = stride * height;
-
- fd = mkstemp(filename);
- if (fd < 0)
- return NULL;
-
- if (ftruncate(fd, size) < 0) {
- close(fd);
- return NULL;
- }
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- unlink(filename);
-
- if (data == MAP_FAILED) {
- close(fd);
- return NULL;
- }
-
- pool = wl_shm_create_pool(shm, fd, size);
- close(fd);
- buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
- WL_SHM_FORMAT_XRGB8888);
- wl_shm_pool_destroy(pool);
- *data_out = data;
-
- return buffer;
-}
-
-static void *__screenshot_to_buf(struct screenshot_data *sdata, int width,
- int height)
-{
- int output_stride, buffer_stride, i;
- void *data, *d, *s;
- struct screenshooter_output *output, *next;
-
- buffer_stride = width * 4;
- data = malloc(buffer_stride * height);
- if (!data)
- return NULL;
-
- wl_list_for_each_safe(output, next, &sdata->output_list, link) {
- output_stride = output->width * 4;
- s = output->data;
- d = data + (output->offset_y - sdata->min_y) * buffer_stride +
- (output->offset_x - sdata->min_x) * 4;
-
- for (i = 0; i < output->height; i++) {
- memcpy(d, s, output_stride);
- d += buffer_stride;
- s += output_stride;
- }
-
- wl_list_remove(&output->link);
- free(output);
- }
-
- return data;
-}
-
-static int
-set_buffer_size(struct screenshot_data *sdata, int *width, int *height)
+static void __set_buffer_size(struct efl_data *data)
{
struct screenshooter_output *output;
- sdata->min_x = sdata->min_y = INT_MAX;
- sdata->max_x = sdata->max_y = INT_MIN;
+ data->min_x = data->min_y = INT_MAX;
+ data->max_x = data->max_y = INT_MIN;
int position = 0;
- wl_list_for_each_reverse(output, &sdata->output_list, link) {
+ wl_list_for_each_reverse(output, &data->output_list, link) {
output->offset_x = position;
position += output->width;
}
- wl_list_for_each(output, &sdata->output_list, link) {
- sdata->min_x = MIN(sdata->min_x, output->offset_x);
- sdata->min_y = MIN(sdata->min_y, output->offset_y);
- sdata->max_x = MAX(sdata->max_x,
- output->offset_x + output->width);
- sdata->max_y = MAX(sdata->max_y,
- output->offset_y + output->height);
+ wl_list_for_each(output, &data->output_list, link) {
+ data->min_x = MIN(data->min_x, output->offset_x);
+ data->min_y = MIN(data->min_y, output->offset_y);
+ data->max_x = MAX(data->max_x, output->offset_x + output->width);
+ data->max_y = MAX(data->max_y, output->offset_y + output->height);
}
- if (sdata->max_x <= sdata->min_x || sdata->max_y <= sdata->min_y)
- return -1;
-
- *width = sdata->max_x - sdata->min_x;
- *height = sdata->max_y - sdata->min_y;
-
- return 0;
-}
-
-static void *__capture_screnshot_wayland(int *width, int *height)
-{
- struct wl_display *display = NULL;
- struct wl_registry *registry;
- struct screenshooter_output *output;
- void *buf = NULL;
- struct screenshot_data *sdata;
- const char *wayland_socket = NULL;
-
- wayland_socket = getenv("WAYLAND_SOCKET");
- if (!wayland_socket)
- wayland_socket = getenv("WAYLAND_DISPLAY");
-
- if (!wayland_socket) {
- PRINTERR("must be launched by wayland");
- return NULL;
- }
-
- sdata = malloc(sizeof(*sdata));
- if (!sdata)
- return NULL;
-
- sdata->shm = NULL;
- sdata->screenshooter = NULL;
- wl_list_init(&sdata->output_list);
- sdata->min_x = 0;
- sdata->min_y = 0;
- sdata->max_x = 0;
- sdata->max_y = 0;
- sdata->buffer_copy_done = 0;
-
- display = wl_display_connect(wayland_socket);
- if (display == NULL)
- goto out;
-
- /* wl_list_init(&output_list); */
- registry = wl_display_get_registry(display);
- wl_registry_add_listener(registry, ®istry_listener, sdata);
- wl_display_dispatch(display);
- wl_display_roundtrip(display);
-
- if (sdata->screenshooter == NULL) {
- PRINTERR("display doesn't support screenshooter");
- return NULL;
- }
-
- screenshooter_add_listener(sdata->screenshooter, &screenshooter_listener,
- sdata);
-
- if (set_buffer_size(sdata, width, height))
- return NULL;
-
-
- wl_list_for_each(output, &sdata->output_list, link) {
- output->buffer = create_shm_buffer(sdata->shm, output->width,
- output->height, &output->data);
- screenshooter_shoot(sdata->screenshooter,
- output->output,
- output->buffer);
- sdata->buffer_copy_done = 0;
- while (!sdata->buffer_copy_done) {
- wl_display_roundtrip(display);
- }
+ if (data->max_x <= data->min_x || data->max_y <= data->min_y) {
+ data->width = 0;
+ data->height = 0;
+ } else {
+ data->width = data->max_x - data->min_x;
+ data->height = data->max_y - data->min_y;
}
-
- buf = __screenshot_to_buf(sdata, *width, *height);
-
-out:
- if (display)
- wl_display_disconnect(display);
- free(sdata);
- return buf;
}
static Evas* create_canvas(int width, int height)
__evas_free_p(canvas);
}
-int captureScreen()
+static int __save_to_png(const char *path, unsigned char *buf,
+ int width, int height)
{
+ int ret = -1, err;
+ Evas *ev = NULL;
+ Evas_Object *img;
+
static void (*__evas_object_resize_p)(Evas_Object *obj,
Evas_Coord w,
Evas_Coord h);
const char *key,
const char *flags);
static Evas_Object *(*__evas_object_image_add_p)(Evas *e);
- static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER;
- char dstpath[MAX_PATH_LENGTH];
- char *scrimage;
- int width, height, err;
- Evas *ev = NULL;
- Evas_Object *img;
- int ret = -1;
rtld_default_set_once(__evas_object_resize_p,
"evas_object_resize");
rtld_default_set_once(__evas_object_image_add_p,
"evas_object_image_add");
- pthread_mutex_lock(&captureScreenLock);
-
- inc_current_event_index();
- scrimage = __capture_screnshot_wayland(&width, &height);
- if (unlikely(scrimage == NULL)) {
- ret = -1;
- goto out;
- }
-
ev = create_canvas(width, height);
if (unlikely(ev == NULL)) {
- ret = -1;
- goto out_image;
+ PRINTERR("failed to create canvas");
+ return -1;
}
- snprintf(dstpath, sizeof(dstpath),
- SCREENSHOT_DIRECTORY "/%d_%d.png", getpid(),
- getCurrentEventIndex());
-
// make image buffer
img = __evas_object_image_add_p(ev);
if (unlikely(img == NULL)) {
- ret = -1;
+ PRINTERR("failed to add image to canvas");
goto out_canvas;
}
//image buffer set
__evas_object_image_data_set_p(img, NULL);
__evas_object_image_size_set_p(img, width, height);
- __evas_object_image_data_set_p(img, scrimage);
+ __evas_object_image_data_set_p(img, buf);
// resize image
if (height > MAX_HEIGHT) {
__evas_object_image_data_update_add_p(img, 0, 0, width, height);
//save image to png file
- err = __evas_object_image_save_p(img, dstpath, NULL, "compress=5");
- if (err != 0) {
+ err = __evas_object_image_save_p(img, path, NULL, "compress=5");
+ if (err != 0)
+ ret = 0;
+
+out_canvas:
+ destroy_canvas(ev);
+
+ return ret;
+}
+
+static struct efl_data *__edata = NULL;
+
+void __wayland_deinit(void)
+{
+ struct screenshooter_output *output, *next;
+
+ if (!__edata)
+ return;
+
+ wl_list_for_each_safe(output, next, &__edata->output_list, link)
+ free(output);
+
+ wl_registry_destroy(__edata->wl_registry);
+ wl_display_disconnect(__edata->wl_display);
+ free(__edata);
+}
+
+struct efl_data *__wayland_init(void)
+{
+ struct wl_display *display = NULL;
+ struct wl_registry *registry;
+ struct efl_data *data;
+ const char *wayland_socket = NULL;
+
+ if (__edata)
+ return __edata;
+
+ wayland_socket = getenv("WAYLAND_SOCKET");
+ if (!wayland_socket)
+ wayland_socket = getenv("WAYLAND_DISPLAY");
+
+ if (!wayland_socket) {
+ PRINTERR("must be launched by wayland");
+ return NULL;
+ }
+
+ data = malloc(sizeof(*data));
+ if (!data)
+ return NULL;
+
+ data->screenshooter = NULL;
+ wl_list_init(&data->output_list);
+ data->min_x = 0;
+ data->min_y = 0;
+ data->max_x = 0;
+ data->max_y = 0;
+ data->buffer_copy_done = 0;
+
+ display = wl_display_connect(wayland_socket);
+ if (display == NULL) {
+ fprintf(stderr, "failed to create display: %m\n");
+ goto fail;
+ }
+ data->wl_display = display;
+
+ /* wl_list_init(&output_list); */
+ registry = wl_display_get_registry(display);
+ wl_registry_add_listener(registry, ®istry_listener, data);
+ wl_display_dispatch(display);
+ wl_display_roundtrip(display);
+
+ data->wl_registry = registry;
+
+ __edata = data;
+
+ return data;
+fail:
+ free(data);
+ return NULL;
+}
+static int __capture_screnshot_wayland(const char *path)
+{
+ struct screenshooter_output *output;
+ struct efl_data *data;
+ tbm_surface_h t_surface;
+ struct wl_buffer *buffer;
+ struct wayland_tbm_client *tbm_client;
+ tbm_surface_info_s tsuri;
+ int plane_idx = 0;
+ int ret = -1;
+ int err;
+
+ data = __wayland_init();
+ if (!data) {
+ PRINTERR("failed to init wayland protocol\n");
+ return -1;
+ }
+
+ if (!data->screenshooter) {
+ PRINTERR("display doesn't support screenshooter\n");
+ return -1;
+ }
+
+ __set_buffer_size(data);
+
+ tbm_client = wayland_tbm_client_init(data->wl_display);
+ if (!tbm_client) {
+ PRINTERR("failed to init tbm client\n");
+ return -1;
+ }
+
+ t_surface = tbm_surface_create(data->width, data->height, TBM_FORMAT_XRGB8888);
+ if (!t_surface) {
+ PRINTERR("failed to create tbm_surface\n");
+ goto fail_tbm_client;
+ }
+
+ buffer = wayland_tbm_client_create_buffer(tbm_client, t_surface);
+ if (!buffer) {
+ PRINTERR("failed to create wl_buffer for screenshot\n");
+ goto fail_tbm_surface;
+ }
+
+ wl_list_for_each(output, &data->output_list, link) {
+ screenshooter_shoot(data->screenshooter,
+ output->output,
+ buffer);
+ data->buffer_copy_done = 0;
+ while (!data->buffer_copy_done) {
+ wl_display_roundtrip(data->wl_display);
+ }
+ }
+
+ err = tbm_surface_map(t_surface,
+ TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
+ &tsuri);
+ if (err != TBM_SURFACE_ERROR_NONE) {
+ PRINTERR("failed to map tbm_surface\n");
+ goto fail_map_surface;
+ }
+
+ ret = __save_to_png(path, tsuri.planes[plane_idx].ptr,
+ data->width, data->height);
+
+ tbm_surface_unmap(t_surface);
+
+fail_map_surface:
+ wayland_tbm_client_destroy_buffer(tbm_client, buffer);
+
+fail_tbm_surface:
+ tbm_surface_destroy(t_surface);
+
+fail_tbm_client:
+ wayland_tbm_client_deinit(tbm_client);
+
+ return ret;
+}
+
+int captureScreen()
+{
+ static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER;
+ char dstpath[MAX_PATH_LENGTH];
+ int ret = -1;
+
+ pthread_mutex_lock(&captureScreenLock);
+
+ inc_current_event_index();
+
+ snprintf(dstpath, sizeof(dstpath),
+ SCREENSHOT_DIRECTORY "/%d_%d.png", getpid(),
+ getCurrentEventIndex());
+
+ ret = __capture_screnshot_wayland(dstpath);
+ if (!ret) {
if (chmod(dstpath, 0777) == -1)
PRINTWRN("cannot chmod -R777 <%s>", dstpath);
ret = 0;
}
- // release resources
-out_canvas:
- destroy_canvas(ev);
-
-out_image:
- free(scrimage);
-
-out:
pthread_mutex_unlock(&captureScreenLock);
return ret;
}