Commit 82cb2aeb0424e7f6928c47a466c36d447b860d99
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, ®istry_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, ®istry_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 | +} | ... | ... |