Commit 82cb2aeb0424e7f6928c47a466c36d447b860d99

Authored by 신재종
1 parent 89fd7edb83
Exists in master

rename main source code

Showing 3 changed files with 1062 additions and 1062 deletions   Show diff stats
Makefile
... ... @@ -60,7 +60,7 @@ LDFLAGS+=`pkg-config --libs libjpeg`
60 60  
61 61 all:
62 62 $(GCC) $(CFLAGS) --sysroot $(SDKTARGETSYSROOT) $(LDFLAGS) $(INC) -o weston-vncserver \
63   - screenshot.c \
  63 + vncserver.c \
64 64 protocol/pointer-constraints-unstable-v1-protocol.c \
65 65 protocol/relative-pointer-unstable-v1-protocol.c \
66 66 protocol/text-cursor-position-protocol.c \
... ...
screenshot.c
... ... @@ -1,1061 +0,0 @@
1   -/*
2   - * Copyright © 2008 Kristian Høgsberg
3   - *
4   - * Permission is hereby granted, free of charge, to any person obtaining a
5   - * copy of this software and associated documentation files (the "Software"),
6   - * to deal in the Software without restriction, including without limitation
7   - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8   - * and/or sell copies of the Software, and to permit persons to whom the
9   - * Software is furnished to do so, subject to the following conditions:
10   - *
11   - * The above copyright notice and this permission notice (including the next
12   - * paragraph) shall be included in all copies or substantial portions of the
13   - * Software.
14   - *
15   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18   - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20   - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21   - * DEALINGS IN THE SOFTWARE.
22   - */
23   -
24   -#include "config.h"
25   -
26   -#include <stdint.h>
27   -#include <errno.h>
28   -#include <stdlib.h>
29   -#include <stdio.h>
30   -#include <stdbool.h>
31   -#include <string.h>
32   -#include <fcntl.h>
33   -#include <libgen.h>
34   -#include <unistd.h>
35   -#include <limits.h>
36   -#include <sys/epoll.h>
37   -#include <sys/param.h>
38   -#include <sys/mman.h>
39   -#include <math.h>
40   -#include <time.h>
41   -#include <cairo.h>
42   -#include <signal.h>
43   -#include <assert.h>
44   -#include <errno.h>
45   -#include <linux/input.h>
46   -#include <pixman.h>
47   -
48   -#include <wayland-client.h>
49   -#include "weston-screenshooter-client-protocol.h"
50   -#include "shared/os-compatibility.h"
51   -#include "shared/xalloc.h"
52   -#include "shared/file-util.h"
53   -#include "shared/cairo-util.h"
54   -#include "shared/helpers.h"
55   -#include "window.h"
56   -
57   -/* The screenshooter is a good example of a custom object exposed by
58   - * the compositor and serves as a test bed for implementing client
59   - * side marshalling outside libwayland.so */
60   -
61   -int isloop = 1;
62   -struct image *pimage;
63   -
64   -struct screenshooter_output
65   -{
66   - struct wl_output *output;
67   - struct wl_buffer *buffer;
68   - int width, height, offset_x, offset_y;
69   - void *data;
70   - struct wl_list link;
71   -};
72   -
73   -struct buffer_size
74   -{
75   - int width, height;
76   -
77   - int min_x, min_y;
78   - int max_x, max_y;
79   -};
80   -
81   -struct screenshooter_data
82   -{
83   - struct wl_shm *shm;
84   - struct wl_list output_list;
85   -
86   - struct weston_screenshooter *screenshooter;
87   - int buffer_copy_done;
88   -};
89   -
90   -struct image
91   -{
92   - struct window *window;
93   - struct widget *widget;
94   - struct display *display;
95   - char *filename;
96   - cairo_surface_t *image;
97   - int fullscreen;
98   - int *image_counter;
99   - int32_t width, height;
100   -
101   - struct
102   - {
103   - double x;
104   - double y;
105   - } pointer;
106   - bool button_pressed;
107   -
108   - bool initialized;
109   - cairo_matrix_t matrix;
110   -};
111   -
112   -struct display
113   -{
114   - struct wl_display *display;
115   - struct wl_registry *registry;
116   - struct wl_compositor *compositor;
117   - struct wl_subcompositor *subcompositor;
118   - struct wl_shm *shm;
119   - struct wl_data_device_manager *data_device_manager;
120   - struct text_cursor_position *text_cursor_position;
121   - struct xdg_wm_base *xdg_shell;
122   - struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
123   - struct zwp_pointer_constraints_v1 *pointer_constraints;
124   - EGLDisplay dpy;
125   - EGLConfig argb_config;
126   - EGLContext argb_ctx;
127   - cairo_device_t *argb_device;
128   - uint32_t serial;
129   -
130   - int display_fd;
131   - uint32_t display_fd_events;
132   - struct task display_task;
133   -
134   - int epoll_fd;
135   - struct wl_list deferred_list;
136   -
137   - int running;
138   -
139   - struct wl_list global_list;
140   - struct wl_list window_list;
141   - struct wl_list input_list;
142   - struct wl_list output_list;
143   -
144   - struct theme *theme;
145   -
146   - struct wl_cursor_theme *cursor_theme;
147   - struct wl_cursor **cursors;
148   -
149   - display_output_handler_t output_configure_handler;
150   - display_global_handler_t global_handler;
151   - display_global_handler_t global_handler_remove;
152   -
153   - void *user_data;
154   -
155   - struct xkb_context *xkb_context;
156   -
157   - /* A hack to get text extents for tooltips */
158   - cairo_surface_t *dummy_surface;
159   - void *dummy_surface_data;
160   -
161   - int data_device_manager_version;
162   - struct wp_viewporter *viewporter;
163   -};
164   -
165   -static void handler_sigint(int sig)
166   -{
167   - isloop = 0;
168   -}
169   -
170   -static void
171   -display_handle_geometry(void *data,
172   - struct wl_output *wl_output,
173   - int x,
174   - int y,
175   - int physical_width,
176   - int physical_height,
177   - int subpixel,
178   - const char *make,
179   - const char *model,
180   - int transform)
181   -{
182   - struct screenshooter_output *output;
183   -
184   - output = wl_output_get_user_data(wl_output);
185   -
186   - if (wl_output == output->output)
187   - {
188   - output->offset_x = x;
189   - output->offset_y = y;
190   - }
191   -}
192   -
193   -static void
194   -display_handle_mode(void *data,
195   - struct wl_output *wl_output,
196   - uint32_t flags,
197   - int width,
198   - int height,
199   - int refresh)
200   -{
201   - struct screenshooter_output *output;
202   -
203   - output = wl_output_get_user_data(wl_output);
204   -
205   - if ((wl_output == output->output) && (flags & WL_OUTPUT_MODE_CURRENT))
206   - {
207   - output->width = width;
208   - output->height = height;
209   - }
210   -}
211   -
212   -static const struct wl_output_listener output_listener = {
213   - display_handle_geometry,
214   - display_handle_mode
215   -};
216   -
217   -static void
218   -screenshot_done(void *data, struct weston_screenshooter *screenshooter)
219   -{
220   - struct screenshooter_data *sh_data = data;
221   - sh_data->buffer_copy_done = 1;
222   -}
223   -
224   -static const struct weston_screenshooter_listener screenshooter_listener = {
225   - screenshot_done
226   -};
227   -
228   -static void
229   -handle_global(void *data, struct wl_registry *registry,
230   - uint32_t name, const char *interface, uint32_t version)
231   -{
232   - static struct screenshooter_output *output;
233   - struct screenshooter_data *sh_data = data;
234   -
235   - if (strcmp(interface, "wl_output") == 0)
236   - {
237   - output = xmalloc(sizeof *output);
238   - output->output = wl_registry_bind(registry, name,
239   - &wl_output_interface, 1);
240   - wl_list_insert(&sh_data->output_list, &output->link);
241   - wl_output_add_listener(output->output, &output_listener, output);
242   - }
243   - else if (strcmp(interface, "wl_shm") == 0)
244   - {
245   - sh_data->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
246   - }
247   - else if (strcmp(interface, "weston_screenshooter") == 0)
248   - {
249   - sh_data->screenshooter = wl_registry_bind(registry, name,
250   - &weston_screenshooter_interface,
251   - 1);
252   - }
253   -}
254   -
255   -static void
256   -handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
257   -{
258   - /* XXX: unimplemented */
259   -}
260   -
261   -static const struct wl_registry_listener registry_listener = {
262   - handle_global,
263   - handle_global_remove
264   -};
265   -
266   -static struct wl_buffer *
267   -screenshot_create_shm_buffer(int width, int height, void **data_out,
268   - struct wl_shm *shm)
269   -{
270   - struct wl_shm_pool *pool;
271   - struct wl_buffer *buffer;
272   - int fd, size, stride;
273   - void *data;
274   -
275   - stride = width * 4;
276   - size = stride * height;
277   -
278   - // printf("screenshot_create_shm_buffer width[%d] height[%d] stride[%d] size[%d]\n",width,height,stride,size);
279   - fd = os_create_anonymous_file(size);
280   - if (fd < 0)
281   - {
282   - fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
283   - size, strerror(errno));
284   - return NULL;
285   - }
286   -
287   - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
288   - if (data == MAP_FAILED)
289   - {
290   - fprintf(stderr, "mmap failed: %s\n", strerror(errno));
291   - close(fd);
292   - return NULL;
293   - }
294   -
295   - pool = wl_shm_create_pool(shm, fd, size);
296   - close(fd);
297   - buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
298   - WL_SHM_FORMAT_XRGB8888);
299   - wl_shm_pool_destroy(pool);
300   -
301   - *data_out = data;
302   -
303   - return buffer;
304   -}
305   -
306   -
307   -static double
308   -get_scale(struct image *image)
309   -{
310   - assert(image->matrix.xy == 0.0 &&
311   - image->matrix.yx == 0.0 &&
312   - image->matrix.xx == image->matrix.yy);
313   - return image->matrix.xx;
314   -}
315   -
316   -static void
317   -clamp_view(struct image *image)
318   -{
319   - struct rectangle allocation;
320   - double scale = get_scale(image);
321   - double sw, sh;
322   - // printf("clamp scale[%f]\n",scale);
323   - // printf("clamp image->width[%d] height[%d]\n",image->width,image->height);
324   -
325   - sw = image->width * scale;
326   - sh = image->height * scale;
327   - widget_get_allocation(image->widget, &allocation);
328   -
329   - // printf("clamp sw[%f] sh[%f]\n",sw,sh);
330   - // printf("clamp allocation.width[%d] height[%d]\n"),allocation.width,allocation.height;
331   -
332   - if (sw < allocation.width)
333   - {
334   - image->matrix.x0 =
335   - (allocation.width - image->width * scale) / 2;
336   - }
337   - else
338   - {
339   - if (image->matrix.x0 > 0.0)
340   - {
341   - image->matrix.x0 = 0.0;
342   - }
343   - if (sw + image->matrix.x0 < allocation.width)
344   - {
345   - image->matrix.x0 = allocation.width - sw;
346   - }
347   - }
348   -
349   - if (sh < allocation.height)
350   - {
351   - image->matrix.y0 =
352   - (allocation.height - image->height * scale) / 2;
353   - }
354   - else
355   - {
356   - if (image->matrix.y0 > 0.0)
357   - {
358   - image->matrix.y0 = 0.0;
359   - }
360   - if (sh + image->matrix.y0 < allocation.height)
361   - {
362   - image->matrix.y0 = allocation.height - sh;
363   - }
364   - }
365   -
366   - // printf("clamp matrix x0:%f y0:%fxx:%f xy:%f yx:%f yy:%f\n",image->matrix.x0,image->matrix.y0, image->matrix.xx,image->matrix.xy,image->matrix.yx,image->matrix.yy);
367   - // printf("x0[%f] y0[%f]\n",image->matrix.x0, image->matrix.y0);
368   -}
369   -
370   -static void
371   -redraw_handler(struct widget *widget, void *data)
372   -{
373   - struct image *image = data;
374   - struct rectangle allocation;
375   - cairo_t *cr;
376   - cairo_surface_t *surface;
377   - double width, height, doc_aspect, window_aspect, scale;
378   - cairo_matrix_t matrix;
379   - cairo_matrix_t translate;
380   -
381   - surface = window_get_surface(image->window);
382   - cr = cairo_create(surface);
383   - widget_get_allocation(image->widget, &allocation);
384   - // printf("allocation x[%d] y[%d] width[%d] height[%d]\n", allocation.x, allocation.y, allocation.width,allocation.height);
385   -
386   - cairo_rectangle(cr, allocation.x, allocation.y,
387   - allocation.width, allocation.height);
388   - cairo_clip(cr);
389   - cairo_push_group(cr);
390   - cairo_translate(cr, allocation.x, allocation.y);
391   -
392   - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
393   - // cairo_set_source_rgba(cr, 1, 0, 1, 0.5); // magenta transparency 50%
394   - cairo_set_source_rgba(cr, 0, 0, 0, 0);
395   - cairo_paint(cr);
396   -
397   - if (!image->initialized)
398   - {
399   - image->initialized = true;
400   - width = cairo_image_surface_get_width(image->image);
401   - height = cairo_image_surface_get_height(image->image);
402   -
403   - doc_aspect = width / height;
404   - window_aspect = (double) allocation.width / allocation.height;
405   - if (doc_aspect < window_aspect)
406   - {
407   - scale = allocation.height / height;
408   - }
409   - else
410   - {
411   - scale = allocation.width / width;
412   - }
413   -
414   - // printf("doc_aspect[%f]\n",doc_aspect);
415   - // printf("window_aspect[%f]\n",window_aspect);
416   - // printf("scale[%f]\n",scale);
417   -
418   - image->width = width;
419   - image->height = height;
420   - cairo_matrix_init_scale(&image->matrix, scale, scale);
421   -
422   - clamp_view(image);
423   - }
424   -
425   - matrix = image->matrix;
426   - cairo_matrix_init_translate(&translate, allocation.x, allocation.y);
427   - // printf("init matrix x0:%f y0:%f xx:%f xy:%f yx:%f yy:%f\n",matrix.x0,matrix.y0,matrix.xx,matrix.xy,matrix.yx,matrix.yy);
428   - cairo_matrix_multiply(&matrix, &matrix, &translate);
429   - // printf("mult matrix x0:%f y0:%f xx:%f xy:%f yx:%f yy:%f\n",matrix.x0,matrix.y0,matrix.xx,matrix.xy,matrix.yx,matrix.yy);
430   - cairo_set_matrix(cr, &matrix);
431   -
432   - cairo_set_source_surface(cr, image->image, 0, 0);
433   - cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
434   - cairo_paint(cr);
435   -
436   - cairo_pop_group_to_source(cr);
437   - cairo_paint(cr);
438   - cairo_destroy(cr);
439   -
440   - cairo_surface_destroy(surface);
441   -}
442   -
443   -static void
444   -resize_handler(struct widget *widget,
445   - int32_t width, int32_t height, void *data)
446   -{
447   - struct image *image = data;
448   -
449   - clamp_view(image);
450   -}
451   -
452   -static void
453   -keyboard_focus_handler(struct window *window,
454   - struct input *device, void *data)
455   -{
456   - struct image *image = data;
457   -
458   - window_schedule_redraw(image->window);
459   -}
460   -
461   -static int
462   -enter_handler(struct widget *widget,
463   - struct input *input,
464   - float x, float y, void *data)
465   -{
466   - struct image *image = data;
467   - struct rectangle allocation;
468   -
469   - widget_get_allocation(image->widget, &allocation);
470   - x -= allocation.x;
471   - y -= allocation.y;
472   -
473   - image->pointer.x = x;
474   - image->pointer.y = y;
475   -
476   - return 1;
477   -}
478   -
479   -static void
480   -move_viewport(struct image *image, double dx, double dy)
481   -{
482   - double scale = get_scale(image);
483   -
484   - if (!image->initialized)
485   - {
486   - return;
487   - }
488   -
489   - cairo_matrix_translate(&image->matrix, -dx/scale, -dy/scale);
490   - clamp_view(image);
491   -
492   - window_schedule_redraw(image->window);
493   -}
494   -
495   -static int
496   -motion_handler(struct widget *widget,
497   - struct input *input, uint32_t time,
498   - float x, float y, void *data)
499   -{
500   - struct image *image = data;
501   - struct rectangle allocation;
502   -
503   - widget_get_allocation(image->widget, &allocation);
504   - x -= allocation.x;
505   - y -= allocation.y;
506   -
507   - if (image->button_pressed)
508   - {
509   - move_viewport(image, image->pointer.x - x,
510   - image->pointer.y - y);
511   - }
512   -
513   - image->pointer.x = x;
514   - image->pointer.y = y;
515   -
516   - return image->button_pressed ? CURSOR_DRAGGING : CURSOR_LEFT_PTR;
517   -}
518   -
519   -static void
520   -button_handler(struct widget *widget,
521   - struct input *input, uint32_t time,
522   - uint32_t button,
523   - enum wl_pointer_button_state state,
524   - void *data)
525   -{
526   - struct image *image = data;
527   -
528   - if (button == BTN_LEFT)
529   - {
530   - image->button_pressed =
531   - state == WL_POINTER_BUTTON_STATE_PRESSED;
532   -
533   - if (state == WL_POINTER_BUTTON_STATE_PRESSED)
534   - {
535   - input_set_pointer_image(input, CURSOR_DRAGGING);
536   - }
537   - else
538   - {
539   - input_set_pointer_image(input, CURSOR_LEFT_PTR);
540   - }
541   - }
542   -}
543   -
544   -static void
545   -zoom(struct image *image, double scale)
546   -{
547   - double x = image->pointer.x;
548   - double y = image->pointer.y;
549   - cairo_matrix_t scale_matrix;
550   -
551   - if (!image->initialized)
552   - {
553   - return;
554   - }
555   -
556   - if ((get_scale(image) * scale > 20.0) ||
557   - (get_scale(image) * scale < 0.02))
558   - {
559   - return;
560   - }
561   -
562   - cairo_matrix_init_identity(&scale_matrix);
563   - cairo_matrix_translate(&scale_matrix, x, y);
564   - cairo_matrix_scale(&scale_matrix, scale, scale);
565   - cairo_matrix_translate(&scale_matrix, -x, -y);
566   -
567   - cairo_matrix_multiply(&image->matrix, &image->matrix, &scale_matrix);
568   - clamp_view(image);
569   -}
570   -
571   -static void
572   -key_handler(struct window *window, struct input *input, uint32_t time,
573   - uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
574   - void *data)
575   -{
576   - struct image *image = data;
577   - int transform;
578   -
579   - if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
580   - {
581   - return;
582   - }
583   -
584   - // printf("XKB_KEY_f[%x] XKB_KEY_t[%x]\n",XKB_KEY_f,XKB_KEY_t);
585   - // printf("sym[%x]\n",sym);
586   -
587   - switch (sym)
588   - {
589   -/*
590   - case XKB_KEY_minus:
591   - zoom(image, 0.8);
592   - window_schedule_redraw(image->window);
593   - break;
594   - case XKB_KEY_equal:
595   - case XKB_KEY_plus:
596   - zoom(image, 1.2);
597   - window_schedule_redraw(image->window);
598   - break;
599   -
600   - case XKB_KEY_1:
601   - image->matrix.xx = 1.0;
602   - image->matrix.xy = 0.0;
603   - image->matrix.yx = 0.0;
604   - image->matrix.yy = 1.0;
605   - clamp_view(image);
606   - window_schedule_redraw(image->window);
607   - break;
608   -
609   - case XKB_KEY_2:
610   - image->matrix.xx = 0.5;
611   - image->matrix.xy = 0.0;
612   - image->matrix.yx = 0.0;
613   - image->matrix.yy = 0.5;
614   - clamp_view(image);
615   - window_schedule_redraw(image->window);
616   - break;
617   - */
618   - case XKB_KEY_f:
619   - image->fullscreen ^= 1;
620   - printf("image->fullscreen[%d]\n",image->fullscreen);
621   -
622   - window_set_fullscreen(image->window, image->fullscreen);
623   - clamp_view(image);
624   - window_schedule_redraw(image->window);
625   - break;
626   -
627   -/*
628   - case XKB_KEY_t:
629   - transform = window_get_buffer_transform (image->window);
630   - printf("transform[%d]\n",transform);
631   - transform = (transform + 1) % 8;
632   - window_set_buffer_transform(image->window, transform);
633   - window_schedule_redraw(image->window);
634   - break;
635   - */
636   - case XKB_KEY_q:
637   - exit(0);
638   - break;
639   - }
640   -}
641   -
642   -static void
643   -axis_handler(struct widget *widget, struct input *input, uint32_t time,
644   - uint32_t axis, wl_fixed_t value, void *data)
645   -{
646   - struct image *image = data;
647   -
648   - if ((axis == WL_POINTER_AXIS_VERTICAL_SCROLL) &&
649   - (input_get_modifiers(input) == MOD_CONTROL_MASK))
650   - {
651   - /* set zoom level to 2% per 10 axis units */
652   - zoom(image, (1.0 - wl_fixed_to_double(value) / 500.0));
653   -
654   - window_schedule_redraw(image->window);
655   - }
656   - else if (input_get_modifiers(input) == 0)
657   - {
658   - if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
659   - {
660   - move_viewport(image, 0, wl_fixed_to_double(value));
661   - }
662   - else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
663   - {
664   - move_viewport(image, wl_fixed_to_double(value), 0);
665   - }
666   - }
667   -}
668   -
669   -static void
670   -fullscreen_handler(struct window *window, void *data)
671   -{
672   - struct image *image = data;
673   -
674   - // image->fullscreen ^= 1;
675   - window_set_fullscreen(window, image->fullscreen);
676   -}
677   -
678   -int is_pass_close_handler = 0;
679   -static void
680   -close_handler(void *data)
681   -{
682   - struct image *image = data;
683   -
684   - *image->image_counter -= 1;
685   -
686   - if (*image->image_counter == 0)
687   - {
688   - display_exit(image->display);
689   - }
690   -
691   - widget_destroy(image->widget);
692   - window_destroy(image->window);
693   -
694   - free(image);
695   -
696   - is_pass_close_handler = 1;
697   -}
698   -
699   -static char *
700   -get_screenshot(const struct buffer_size *buff_size,
701   - struct wl_list *output_list)
702   -{
703   - int output_stride, buffer_stride, i;
704   - cairo_surface_t *surface;
705   - char *data, *d, *s;
706   - struct screenshooter_output *output, *next;
707   - FILE *fp;
708   - char filepath[PATH_MAX];
709   -
710   - buffer_stride = buff_size->width * 4;
711   -
712   - // printf("buffer_stride[%d] * buff_size->height[%d] = %d\n",buffer_stride, buff_size->height, buffer_stride * buff_size->height);
713   - data = xmalloc(1024 * 4 * 768);
714   - if (!data)
715   - {
716   - return;
717   - }
718   -
719   - wl_list_for_each_safe(output, next, output_list, link)
720   - {
721   - if (output->offset_x == 0)
722   - {
723   - output_stride = 4;
724   - d = data + 1024 * 4 * 767 + 1023 * 4;
725   - s = output->data;
726   -
727   - for (i = 0; i < 1024*768; i++)
728   - {
729   - memcpy(d, s, output_stride);
730   - d -= output_stride;
731   - s += output_stride;
732   - }
733   -
734   - wl_buffer_destroy(output->buffer);
735   - int ret = munmap(output->data, 1024*4*768);
736   - // printf("munmap error[%d]\n",ret);
737   - // printf("%s\n",strerror(errno));
738   - // free(output->buffer);
739   - }
740   -
741   - wl_registry_destroy(output->output);
742   - free(output);
743   - }
744   -
745   - // fp = file_create_dated("/tmp", "raw-",
746   - // ".png", filepath, sizeof(filepath));
747   - // if (fp) {
748   - // fwrite(data, 1, 1024 * 4 * 768, fp);
749   - // fclose (fp);
750   - // }
751   -
752   - return data;
753   -}
754   -
755   -static struct image *
756   -image_create(struct display *display, const char *filename,
757   - int *image_counter, char *cap_img)
758   -{
759   - struct image *image;
760   - char *b, *copy, title[512];
761   -
762   - image = zalloc(sizeof *image);
763   - if (image == NULL)
764   - {
765   - return image;
766   - }
767   -
768   - sprintf(title,"weston_clone_app");
769   - image->filename = strdup(title);
770   -
771   - image->image = cairo_image_surface_create_for_data(cap_img, CAIRO_FORMAT_ARGB32, 1024, 768, 1024*4);
772   - double width = cairo_image_surface_get_width(image->image);
773   - double height = cairo_image_surface_get_height(image->image);
774   - printf("1 width[%f] height[%f]\n",width,height);
775   -
776   - if (!image->image)
777   - {
778   - free(image->filename);
779   - free(image);
780   -
781   - printf("image->image failed\n");
782   - return NULL;
783   - }
784   -
785   - image->window = window_create(display);
786   - image->widget = window_frame_create(image->window, image);
787   - window_set_title(image->window, title);
788   - image->display = display;
789   - image->image_counter = image_counter;
790   - *image_counter += 1;
791   - image->initialized = false;
792   -
793   - window_set_user_data(image->window, image);
794   - widget_set_redraw_handler(image->widget, redraw_handler);
795   - // widget_set_resize_handler(image->widget, resize_handler);
796   - // window_set_keyboard_focus_handler(image->window, keyboard_focus_handler);
797   - // window_set_fullscreen_handler(image->window, fullscreen_handler);
798   - window_set_close_handler(image->window, close_handler);
799   -
800   - // widget_set_enter_handler(image->widget, enter_handler);
801   - // widget_set_motion_handler(image->widget, motion_handler);
802   - // widget_set_button_handler(image->widget, button_handler);
803   - // widget_set_axis_handler(image->widget, axis_handler);
804   - window_set_key_handler(image->window, key_handler);
805   - widget_schedule_resize(image->widget, 600, 400);
806   -
807   - return image;
808   -}
809   -
810   -static void display_run_nonloop(struct display *display)
811   -{
812   - struct task *task;
813   - struct epoll_event ep[16];
814   - int i, count, ret;
815   - int idx = 0;
816   -
817   - display->running = 1;
818   - // while (1)
819   - {
820   - while (!wl_list_empty(&display->deferred_list))
821   - {
822   - task = container_of(display->deferred_list.prev,
823   - struct task, link);
824   - wl_list_remove(&task->link);
825   - task->run(task, 0);
826   - }
827   -
828   - wl_display_dispatch_pending(display->display);
829   -
830   - ret = wl_display_flush(display->display);
831   - if ((ret < 0) && (errno == EAGAIN))
832   - {
833   - ep[0].events =
834   - EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
835   - ep[0].data.ptr = &display->display_task;
836   -
837   - epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
838   - display->display_fd, &ep[0]);
839   - }
840   - else if (ret < 0)
841   - {
842   - // break;
843   - return;
844   - }
845   -
846   - count = epoll_wait(display->epoll_fd,
847   - ep, ARRAY_LENGTH(ep), -1);
848   - for (i = 0; i < count; i++)
849   - {
850   - task = ep[i].data.ptr;
851   - task->run(task, ep[i].events);
852   - }
853   - }
854   -}
855   -
856   -static int
857   -screenshot_set_buffer_size(struct buffer_size *buff_size, struct wl_list *output_list)
858   -{
859   - struct screenshooter_output *output;
860   - buff_size->min_x = buff_size->min_y = INT_MAX;
861   - buff_size->max_x = buff_size->max_y = INT_MIN;
862   - int position = 0;
863   -
864   - wl_list_for_each_reverse(output, output_list, link)
865   - {
866   - output->offset_x = position;
867   - position += output->width;
868   - }
869   -
870   - wl_list_for_each(output, output_list, link)
871   - {
872   - buff_size->min_x = MIN(buff_size->min_x, output->offset_x);
873   - buff_size->min_y = MIN(buff_size->min_y, output->offset_y);
874   - buff_size->max_x =
875   - MAX(buff_size->max_x, output->offset_x + output->width);
876   - buff_size->max_y =
877   - MAX(buff_size->max_y, output->offset_y + output->height);
878   - }
879   -
880   - if ((buff_size->max_x <= buff_size->min_x) ||
881   - (buff_size->max_y <= buff_size->min_y))
882   - {
883   - return -1;
884   - }
885   -
886   - buff_size->width = buff_size->max_x - buff_size->min_x;
887   - buff_size->height = buff_size->max_y - buff_size->min_y;
888   -
889   - return 0;
890   -}
891   -
892   -char *get_weston_screen_image()
893   -{
894   - struct wl_display *display_cap; // screenshooter variable
895   - struct wl_registry *registry;
896   - struct screenshooter_output *output;
897   - struct buffer_size buff_size = {};
898   - struct screenshooter_data sh_data = {};
899   - char *cap_img = NULL;
900   -
901   - // start of screenshoot
902   - display_cap = wl_display_connect(NULL);
903   - if (display_cap == NULL)
904   - {
905   - fprintf(stderr, "failed to create display: %s\n",
906   - strerror(errno));
907   - return -1;
908   - }
909   -
910   - wl_list_init(&sh_data.output_list);
911   - registry = wl_display_get_registry(display_cap);
912   - wl_registry_add_listener(registry, &registry_listener, &sh_data);
913   - wl_display_dispatch(display_cap);
914   - // printf("0.1 sh_data.shm[%p]\n",sh_data.shm);
915   - wl_display_roundtrip(display_cap);
916   - if (sh_data.screenshooter == NULL)
917   - {
918   - fprintf(stderr, "display doesn't support screenshooter\n");
919   - return -1;
920   - }
921   - weston_screenshooter_add_listener(sh_data.screenshooter,
922   - &screenshooter_listener,
923   - &sh_data);
924   - if (screenshot_set_buffer_size(&buff_size, &sh_data.output_list))
925   - {
926   - printf("screenshot_set_buffer_size fail\n");
927   - // continue;
928   - return -1;
929   - }
930   -
931   - int idx = 0;
932   - wl_list_for_each(output, &sh_data.output_list, link)
933   - {
934   - if ((output->offset_x == 0) &&
935   - ((output->width == 1024) && (output->height == 768)))
936   - {
937   - // printf("output->offset_x[%d]\n",output->offset_x);
938   - output->buffer =
939   - screenshot_create_shm_buffer(output->width,
940   - output->height,
941   - &output->data,
942   - sh_data.shm);
943   - if (output->buffer == NULL)
944   - {
945   - continue;
946   - }
947   -
948   - weston_screenshooter_shoot(sh_data.screenshooter,
949   - output->output,
950   - output->buffer);
951   -
952   - sh_data.buffer_copy_done = 0;
953   - wl_display_roundtrip(display_cap);
954   - usleep(35000);
955   -
956   - while (!sh_data.buffer_copy_done)
957   - {
958   - wl_display_roundtrip(display_cap);
959   - usleep(1000);
960   - }
961   - }
962   - }
963   - // end of screenshoot
964   -
965   - if (buff_size.height == 768)
966   - {
967   - cap_img = get_screenshot(&buff_size, &sh_data.output_list);
968   - }
969   - else
970   - {
971   - struct screenshooter_output *output, *next;
972   - wl_list_for_each_safe(output, next, &sh_data.output_list, link)
973   - {
974   - int ret = munmap(output->data, 1024*4*768);
975   - // printf("munmap error[%d]\n",ret);
976   - // printf("%s\n",strerror(errno));
977   -
978   - wl_registry_destroy(output->output);
979   - wl_list_remove(&output->link);
980   - wl_buffer_destroy(output->buffer);
981   - // free(output->buffer);
982   - free(output);
983   - }
984   - }
985   -
986   - wl_registry_destroy(sh_data.shm);
987   - wl_registry_destroy(sh_data.screenshooter);
988   -
989   - wl_registry_destroy(registry);
990   - wl_display_disconnect(display_cap);
991   -
992   - return cap_img;
993   -}
994   -
995   -int main(int argc, char *argv[])
996   -{
997   - struct display *d; // image.c variable
998   - int i;
999   - int image_counter = 0;
1000   - char *cap_img = NULL;
1001   - struct timespec start_time, end_time;
1002   -
1003   - d = display_create(&argc, argv);
1004   - cap_img = get_weston_screen_image();
1005   - pimage = image_create(d, argv[i], &image_counter,cap_img);
1006   -
1007   - // full screen with 1x zoom scale
1008   - window_set_fullscreen(pimage->window, pimage->fullscreen = 1);
1009   - pimage->matrix.xx = 1.0;
1010   - pimage->matrix.xy = 0.0;
1011   - pimage->matrix.yx = 0.0;
1012   - pimage->matrix.yy = 1.0;
1013   - clamp_view(pimage);
1014   - window_schedule_redraw(pimage->window);
1015   - display_run_nonloop(d);
1016   -
1017   - struct sigaction sigint;
1018   - sigint.sa_handler = handler_sigint;
1019   - sigemptyset(&sigint.sa_mask);
1020   - sigint.sa_flags = SA_RESETHAND;
1021   - sigaction(SIGINT, &sigint, NULL);
1022   -
1023   - clock_gettime(CLOCK_MONOTONIC, &end_time);
1024   - memcpy(&start_time, &end_time, sizeof(struct timespec));
1025   -
1026   - int loop = 0;
1027   - long long usec;
1028   - while (isloop)
1029   - {
1030   - // ui loop
1031   - display_run_nonloop(d); // 20 msec
1032   -
1033   - // reload image
1034   - free(cap_img);
1035   - cap_img = get_weston_screen_image(); // 80 msec
1036   - cairo_surface_destroy(pimage->image); // 70 usec
1037   - pimage->image = cairo_image_surface_create_for_data(cap_img, CAIRO_FORMAT_ARGB32,1024, 768, 1024*4);
1038   -
1039   - // ui redraw request
1040   - window_schedule_redraw(pimage->window);
1041   -
1042   - // fps calc.
1043   - clock_gettime(CLOCK_MONOTONIC, &end_time);
1044   - usec = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_nsec - start_time.tv_nsec) / 1000;
1045   - // printf("%d : %lld usec / %lld fps\n", loop++, usec, 1000000UL / usec);
1046   - memcpy(&start_time, &end_time, sizeof(struct timespec));
1047   - }
1048   -
1049   - free(cap_img);
1050   - if (!is_pass_close_handler)
1051   - {
1052   - widget_destroy(pimage->widget);
1053   - window_destroy(pimage->window);
1054   - }
1055   - cairo_surface_destroy(pimage->image);
1056   - free(pimage);
1057   -
1058   - display_destroy(d);
1059   -
1060   - return 0;
1061   -}
vncserver.c
... ... @@ -0,0 +1,1061 @@
  1 +/*
  2 + * Copyright © 2008 Kristian Høgsberg
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice (including the next
  12 + * paragraph) shall be included in all copies or substantial portions of the
  13 + * Software.
  14 + *
  15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21 + * DEALINGS IN THE SOFTWARE.
  22 + */
  23 +
  24 +#include "config.h"
  25 +
  26 +#include <stdint.h>
  27 +#include <errno.h>
  28 +#include <stdlib.h>
  29 +#include <stdio.h>
  30 +#include <stdbool.h>
  31 +#include <string.h>
  32 +#include <fcntl.h>
  33 +#include <libgen.h>
  34 +#include <unistd.h>
  35 +#include <limits.h>
  36 +#include <sys/epoll.h>
  37 +#include <sys/param.h>
  38 +#include <sys/mman.h>
  39 +#include <math.h>
  40 +#include <time.h>
  41 +#include <cairo.h>
  42 +#include <signal.h>
  43 +#include <assert.h>
  44 +#include <errno.h>
  45 +#include <linux/input.h>
  46 +#include <pixman.h>
  47 +
  48 +#include <wayland-client.h>
  49 +#include "weston-screenshooter-client-protocol.h"
  50 +#include "shared/os-compatibility.h"
  51 +#include "shared/xalloc.h"
  52 +#include "shared/file-util.h"
  53 +#include "shared/cairo-util.h"
  54 +#include "shared/helpers.h"
  55 +#include "window.h"
  56 +
  57 +/* The screenshooter is a good example of a custom object exposed by
  58 + * the compositor and serves as a test bed for implementing client
  59 + * side marshalling outside libwayland.so */
  60 +
  61 +int isloop = 1;
  62 +struct image *pimage;
  63 +
  64 +struct screenshooter_output
  65 +{
  66 + struct wl_output *output;
  67 + struct wl_buffer *buffer;
  68 + int width, height, offset_x, offset_y;
  69 + void *data;
  70 + struct wl_list link;
  71 +};
  72 +
  73 +struct buffer_size
  74 +{
  75 + int width, height;
  76 +
  77 + int min_x, min_y;
  78 + int max_x, max_y;
  79 +};
  80 +
  81 +struct screenshooter_data
  82 +{
  83 + struct wl_shm *shm;
  84 + struct wl_list output_list;
  85 +
  86 + struct weston_screenshooter *screenshooter;
  87 + int buffer_copy_done;
  88 +};
  89 +
  90 +struct image
  91 +{
  92 + struct window *window;
  93 + struct widget *widget;
  94 + struct display *display;
  95 + char *filename;
  96 + cairo_surface_t *image;
  97 + int fullscreen;
  98 + int *image_counter;
  99 + int32_t width, height;
  100 +
  101 + struct
  102 + {
  103 + double x;
  104 + double y;
  105 + } pointer;
  106 + bool button_pressed;
  107 +
  108 + bool initialized;
  109 + cairo_matrix_t matrix;
  110 +};
  111 +
  112 +struct display
  113 +{
  114 + struct wl_display *display;
  115 + struct wl_registry *registry;
  116 + struct wl_compositor *compositor;
  117 + struct wl_subcompositor *subcompositor;
  118 + struct wl_shm *shm;
  119 + struct wl_data_device_manager *data_device_manager;
  120 + struct text_cursor_position *text_cursor_position;
  121 + struct xdg_wm_base *xdg_shell;
  122 + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
  123 + struct zwp_pointer_constraints_v1 *pointer_constraints;
  124 + EGLDisplay dpy;
  125 + EGLConfig argb_config;
  126 + EGLContext argb_ctx;
  127 + cairo_device_t *argb_device;
  128 + uint32_t serial;
  129 +
  130 + int display_fd;
  131 + uint32_t display_fd_events;
  132 + struct task display_task;
  133 +
  134 + int epoll_fd;
  135 + struct wl_list deferred_list;
  136 +
  137 + int running;
  138 +
  139 + struct wl_list global_list;
  140 + struct wl_list window_list;
  141 + struct wl_list input_list;
  142 + struct wl_list output_list;
  143 +
  144 + struct theme *theme;
  145 +
  146 + struct wl_cursor_theme *cursor_theme;
  147 + struct wl_cursor **cursors;
  148 +
  149 + display_output_handler_t output_configure_handler;
  150 + display_global_handler_t global_handler;
  151 + display_global_handler_t global_handler_remove;
  152 +
  153 + void *user_data;
  154 +
  155 + struct xkb_context *xkb_context;
  156 +
  157 + /* A hack to get text extents for tooltips */
  158 + cairo_surface_t *dummy_surface;
  159 + void *dummy_surface_data;
  160 +
  161 + int data_device_manager_version;
  162 + struct wp_viewporter *viewporter;
  163 +};
  164 +
  165 +static void handler_sigint(int sig)
  166 +{
  167 + isloop = 0;
  168 +}
  169 +
  170 +static void
  171 +display_handle_geometry(void *data,
  172 + struct wl_output *wl_output,
  173 + int x,
  174 + int y,
  175 + int physical_width,
  176 + int physical_height,
  177 + int subpixel,
  178 + const char *make,
  179 + const char *model,
  180 + int transform)
  181 +{
  182 + struct screenshooter_output *output;
  183 +
  184 + output = wl_output_get_user_data(wl_output);
  185 +
  186 + if (wl_output == output->output)
  187 + {
  188 + output->offset_x = x;
  189 + output->offset_y = y;
  190 + }
  191 +}
  192 +
  193 +static void
  194 +display_handle_mode(void *data,
  195 + struct wl_output *wl_output,
  196 + uint32_t flags,
  197 + int width,
  198 + int height,
  199 + int refresh)
  200 +{
  201 + struct screenshooter_output *output;
  202 +
  203 + output = wl_output_get_user_data(wl_output);
  204 +
  205 + if ((wl_output == output->output) && (flags & WL_OUTPUT_MODE_CURRENT))
  206 + {
  207 + output->width = width;
  208 + output->height = height;
  209 + }
  210 +}
  211 +
  212 +static const struct wl_output_listener output_listener = {
  213 + display_handle_geometry,
  214 + display_handle_mode
  215 +};
  216 +
  217 +static void
  218 +screenshot_done(void *data, struct weston_screenshooter *screenshooter)
  219 +{
  220 + struct screenshooter_data *sh_data = data;
  221 + sh_data->buffer_copy_done = 1;
  222 +}
  223 +
  224 +static const struct weston_screenshooter_listener screenshooter_listener = {
  225 + screenshot_done
  226 +};
  227 +
  228 +static void
  229 +handle_global(void *data, struct wl_registry *registry,
  230 + uint32_t name, const char *interface, uint32_t version)
  231 +{
  232 + static struct screenshooter_output *output;
  233 + struct screenshooter_data *sh_data = data;
  234 +
  235 + if (strcmp(interface, "wl_output") == 0)
  236 + {
  237 + output = xmalloc(sizeof *output);
  238 + output->output = wl_registry_bind(registry, name,
  239 + &wl_output_interface, 1);
  240 + wl_list_insert(&sh_data->output_list, &output->link);
  241 + wl_output_add_listener(output->output, &output_listener, output);
  242 + }
  243 + else if (strcmp(interface, "wl_shm") == 0)
  244 + {
  245 + sh_data->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
  246 + }
  247 + else if (strcmp(interface, "weston_screenshooter") == 0)
  248 + {
  249 + sh_data->screenshooter = wl_registry_bind(registry, name,
  250 + &weston_screenshooter_interface,
  251 + 1);
  252 + }
  253 +}
  254 +
  255 +static void
  256 +handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
  257 +{
  258 + /* XXX: unimplemented */
  259 +}
  260 +
  261 +static const struct wl_registry_listener registry_listener = {
  262 + handle_global,
  263 + handle_global_remove
  264 +};
  265 +
  266 +static struct wl_buffer *
  267 +screenshot_create_shm_buffer(int width, int height, void **data_out,
  268 + struct wl_shm *shm)
  269 +{
  270 + struct wl_shm_pool *pool;
  271 + struct wl_buffer *buffer;
  272 + int fd, size, stride;
  273 + void *data;
  274 +
  275 + stride = width * 4;
  276 + size = stride * height;
  277 +
  278 + // printf("screenshot_create_shm_buffer width[%d] height[%d] stride[%d] size[%d]\n",width,height,stride,size);
  279 + fd = os_create_anonymous_file(size);
  280 + if (fd < 0)
  281 + {
  282 + fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
  283 + size, strerror(errno));
  284 + return NULL;
  285 + }
  286 +
  287 + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  288 + if (data == MAP_FAILED)
  289 + {
  290 + fprintf(stderr, "mmap failed: %s\n", strerror(errno));
  291 + close(fd);
  292 + return NULL;
  293 + }
  294 +
  295 + pool = wl_shm_create_pool(shm, fd, size);
  296 + close(fd);
  297 + buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
  298 + WL_SHM_FORMAT_XRGB8888);
  299 + wl_shm_pool_destroy(pool);
  300 +
  301 + *data_out = data;
  302 +
  303 + return buffer;
  304 +}
  305 +
  306 +
  307 +static double
  308 +get_scale(struct image *image)
  309 +{
  310 + assert(image->matrix.xy == 0.0 &&
  311 + image->matrix.yx == 0.0 &&
  312 + image->matrix.xx == image->matrix.yy);
  313 + return image->matrix.xx;
  314 +}
  315 +
  316 +static void
  317 +clamp_view(struct image *image)
  318 +{
  319 + struct rectangle allocation;
  320 + double scale = get_scale(image);
  321 + double sw, sh;
  322 + // printf("clamp scale[%f]\n",scale);
  323 + // printf("clamp image->width[%d] height[%d]\n",image->width,image->height);
  324 +
  325 + sw = image->width * scale;
  326 + sh = image->height * scale;
  327 + widget_get_allocation(image->widget, &allocation);
  328 +
  329 + // printf("clamp sw[%f] sh[%f]\n",sw,sh);
  330 + // printf("clamp allocation.width[%d] height[%d]\n"),allocation.width,allocation.height;
  331 +
  332 + if (sw < allocation.width)
  333 + {
  334 + image->matrix.x0 =
  335 + (allocation.width - image->width * scale) / 2;
  336 + }
  337 + else
  338 + {
  339 + if (image->matrix.x0 > 0.0)
  340 + {
  341 + image->matrix.x0 = 0.0;
  342 + }
  343 + if (sw + image->matrix.x0 < allocation.width)
  344 + {
  345 + image->matrix.x0 = allocation.width - sw;
  346 + }
  347 + }
  348 +
  349 + if (sh < allocation.height)
  350 + {
  351 + image->matrix.y0 =
  352 + (allocation.height - image->height * scale) / 2;
  353 + }
  354 + else
  355 + {
  356 + if (image->matrix.y0 > 0.0)
  357 + {
  358 + image->matrix.y0 = 0.0;
  359 + }
  360 + if (sh + image->matrix.y0 < allocation.height)
  361 + {
  362 + image->matrix.y0 = allocation.height - sh;
  363 + }
  364 + }
  365 +
  366 + // printf("clamp matrix x0:%f y0:%fxx:%f xy:%f yx:%f yy:%f\n",image->matrix.x0,image->matrix.y0, image->matrix.xx,image->matrix.xy,image->matrix.yx,image->matrix.yy);
  367 + // printf("x0[%f] y0[%f]\n",image->matrix.x0, image->matrix.y0);
  368 +}
  369 +
  370 +static void
  371 +redraw_handler(struct widget *widget, void *data)
  372 +{
  373 + struct image *image = data;
  374 + struct rectangle allocation;
  375 + cairo_t *cr;
  376 + cairo_surface_t *surface;
  377 + double width, height, doc_aspect, window_aspect, scale;
  378 + cairo_matrix_t matrix;
  379 + cairo_matrix_t translate;
  380 +
  381 + surface = window_get_surface(image->window);
  382 + cr = cairo_create(surface);
  383 + widget_get_allocation(image->widget, &allocation);
  384 + // printf("allocation x[%d] y[%d] width[%d] height[%d]\n", allocation.x, allocation.y, allocation.width,allocation.height);
  385 +
  386 + cairo_rectangle(cr, allocation.x, allocation.y,
  387 + allocation.width, allocation.height);
  388 + cairo_clip(cr);
  389 + cairo_push_group(cr);
  390 + cairo_translate(cr, allocation.x, allocation.y);
  391 +
  392 + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  393 + // cairo_set_source_rgba(cr, 1, 0, 1, 0.5); // magenta transparency 50%
  394 + cairo_set_source_rgba(cr, 0, 0, 0, 0);
  395 + cairo_paint(cr);
  396 +
  397 + if (!image->initialized)
  398 + {
  399 + image->initialized = true;
  400 + width = cairo_image_surface_get_width(image->image);
  401 + height = cairo_image_surface_get_height(image->image);
  402 +
  403 + doc_aspect = width / height;
  404 + window_aspect = (double) allocation.width / allocation.height;
  405 + if (doc_aspect < window_aspect)
  406 + {
  407 + scale = allocation.height / height;
  408 + }
  409 + else
  410 + {
  411 + scale = allocation.width / width;
  412 + }
  413 +
  414 + // printf("doc_aspect[%f]\n",doc_aspect);
  415 + // printf("window_aspect[%f]\n",window_aspect);
  416 + // printf("scale[%f]\n",scale);
  417 +
  418 + image->width = width;
  419 + image->height = height;
  420 + cairo_matrix_init_scale(&image->matrix, scale, scale);
  421 +
  422 + clamp_view(image);
  423 + }
  424 +
  425 + matrix = image->matrix;
  426 + cairo_matrix_init_translate(&translate, allocation.x, allocation.y);
  427 + // printf("init matrix x0:%f y0:%f xx:%f xy:%f yx:%f yy:%f\n",matrix.x0,matrix.y0,matrix.xx,matrix.xy,matrix.yx,matrix.yy);
  428 + cairo_matrix_multiply(&matrix, &matrix, &translate);
  429 + // printf("mult matrix x0:%f y0:%f xx:%f xy:%f yx:%f yy:%f\n",matrix.x0,matrix.y0,matrix.xx,matrix.xy,matrix.yx,matrix.yy);
  430 + cairo_set_matrix(cr, &matrix);
  431 +
  432 + cairo_set_source_surface(cr, image->image, 0, 0);
  433 + cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  434 + cairo_paint(cr);
  435 +
  436 + cairo_pop_group_to_source(cr);
  437 + cairo_paint(cr);
  438 + cairo_destroy(cr);
  439 +
  440 + cairo_surface_destroy(surface);
  441 +}
  442 +
  443 +static void
  444 +resize_handler(struct widget *widget,
  445 + int32_t width, int32_t height, void *data)
  446 +{
  447 + struct image *image = data;
  448 +
  449 + clamp_view(image);
  450 +}
  451 +
  452 +static void
  453 +keyboard_focus_handler(struct window *window,
  454 + struct input *device, void *data)
  455 +{
  456 + struct image *image = data;
  457 +
  458 + window_schedule_redraw(image->window);
  459 +}
  460 +
  461 +static int
  462 +enter_handler(struct widget *widget,
  463 + struct input *input,
  464 + float x, float y, void *data)
  465 +{
  466 + struct image *image = data;
  467 + struct rectangle allocation;
  468 +
  469 + widget_get_allocation(image->widget, &allocation);
  470 + x -= allocation.x;
  471 + y -= allocation.y;
  472 +
  473 + image->pointer.x = x;
  474 + image->pointer.y = y;
  475 +
  476 + return 1;
  477 +}
  478 +
  479 +static void
  480 +move_viewport(struct image *image, double dx, double dy)
  481 +{
  482 + double scale = get_scale(image);
  483 +
  484 + if (!image->initialized)
  485 + {
  486 + return;
  487 + }
  488 +
  489 + cairo_matrix_translate(&image->matrix, -dx/scale, -dy/scale);
  490 + clamp_view(image);
  491 +
  492 + window_schedule_redraw(image->window);
  493 +}
  494 +
  495 +static int
  496 +motion_handler(struct widget *widget,
  497 + struct input *input, uint32_t time,
  498 + float x, float y, void *data)
  499 +{
  500 + struct image *image = data;
  501 + struct rectangle allocation;
  502 +
  503 + widget_get_allocation(image->widget, &allocation);
  504 + x -= allocation.x;
  505 + y -= allocation.y;
  506 +
  507 + if (image->button_pressed)
  508 + {
  509 + move_viewport(image, image->pointer.x - x,
  510 + image->pointer.y - y);
  511 + }
  512 +
  513 + image->pointer.x = x;
  514 + image->pointer.y = y;
  515 +
  516 + return image->button_pressed ? CURSOR_DRAGGING : CURSOR_LEFT_PTR;
  517 +}
  518 +
  519 +static void
  520 +button_handler(struct widget *widget,
  521 + struct input *input, uint32_t time,
  522 + uint32_t button,
  523 + enum wl_pointer_button_state state,
  524 + void *data)
  525 +{
  526 + struct image *image = data;
  527 +
  528 + if (button == BTN_LEFT)
  529 + {
  530 + image->button_pressed =
  531 + state == WL_POINTER_BUTTON_STATE_PRESSED;
  532 +
  533 + if (state == WL_POINTER_BUTTON_STATE_PRESSED)
  534 + {
  535 + input_set_pointer_image(input, CURSOR_DRAGGING);
  536 + }
  537 + else
  538 + {
  539 + input_set_pointer_image(input, CURSOR_LEFT_PTR);
  540 + }
  541 + }
  542 +}
  543 +
  544 +static void
  545 +zoom(struct image *image, double scale)
  546 +{
  547 + double x = image->pointer.x;
  548 + double y = image->pointer.y;
  549 + cairo_matrix_t scale_matrix;
  550 +
  551 + if (!image->initialized)
  552 + {
  553 + return;
  554 + }
  555 +
  556 + if ((get_scale(image) * scale > 20.0) ||
  557 + (get_scale(image) * scale < 0.02))
  558 + {
  559 + return;
  560 + }
  561 +
  562 + cairo_matrix_init_identity(&scale_matrix);
  563 + cairo_matrix_translate(&scale_matrix, x, y);
  564 + cairo_matrix_scale(&scale_matrix, scale, scale);
  565 + cairo_matrix_translate(&scale_matrix, -x, -y);
  566 +
  567 + cairo_matrix_multiply(&image->matrix, &image->matrix, &scale_matrix);
  568 + clamp_view(image);
  569 +}
  570 +
  571 +static void
  572 +key_handler(struct window *window, struct input *input, uint32_t time,
  573 + uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
  574 + void *data)
  575 +{
  576 + struct image *image = data;
  577 + int transform;
  578 +
  579 + if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
  580 + {
  581 + return;
  582 + }
  583 +
  584 + // printf("XKB_KEY_f[%x] XKB_KEY_t[%x]\n",XKB_KEY_f,XKB_KEY_t);
  585 + // printf("sym[%x]\n",sym);
  586 +
  587 + switch (sym)
  588 + {
  589 +/*
  590 + case XKB_KEY_minus:
  591 + zoom(image, 0.8);
  592 + window_schedule_redraw(image->window);
  593 + break;
  594 + case XKB_KEY_equal:
  595 + case XKB_KEY_plus:
  596 + zoom(image, 1.2);
  597 + window_schedule_redraw(image->window);
  598 + break;
  599 +
  600 + case XKB_KEY_1:
  601 + image->matrix.xx = 1.0;
  602 + image->matrix.xy = 0.0;
  603 + image->matrix.yx = 0.0;
  604 + image->matrix.yy = 1.0;
  605 + clamp_view(image);
  606 + window_schedule_redraw(image->window);
  607 + break;
  608 +
  609 + case XKB_KEY_2:
  610 + image->matrix.xx = 0.5;
  611 + image->matrix.xy = 0.0;
  612 + image->matrix.yx = 0.0;
  613 + image->matrix.yy = 0.5;
  614 + clamp_view(image);
  615 + window_schedule_redraw(image->window);
  616 + break;
  617 + */
  618 + case XKB_KEY_f:
  619 + image->fullscreen ^= 1;
  620 + printf("image->fullscreen[%d]\n",image->fullscreen);
  621 +
  622 + window_set_fullscreen(image->window, image->fullscreen);
  623 + clamp_view(image);
  624 + window_schedule_redraw(image->window);
  625 + break;
  626 +
  627 +/*
  628 + case XKB_KEY_t:
  629 + transform = window_get_buffer_transform (image->window);
  630 + printf("transform[%d]\n",transform);
  631 + transform = (transform + 1) % 8;
  632 + window_set_buffer_transform(image->window, transform);
  633 + window_schedule_redraw(image->window);
  634 + break;
  635 + */
  636 + case XKB_KEY_q:
  637 + exit(0);
  638 + break;
  639 + }
  640 +}
  641 +
  642 +static void
  643 +axis_handler(struct widget *widget, struct input *input, uint32_t time,
  644 + uint32_t axis, wl_fixed_t value, void *data)
  645 +{
  646 + struct image *image = data;
  647 +
  648 + if ((axis == WL_POINTER_AXIS_VERTICAL_SCROLL) &&
  649 + (input_get_modifiers(input) == MOD_CONTROL_MASK))
  650 + {
  651 + /* set zoom level to 2% per 10 axis units */
  652 + zoom(image, (1.0 - wl_fixed_to_double(value) / 500.0));
  653 +
  654 + window_schedule_redraw(image->window);
  655 + }
  656 + else if (input_get_modifiers(input) == 0)
  657 + {
  658 + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
  659 + {
  660 + move_viewport(image, 0, wl_fixed_to_double(value));
  661 + }
  662 + else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
  663 + {
  664 + move_viewport(image, wl_fixed_to_double(value), 0);
  665 + }
  666 + }
  667 +}
  668 +
  669 +static void
  670 +fullscreen_handler(struct window *window, void *data)
  671 +{
  672 + struct image *image = data;
  673 +
  674 + // image->fullscreen ^= 1;
  675 + window_set_fullscreen(window, image->fullscreen);
  676 +}
  677 +
  678 +int is_pass_close_handler = 0;
  679 +static void
  680 +close_handler(void *data)
  681 +{
  682 + struct image *image = data;
  683 +
  684 + *image->image_counter -= 1;
  685 +
  686 + if (*image->image_counter == 0)
  687 + {
  688 + display_exit(image->display);
  689 + }
  690 +
  691 + widget_destroy(image->widget);
  692 + window_destroy(image->window);
  693 +
  694 + free(image);
  695 +
  696 + is_pass_close_handler = 1;
  697 +}
  698 +
  699 +static char *
  700 +get_screenshot(const struct buffer_size *buff_size,
  701 + struct wl_list *output_list)
  702 +{
  703 + int output_stride, buffer_stride, i;
  704 + cairo_surface_t *surface;
  705 + char *data, *d, *s;
  706 + struct screenshooter_output *output, *next;
  707 + FILE *fp;
  708 + char filepath[PATH_MAX];
  709 +
  710 + buffer_stride = buff_size->width * 4;
  711 +
  712 + // printf("buffer_stride[%d] * buff_size->height[%d] = %d\n",buffer_stride, buff_size->height, buffer_stride * buff_size->height);
  713 + data = xmalloc(1024 * 4 * 768);
  714 + if (!data)
  715 + {
  716 + return;
  717 + }
  718 +
  719 + wl_list_for_each_safe(output, next, output_list, link)
  720 + {
  721 + if (output->offset_x == 0)
  722 + {
  723 + output_stride = 4;
  724 + d = data + 1024 * 4 * 767 + 1023 * 4;
  725 + s = output->data;
  726 +
  727 + for (i = 0; i < 1024*768; i++)
  728 + {
  729 + memcpy(d, s, output_stride);
  730 + d -= output_stride;
  731 + s += output_stride;
  732 + }
  733 +
  734 + wl_buffer_destroy(output->buffer);
  735 + int ret = munmap(output->data, 1024*4*768);
  736 + // printf("munmap error[%d]\n",ret);
  737 + // printf("%s\n",strerror(errno));
  738 + // free(output->buffer);
  739 + }
  740 +
  741 + wl_registry_destroy(output->output);
  742 + free(output);
  743 + }
  744 +
  745 + // fp = file_create_dated("/tmp", "raw-",
  746 + // ".png", filepath, sizeof(filepath));
  747 + // if (fp) {
  748 + // fwrite(data, 1, 1024 * 4 * 768, fp);
  749 + // fclose (fp);
  750 + // }
  751 +
  752 + return data;
  753 +}
  754 +
  755 +static struct image *
  756 +image_create(struct display *display, const char *filename,
  757 + int *image_counter, char *cap_img)
  758 +{
  759 + struct image *image;
  760 + char *b, *copy, title[512];
  761 +
  762 + image = zalloc(sizeof *image);
  763 + if (image == NULL)
  764 + {
  765 + return image;
  766 + }
  767 +
  768 + sprintf(title,"weston_clone_app");
  769 + image->filename = strdup(title);
  770 +
  771 + image->image = cairo_image_surface_create_for_data(cap_img, CAIRO_FORMAT_ARGB32, 1024, 768, 1024*4);
  772 + double width = cairo_image_surface_get_width(image->image);
  773 + double height = cairo_image_surface_get_height(image->image);
  774 + printf("1 width[%f] height[%f]\n",width,height);
  775 +
  776 + if (!image->image)
  777 + {
  778 + free(image->filename);
  779 + free(image);
  780 +
  781 + printf("image->image failed\n");
  782 + return NULL;
  783 + }
  784 +
  785 + image->window = window_create(display);
  786 + image->widget = window_frame_create(image->window, image);
  787 + window_set_title(image->window, title);
  788 + image->display = display;
  789 + image->image_counter = image_counter;
  790 + *image_counter += 1;
  791 + image->initialized = false;
  792 +
  793 + window_set_user_data(image->window, image);
  794 + widget_set_redraw_handler(image->widget, redraw_handler);
  795 + // widget_set_resize_handler(image->widget, resize_handler);
  796 + // window_set_keyboard_focus_handler(image->window, keyboard_focus_handler);
  797 + // window_set_fullscreen_handler(image->window, fullscreen_handler);
  798 + window_set_close_handler(image->window, close_handler);
  799 +
  800 + // widget_set_enter_handler(image->widget, enter_handler);
  801 + // widget_set_motion_handler(image->widget, motion_handler);
  802 + // widget_set_button_handler(image->widget, button_handler);
  803 + // widget_set_axis_handler(image->widget, axis_handler);
  804 + window_set_key_handler(image->window, key_handler);
  805 + widget_schedule_resize(image->widget, 600, 400);
  806 +
  807 + return image;
  808 +}
  809 +
  810 +static void display_run_nonloop(struct display *display)
  811 +{
  812 + struct task *task;
  813 + struct epoll_event ep[16];
  814 + int i, count, ret;
  815 + int idx = 0;
  816 +
  817 + display->running = 1;
  818 + // while (1)
  819 + {
  820 + while (!wl_list_empty(&display->deferred_list))
  821 + {
  822 + task = container_of(display->deferred_list.prev,
  823 + struct task, link);
  824 + wl_list_remove(&task->link);
  825 + task->run(task, 0);
  826 + }
  827 +
  828 + wl_display_dispatch_pending(display->display);
  829 +
  830 + ret = wl_display_flush(display->display);
  831 + if ((ret < 0) && (errno == EAGAIN))
  832 + {
  833 + ep[0].events =
  834 + EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
  835 + ep[0].data.ptr = &display->display_task;
  836 +
  837 + epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD,
  838 + display->display_fd, &ep[0]);
  839 + }
  840 + else if (ret < 0)
  841 + {
  842 + // break;
  843 + return;
  844 + }
  845 +
  846 + count = epoll_wait(display->epoll_fd,
  847 + ep, ARRAY_LENGTH(ep), -1);
  848 + for (i = 0; i < count; i++)
  849 + {
  850 + task = ep[i].data.ptr;
  851 + task->run(task, ep[i].events);
  852 + }
  853 + }
  854 +}
  855 +
  856 +static int
  857 +screenshot_set_buffer_size(struct buffer_size *buff_size, struct wl_list *output_list)
  858 +{
  859 + struct screenshooter_output *output;
  860 + buff_size->min_x = buff_size->min_y = INT_MAX;
  861 + buff_size->max_x = buff_size->max_y = INT_MIN;
  862 + int position = 0;
  863 +
  864 + wl_list_for_each_reverse(output, output_list, link)
  865 + {
  866 + output->offset_x = position;
  867 + position += output->width;
  868 + }
  869 +
  870 + wl_list_for_each(output, output_list, link)
  871 + {
  872 + buff_size->min_x = MIN(buff_size->min_x, output->offset_x);
  873 + buff_size->min_y = MIN(buff_size->min_y, output->offset_y);
  874 + buff_size->max_x =
  875 + MAX(buff_size->max_x, output->offset_x + output->width);
  876 + buff_size->max_y =
  877 + MAX(buff_size->max_y, output->offset_y + output->height);
  878 + }
  879 +
  880 + if ((buff_size->max_x <= buff_size->min_x) ||
  881 + (buff_size->max_y <= buff_size->min_y))
  882 + {
  883 + return -1;
  884 + }
  885 +
  886 + buff_size->width = buff_size->max_x - buff_size->min_x;
  887 + buff_size->height = buff_size->max_y - buff_size->min_y;
  888 +
  889 + return 0;
  890 +}
  891 +
  892 +char *get_weston_screen_image()
  893 +{
  894 + struct wl_display *display_cap; // screenshooter variable
  895 + struct wl_registry *registry;
  896 + struct screenshooter_output *output;
  897 + struct buffer_size buff_size = {};
  898 + struct screenshooter_data sh_data = {};
  899 + char *cap_img = NULL;
  900 +
  901 + // start of screenshoot
  902 + display_cap = wl_display_connect(NULL);
  903 + if (display_cap == NULL)
  904 + {
  905 + fprintf(stderr, "failed to create display: %s\n",
  906 + strerror(errno));
  907 + return -1;
  908 + }
  909 +
  910 + wl_list_init(&sh_data.output_list);
  911 + registry = wl_display_get_registry(display_cap);
  912 + wl_registry_add_listener(registry, &registry_listener, &sh_data);
  913 + wl_display_dispatch(display_cap);
  914 + // printf("0.1 sh_data.shm[%p]\n",sh_data.shm);
  915 + wl_display_roundtrip(display_cap);
  916 + if (sh_data.screenshooter == NULL)
  917 + {
  918 + fprintf(stderr, "display doesn't support screenshooter\n");
  919 + return -1;
  920 + }
  921 + weston_screenshooter_add_listener(sh_data.screenshooter,
  922 + &screenshooter_listener,
  923 + &sh_data);
  924 + if (screenshot_set_buffer_size(&buff_size, &sh_data.output_list))
  925 + {
  926 + printf("screenshot_set_buffer_size fail\n");
  927 + // continue;
  928 + return -1;
  929 + }
  930 +
  931 + int idx = 0;
  932 + wl_list_for_each(output, &sh_data.output_list, link)
  933 + {
  934 + if ((output->offset_x == 0) &&
  935 + ((output->width == 1024) && (output->height == 768)))
  936 + {
  937 + // printf("output->offset_x[%d]\n",output->offset_x);
  938 + output->buffer =
  939 + screenshot_create_shm_buffer(output->width,
  940 + output->height,
  941 + &output->data,
  942 + sh_data.shm);
  943 + if (output->buffer == NULL)
  944 + {
  945 + continue;
  946 + }
  947 +
  948 + weston_screenshooter_shoot(sh_data.screenshooter,
  949 + output->output,
  950 + output->buffer);
  951 +
  952 + sh_data.buffer_copy_done = 0;
  953 + wl_display_roundtrip(display_cap);
  954 + usleep(35000);
  955 +
  956 + while (!sh_data.buffer_copy_done)
  957 + {
  958 + wl_display_roundtrip(display_cap);
  959 + usleep(1000);
  960 + }
  961 + }
  962 + }
  963 + // end of screenshoot
  964 +
  965 + if (buff_size.height == 768)
  966 + {
  967 + cap_img = get_screenshot(&buff_size, &sh_data.output_list);
  968 + }
  969 + else
  970 + {
  971 + struct screenshooter_output *output, *next;
  972 + wl_list_for_each_safe(output, next, &sh_data.output_list, link)
  973 + {
  974 + int ret = munmap(output->data, 1024*4*768);
  975 + // printf("munmap error[%d]\n",ret);
  976 + // printf("%s\n",strerror(errno));
  977 +
  978 + wl_registry_destroy(output->output);
  979 + wl_list_remove(&output->link);
  980 + wl_buffer_destroy(output->buffer);
  981 + // free(output->buffer);
  982 + free(output);
  983 + }
  984 + }
  985 +
  986 + wl_registry_destroy(sh_data.shm);
  987 + wl_registry_destroy(sh_data.screenshooter);
  988 +
  989 + wl_registry_destroy(registry);
  990 + wl_display_disconnect(display_cap);
  991 +
  992 + return cap_img;
  993 +}
  994 +
  995 +int main(int argc, char *argv[])
  996 +{
  997 + struct display *d; // image.c variable
  998 + int i;
  999 + int image_counter = 0;
  1000 + char *cap_img = NULL;
  1001 + struct timespec start_time, end_time;
  1002 +
  1003 + d = display_create(&argc, argv);
  1004 + cap_img = get_weston_screen_image();
  1005 + pimage = image_create(d, argv[i], &image_counter,cap_img);
  1006 +
  1007 + // full screen with 1x zoom scale
  1008 + window_set_fullscreen(pimage->window, pimage->fullscreen = 1);
  1009 + pimage->matrix.xx = 1.0;
  1010 + pimage->matrix.xy = 0.0;
  1011 + pimage->matrix.yx = 0.0;
  1012 + pimage->matrix.yy = 1.0;
  1013 + clamp_view(pimage);
  1014 + window_schedule_redraw(pimage->window);
  1015 + display_run_nonloop(d);
  1016 +
  1017 + struct sigaction sigint;
  1018 + sigint.sa_handler = handler_sigint;
  1019 + sigemptyset(&sigint.sa_mask);
  1020 + sigint.sa_flags = SA_RESETHAND;
  1021 + sigaction(SIGINT, &sigint, NULL);
  1022 +
  1023 + clock_gettime(CLOCK_MONOTONIC, &end_time);
  1024 + memcpy(&start_time, &end_time, sizeof(struct timespec));
  1025 +
  1026 + int loop = 0;
  1027 + long long usec;
  1028 + while (isloop)
  1029 + {
  1030 + // ui loop
  1031 + display_run_nonloop(d); // 20 msec
  1032 +
  1033 + // reload image
  1034 + free(cap_img);
  1035 + cap_img = get_weston_screen_image(); // 80 msec
  1036 + cairo_surface_destroy(pimage->image); // 70 usec
  1037 + pimage->image = cairo_image_surface_create_for_data(cap_img, CAIRO_FORMAT_ARGB32,1024, 768, 1024*4);
  1038 +
  1039 + // ui redraw request
  1040 + window_schedule_redraw(pimage->window);
  1041 +
  1042 + // fps calc.
  1043 + clock_gettime(CLOCK_MONOTONIC, &end_time);
  1044 + usec = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_nsec - start_time.tv_nsec) / 1000;
  1045 + // printf("%d : %lld usec / %lld fps\n", loop++, usec, 1000000UL / usec);
  1046 + memcpy(&start_time, &end_time, sizeof(struct timespec));
  1047 + }
  1048 +
  1049 + free(cap_img);
  1050 + if (!is_pass_close_handler)
  1051 + {
  1052 + widget_destroy(pimage->widget);
  1053 + window_destroy(pimage->window);
  1054 + }
  1055 + cairo_surface_destroy(pimage->image);
  1056 + free(pimage);
  1057 +
  1058 + display_destroy(d);
  1059 +
  1060 + return 0;
  1061 +}
... ...