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