uihv: move the creation of the screenshot path
[platform/core/system/swap-manager.git] / ui_viewer / ui_viewer_screenshot.c
1 /*
2  *  DA manager
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  * Copyright (c) 2008 Kristian Høgsberg (screenshooter)
6  *
7  * Contact:
8  *
9  * Lyupa Anastasia <a.lyupa@samsung.com>
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  * Contributors:
24  * - Samsung RnD Institute Russia
25  *
26  */
27
28 #include <stdlib.h>             // for system
29 #include <sys/types.h>          // for stat, getpid
30 #include <sys/stat.h>           // fot stat, chmod
31 #include <unistd.h>             // fot stat, getpid
32 #include <pthread.h>            // for mutex
33 #include <sys/param.h>          // MIN, MAX
34 #include <sys/mman.h>           // mmap
35
36 #include <Ecore.h>
37 #include <Evas.h>
38 #include <Evas_Engine_Buffer.h>
39 #include <Elementary.h>
40
41 #include <wayland-client.h>
42 #include <wayland-tbm-client.h>
43 #include <tbm_bufmgr.h>
44 #include <tbm_surface.h>
45 #include <tbm_surface_internal.h>
46 #include <tizen-extension-client-protocol.h>
47 #include <screenshooter-client-protocol.h>
48
49 #include "ui_viewer_utils.h"
50
51 #define MAX_PATH_LENGTH         256
52
53 static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER;
54
55 struct efl_data {
56         struct wl_display *wl_display;
57         struct wl_registry *wl_registry;
58         struct wl_event_queue *wl_queue;
59         struct screenshooter *screenshooter;
60         struct wl_list output_list;
61         int min_x, min_y, max_x, max_y;
62         int buffer_copy_done;
63         int width, height;
64 };
65
66 struct screenshot_data {
67         struct wl_shm *shm;
68         struct screenshooter *screenshooter;
69         struct wl_list output_list;
70         int min_x, min_y, max_x, max_y;
71         int buffer_copy_done;
72 };
73
74 struct screenshooter_output {
75         struct wl_output *output;
76         struct wl_buffer *buffer;
77         int width, height, offset_x, offset_y;
78         void *data;
79         struct wl_list link;
80 };
81
82 static void
83 display_handle_geometry(void __attribute__((unused)) *data,
84                         struct wl_output *wl_output,
85                         int x,
86                         int y,
87                         int __attribute__((unused)) physical_width,
88                         int __attribute__((unused)) physical_height,
89                         int __attribute__((unused)) subpixel,
90                         const char __attribute__((unused)) *make,
91                         const char __attribute__((unused)) *model,
92                         int __attribute__((unused)) transform)
93 {
94         struct screenshooter_output *output;
95
96         output = wl_output_get_user_data(wl_output);
97
98         if (wl_output == output->output) {
99                 output->offset_x = x;
100                 output->offset_y = y;
101         }
102 }
103
104 static void
105 display_handle_mode(void __attribute__((unused)) *data,
106                     struct wl_output *wl_output, uint32_t flags, int width,
107                     int height, int __attribute__((unused)) refresh)
108 {
109         struct screenshooter_output *output;
110
111         output = wl_output_get_user_data(wl_output);
112
113         if ((wl_output == output->output) && (flags & WL_OUTPUT_MODE_CURRENT)) {
114                 output->width = width;
115                 output->height = height;
116         }
117 }
118
119 static const struct wl_output_listener output_listener = {
120         display_handle_geometry,
121         display_handle_mode,
122         NULL,
123         NULL
124 };
125
126 static void
127 screenshot_done(void *data,
128                 struct screenshooter __attribute__((unused)) *screenshooter)
129 {
130         struct efl_data *sdata = data;
131         sdata->buffer_copy_done = 1;
132 }
133
134 static const struct screenshooter_listener screenshooter_listener = {
135         screenshot_done
136 };
137
138 static void
139 handle_global(void *data, struct wl_registry *registry,
140               uint32_t name, const char *interface,
141               uint32_t __attribute__((unused)) version)
142 {
143         struct efl_data *sdata = data;
144
145         if (strcmp(interface, "wl_output") == 0) {
146                 struct screenshooter_output *output = malloc(sizeof(*output));
147
148                 if (output) {
149                         PRINTMSG("allocate %p", output);
150                         output->output = wl_registry_bind(registry, name,
151                                                           &wl_output_interface,
152                                                           1);
153                         wl_list_insert(&sdata->output_list, &output->link);
154                         wl_output_add_listener(output->output,
155                                                &output_listener, output);
156                 }
157         } else if (strcmp(interface, "screenshooter") == 0) {
158                 sdata->screenshooter = wl_registry_bind(registry, name,
159                                                  &screenshooter_interface,
160                                                  1);
161                 screenshooter_add_listener(sdata->screenshooter,
162                                            &screenshooter_listener,
163                                            sdata);
164         }
165 }
166
167 static const struct wl_registry_listener registry_listener = {
168         handle_global,
169         NULL
170 };
171
172 static struct efl_data *__edata = NULL;
173
174 void wayland_deinit(void)
175 {
176         struct screenshooter_output *output, *next;
177
178         if (!__edata)
179                 return;
180
181         wl_list_for_each_safe(output, next, &__edata->output_list, link)
182                 free(output);
183
184         wl_registry_destroy(__edata->wl_registry);
185         wl_event_queue_destroy(__edata->wl_queue);
186         wl_display_disconnect(__edata->wl_display);
187         free(__edata);
188         __edata = NULL;
189 }
190
191 static struct efl_data *__wayland_init(void)
192 {
193         struct wl_event_queue *queue;
194         struct wl_display *display = NULL;
195         struct wl_registry *registry;
196         struct efl_data *data;
197         const char *wayland_socket = NULL;
198
199         if (__edata)
200                 return __edata;
201
202         wayland_socket = getenv("WAYLAND_SOCKET");
203         if (!wayland_socket)
204                 wayland_socket = getenv("WAYLAND_DISPLAY");
205
206         if (!wayland_socket) {
207                 PRINTERR("must be launched by wayland");
208                 return NULL;
209         }
210
211         data = malloc(sizeof(*data));
212         if (!data)
213                 return NULL;
214
215         data->screenshooter = NULL;
216         wl_list_init(&data->output_list);
217         data->min_x = 0;
218         data->min_y = 0;
219         data->max_x = 0;
220         data->max_y = 0;
221         data->buffer_copy_done = 0;
222
223         display = wl_display_connect(wayland_socket);
224         if (display == NULL) {
225                 PRINTERR("failed to create display: %m\n");
226                 goto fail_display;
227         }
228
229         queue = wl_display_create_queue(display);
230         if (queue == NULL) {
231                 PRINTERR("failed to create display queue: %m\n");
232                 goto fail_queue;
233         }
234
235         /* wl_list_init(&output_list); */
236         registry = wl_display_get_registry(display);
237         wl_proxy_set_queue((struct wl_proxy*)registry, queue);
238         wl_registry_add_listener(registry, &registry_listener, data);
239         wl_display_dispatch_queue(display, queue);
240         wl_display_roundtrip_queue(display, queue);
241
242         data->wl_display = display;
243         data->wl_queue = queue;
244         data->wl_registry = registry;
245         __edata = data;
246
247         return data;
248
249 fail_queue:
250         wl_display_disconnect(display);
251
252 fail_display:
253         free(data);
254         return NULL;
255 }
256
257 static void  __set_buffer_size(struct efl_data *data)
258 {
259         struct screenshooter_output *output;
260
261         data->min_x = data->min_y = INT_MAX;
262         data->max_x = data->max_y = INT_MIN;
263         int position = 0;
264
265         wl_list_for_each_reverse(output, &data->output_list, link) {
266                 output->offset_x = position;
267                 position += output->width;
268         }
269
270         wl_list_for_each(output, &data->output_list, link) {
271                 data->min_x = MIN(data->min_x, output->offset_x);
272                 data->min_y = MIN(data->min_y, output->offset_y);
273                 data->max_x = MAX(data->max_x, output->offset_x + output->width);
274                 data->max_y = MAX(data->max_y, output->offset_y + output->height);
275         }
276
277         if (data->max_x <= data->min_x || data->max_y <= data->min_y) {
278                 data->width = 0;
279                 data->height = 0;
280         } else {
281                 data->width = data->max_x - data->min_x;
282                 data->height = data->max_y - data->min_y;
283         }
284 }
285
286 static int min(int a, int b)
287 {
288         if (a < b)
289                 return a;
290         return b;
291 }
292
293 static int max(int a, int b)
294 {
295         if (a > b)
296                 return a;
297         return b;
298 }
299
300 static void *__tbm_surface_to_buf(unsigned char *src, uint32_t src_stride,
301                                   uint32_t src_size, int x, int y,
302                                   int width, int height)
303 {
304         int dest_stride;
305         int dest_copy_size;
306         void *data, *dest;
307         uint32_t dest_size;
308         int n;
309
310         int dest_x, dest_y, dest_width, dest_height;
311         int src_x, src_y, src_width, src_height;
312
313
314         src_x = max(x, 0);
315         src_y = max(y, 0);
316
317         src_width = src_stride / 4;
318         src_height = src_size / src_stride;
319
320         src_width = max(0, min(x + width, src_width) - src_x);
321         src_height = max(0, min(y + height, src_height) - src_y);
322
323         dest_x = -min(x, 0);
324         dest_y = -min(y, 0);
325         dest_width = width;
326         dest_height = height;
327         dest_stride = dest_width * 4;
328         dest_size = dest_stride * dest_height;
329
330         data = calloc(1, dest_size);
331         if (!data)
332                 return NULL;
333
334         dest = data + dest_x * 4 + dest_y * dest_stride;
335         src = src + src_x * 4 + src_y * src_stride;
336         dest_copy_size = src_width * 4;
337
338         for (n = 0; n < src_height; n++) {
339                 memcpy(dest, src, dest_copy_size);
340                 dest += dest_stride;
341                 src += src_stride;
342         }
343         return data;
344 }
345
346 static void *__capture_screnshot_wayland(int x, int y, int width, int height)
347 {
348         struct screenshooter_output *output;
349         struct efl_data *data;
350         tbm_surface_h t_surface;
351         struct wl_buffer *buffer;
352         struct wayland_tbm_client *tbm_client;
353         tbm_surface_info_s tsuri;
354         int plane_idx = 0;
355         int err;
356         void *buf = NULL;
357
358         data =  __wayland_init();
359         if (!data) {
360                 PRINTERR("failed to init wayland protocol\n");
361                 return NULL;
362         }
363
364         if (!data->screenshooter) {
365                 PRINTERR("display doesn't support screenshooter\n");
366                 return NULL;
367         }
368
369         __set_buffer_size(data);
370
371         tbm_client = wayland_tbm_client_init(data->wl_display);
372         if (!tbm_client) {
373                 PRINTERR("failed to init tbm client\n");
374                 return NULL;
375         }
376
377         t_surface = tbm_surface_create(data->width, data->height, TBM_FORMAT_XRGB8888);
378         if (!t_surface) {
379                 PRINTERR("failed to create tbm_surface\n");
380                 goto fail_tbm_client;
381         }
382
383         buffer = wayland_tbm_client_create_buffer(tbm_client, t_surface);
384         if (!buffer) {
385                 PRINTERR("failed to create wl_buffer for screenshot\n");
386                 goto fail_tbm_surface;
387         }
388
389         wl_list_for_each(output, &data->output_list, link) {
390                 screenshooter_shoot(data->screenshooter,
391                                            output->output,
392                                            buffer);
393                 data->buffer_copy_done = 0;
394                 while (!data->buffer_copy_done) {
395                         wl_display_roundtrip_queue(data->wl_display,
396                                                    data->wl_queue);
397                 }
398         }
399
400         err = tbm_surface_map(t_surface,
401                               TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE,
402                               &tsuri);
403         if (err != TBM_SURFACE_ERROR_NONE) {
404                 PRINTERR("failed to map tbm_surface\n");
405                 goto fail_map_surface;
406         }
407
408         buf = __tbm_surface_to_buf(tsuri.planes[plane_idx].ptr,
409                                    tsuri.planes[plane_idx].stride,
410                                    tsuri.planes[plane_idx].size,
411                                    x, y, width, height);
412
413         tbm_surface_unmap(t_surface);
414
415 fail_map_surface:
416         wayland_tbm_client_destroy_buffer(tbm_client, buffer);
417
418 fail_tbm_surface:
419         tbm_surface_destroy(t_surface);
420
421 fail_tbm_client:
422         wayland_tbm_client_deinit(tbm_client);
423
424         return buf;
425 }
426 static int capture_object(const char *screenshot_path, int width, int height,
427                           Evas_Object *obj, const char *type_name)
428 {
429         Evas_Object *img;
430         Evas *canvas, *sub_canvas;
431         Ecore_Evas *ee, *sub_ee;
432         int ret = 0;
433         char *image_data = NULL;
434
435         canvas = evas_object_evas_get(obj);
436         ee = ecore_evas_ecore_evas_get(canvas);
437         img = ecore_evas_object_image_new(ee);
438         evas_object_image_filled_set(img, EINA_TRUE);
439         evas_object_image_size_set(img, width, height);
440         sub_ee = ecore_evas_object_ecore_evas_get(img);
441         sub_canvas = ecore_evas_object_evas_get(img);
442         evas_object_resize(img, width, height);
443         ecore_evas_resize(sub_ee, width, height);
444
445         if (!strcmp(type_name, "rectangle")) {
446                 Evas_Object *rect;
447                 int r, g, b, a;
448
449                 rect = evas_object_rectangle_add(sub_canvas);
450                 evas_object_color_get(obj, &r, &g, &b, &a);
451                 evas_object_color_set(rect, r, g, b, a);
452                 evas_object_resize(rect, width, height);
453                 evas_object_show(rect);
454         } else if (!strcmp(type_name, "image")) {
455                 Evas_Object *image;
456                 void *img_data;
457                 int w, h;
458
459                 img_data = evas_object_image_data_get(obj, EINA_FALSE);
460                 evas_object_image_size_get(obj, &w, &h);
461                 image = evas_object_image_filled_add(sub_canvas);
462                 evas_object_image_size_set(image, w, h);
463                 evas_object_image_data_set(image, img_data);
464                 evas_object_image_data_update_add(image, 0, 0, w, h);
465                 evas_object_resize(image, width, height);
466
467                 evas_object_show(image);
468         } else {
469                 int x, y;
470                 Evas_Object *image;
471
472                 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
473                 image_data = __capture_screnshot_wayland(x, y, width, height);
474                 if (image_data == NULL)
475                         goto finish;
476                 image = evas_object_image_filled_add(sub_canvas);
477                 evas_object_image_size_set(image, width, height);
478                 evas_object_image_data_set(image, image_data);
479                 evas_object_image_data_update_add(image, 0, 0, width, height);
480                 evas_object_resize(image, width, height);
481                 evas_object_show(image);
482         }
483
484 finish:
485         ecore_evas_manual_render(sub_ee);
486
487         if (!evas_object_image_save(img, screenshot_path, NULL, "compress=5")) {
488                 ui_viewer_log("ERROR: capture_object : can't save image\n");
489                 ret = -1;
490         }
491
492         evas_object_del(img);
493         free(image_data);
494
495         return ret;
496 }
497
498 int ui_viewer_capture_screen(const char *screenshot_path, Evas_Object *obj)
499 {
500         int view_w, view_h;
501         int obj_x, obj_y, obj_w, obj_h;
502         int ret = 0;
503         Evas *evas;
504         char type_name[MAX_PATH_LENGTH];
505
506         pthread_mutex_lock(&captureScreenLock);
507
508         evas = evas_object_evas_get(obj);
509         if (evas == NULL) {
510                 PRINTERR("Bad object evas");
511                 pthread_mutex_unlock(&captureScreenLock);
512                 return -1;
513         }
514         _strncpy(type_name, evas_object_type_get(obj), MAX_PATH_LENGTH);
515
516         evas_output_viewport_get(evas, NULL, NULL, &view_w, &view_h);
517         evas_object_geometry_get(obj, &obj_x, &obj_y, &obj_w, &obj_h);
518
519         if (obj_w == 0 || obj_h == 0) {
520                 ui_viewer_log("ui_viewer_capture_screen : object %p[%d,%d]"
521                               "has zero width or height\n", obj, obj_w, obj_h);
522                 ret = -1;
523         } else if (!strcmp(type_name, "rectangle")) {
524                 int width, height;
525
526                 // restrict rectangle area
527                 width = (obj_w <= view_w) ? obj_w : view_w;
528                 height = (obj_h <= view_h) ? obj_h : view_h;
529
530                 ret = capture_object(screenshot_path, width, height, obj,
531                                      type_name);
532         } else if (!strcmp(type_name, "image")) {
533                 ret = capture_object(screenshot_path, obj_w, obj_h, obj,
534                                      type_name);
535         } else if (!strcmp(type_name, "vectors")) {
536                 ret = -1;
537         } else if (!strcmp(type_name, "elm_image") ||
538                    !strcmp(type_name, "elm_icon")) {
539                 Evas_Object *internal_img;
540                 int img_w, img_h;
541
542                 internal_img = elm_image_object_get(obj);
543                 evas_object_geometry_get(internal_img, NULL, NULL, &img_w,
544                                          &img_h);
545
546                 ret = capture_object(screenshot_path, img_w, img_h,
547                                      internal_img, type_name);
548         } else if (obj_x > view_w || obj_y > view_h) {
549                 ui_viewer_log("ui_viewer_capture_screen:"
550                               "object %p lies beside view area\n", obj);
551                 ret = -1;
552         } else if (!evas_object_visible_get(obj)) {
553                 ui_viewer_log("ui_viewer_capture_screen:"
554                               "object %p is unvisible\n", obj);
555                 ret = -1;
556         } else {
557                 int width, height;
558
559                 // take visible on screen part of object
560                 width = (view_w < obj_w + obj_x) ? (view_w - obj_x) : obj_w;
561                 height = (view_h < obj_h + obj_y) ? (view_h - obj_y) : obj_h;
562
563                 ret = capture_object(screenshot_path, width, height, obj,
564                                      type_name);
565         }
566
567         pthread_mutex_unlock(&captureScreenLock);
568         return ret;
569 }