1*4882a593SmuzhiyunFrom 99e73c78fe530b89b110f0369458089591d192a6 Mon Sep 17 00:00:00 2001 2*4882a593SmuzhiyunFrom: Stefan Agner <stefan@agner.ch> 3*4882a593SmuzhiyunDate: Sun, 22 Sep 2019 19:40:04 +0200 4*4882a593SmuzhiyunSubject: [PATCH 83/93] backend-vnc: add VNC support using Neat VNC library 5*4882a593Smuzhiyun 6*4882a593SmuzhiyunThis adds basic VNC protocol support using the Neat VNC library 7*4882a593Smuzhiyun(https://github.com/any1/neatvnc). Neat VNC depends on the AML main 8*4882a593Smuzhiyunloop library. The backend makes use of AML's integrated epoll backend 9*4882a593Smuzhiyunand connects AML via file descriptor with the Wayland event loop. 10*4882a593Smuzhiyun 11*4882a593SmuzhiyunThis implementation does not support authentication and hardcodes the 12*4882a593Smuzhiyunpixel format currently. 13*4882a593Smuzhiyun 14*4882a593SmuzhiyunCo-authored-by: Philipp Zabel <p.zabel@pengutronix.de> 15*4882a593SmuzhiyunCo-authored-by: Rouven Czerwinski <r.czerwinski@pengutronix.de> 16*4882a593SmuzhiyunSigned-off-by: Stefan Agner <stefan@agner.ch> 17*4882a593Smuzhiyun[r.czerwinski@pengutronix.de: 18*4882a593Smuzhiyun - use new (as of 0.5.0) Neat VNC buffer API, with a buffer pool] 19*4882a593SmuzhiyunSigned-off-by: Rouven Czerwinski <r.czerwinski@pengutronix.de> 20*4882a593Smuzhiyun[p.zabel@pengutronix.de: 21*4882a593Smuzhiyun - transform repaint damage to output coordinates 22*4882a593Smuzhiyun - transform pointer coordinates into global space 23*4882a593Smuzhiyun - check that outputs and heads are in fact ours, see aab722bb1785..060ef82d9360 24*4882a593Smuzhiyun - track damage across multiple frame buffers 25*4882a593Smuzhiyun - choose pixel format by drm_fourcc, see 8b6c3fe0ad4b 26*4882a593Smuzhiyun - enable ctrl and alt modifiers 27*4882a593Smuzhiyun - fix frame timing to achieve a constant repaint rate 28*4882a593Smuzhiyun - pass initial size explicitly, see f4559b076008 29*4882a593Smuzhiyun - use resize_output with pixman-renderer, see 55d08f9634e8..84b5d0eb4bee 30*4882a593Smuzhiyun - allow configuring the refresh rate] 31*4882a593SmuzhiyunSigned-off-by: Philipp Zabel <p.zabel@pengutronix.de> 32*4882a593Smuzhiyun(cherry picked from commit 12f766531002d0086c8cd2ea62a1605db934304a) 33*4882a593SmuzhiyunSigned-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 34*4882a593Smuzhiyun--- 35*4882a593Smuzhiyun compositor/main.c | 99 +++ 36*4882a593Smuzhiyun include/libweston/backend-vnc.h | 71 ++ 37*4882a593Smuzhiyun include/libweston/libweston.h | 1 + 38*4882a593Smuzhiyun include/libweston/meson.build | 1 + 39*4882a593Smuzhiyun libweston/backend-vnc/meson.build | 32 + 40*4882a593Smuzhiyun libweston/backend-vnc/vnc.c | 1032 +++++++++++++++++++++++++++++ 41*4882a593Smuzhiyun libweston/compositor.c | 1 + 42*4882a593Smuzhiyun libweston/meson.build | 1 + 43*4882a593Smuzhiyun meson_options.txt | 6 + 44*4882a593Smuzhiyun 9 files changed, 1244 insertions(+) 45*4882a593Smuzhiyun create mode 100644 include/libweston/backend-vnc.h 46*4882a593Smuzhiyun create mode 100644 libweston/backend-vnc/meson.build 47*4882a593Smuzhiyun create mode 100644 libweston/backend-vnc/vnc.c 48*4882a593Smuzhiyun 49*4882a593Smuzhiyundiff --git a/compositor/main.c b/compositor/main.c 50*4882a593Smuzhiyunindex a9ad103..aee3f24 100644 51*4882a593Smuzhiyun--- a/compositor/main.c 52*4882a593Smuzhiyun+++ b/compositor/main.c 53*4882a593Smuzhiyun@@ -61,6 +61,7 @@ 54*4882a593Smuzhiyun #include <libweston/backend-drm.h> 55*4882a593Smuzhiyun #include <libweston/backend-headless.h> 56*4882a593Smuzhiyun #include <libweston/backend-rdp.h> 57*4882a593Smuzhiyun+#include <libweston/backend-vnc.h> 58*4882a593Smuzhiyun #include <libweston/backend-x11.h> 59*4882a593Smuzhiyun #include <libweston/backend-wayland.h> 60*4882a593Smuzhiyun #include <libweston/windowed-output-api.h> 61*4882a593Smuzhiyun@@ -653,6 +654,9 @@ usage(int error_code) 62*4882a593Smuzhiyun #if defined(BUILD_RDP_COMPOSITOR) 63*4882a593Smuzhiyun "\t\t\t\trdp-backend.so\n" 64*4882a593Smuzhiyun #endif 65*4882a593Smuzhiyun+#if defined(BUILD_VNC_COMPOSITOR) 66*4882a593Smuzhiyun+ "\t\t\t\tvnc-backend.so\n" 67*4882a593Smuzhiyun+#endif 68*4882a593Smuzhiyun #if defined(BUILD_WAYLAND_COMPOSITOR) 69*4882a593Smuzhiyun "\t\t\t\twayland-backend.so\n" 70*4882a593Smuzhiyun #endif 71*4882a593Smuzhiyun@@ -720,6 +724,15 @@ usage(int error_code) 72*4882a593Smuzhiyun "\n"); 73*4882a593Smuzhiyun #endif 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun+#if defined(BUILD_VNC_COMPOSITOR) 76*4882a593Smuzhiyun+ fprintf(out, 77*4882a593Smuzhiyun+ "Options for vnc-backend.so:\n\n" 78*4882a593Smuzhiyun+ " --width=WIDTH\t\tWidth of desktop\n" 79*4882a593Smuzhiyun+ " --height=HEIGHT\tHeight of desktop\n" 80*4882a593Smuzhiyun+ " --port=PORT\t\tThe port to listen on\n" 81*4882a593Smuzhiyun+ "\n"); 82*4882a593Smuzhiyun+#endif 83*4882a593Smuzhiyun+ 84*4882a593Smuzhiyun #if defined(BUILD_WAYLAND_COMPOSITOR) 85*4882a593Smuzhiyun fprintf(out, 86*4882a593Smuzhiyun "Options for wayland-backend.so:\n\n" 87*4882a593Smuzhiyun@@ -3177,6 +3190,90 @@ load_rdp_backend(struct weston_compositor *c, 88*4882a593Smuzhiyun return ret; 89*4882a593Smuzhiyun } 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun+static int 92*4882a593Smuzhiyun+vnc_backend_output_configure(struct weston_output *output) 93*4882a593Smuzhiyun+{ 94*4882a593Smuzhiyun+ struct wet_compositor *compositor = to_wet_compositor(output->compositor); 95*4882a593Smuzhiyun+ struct wet_output_config *parsed_options = compositor->parsed_options; 96*4882a593Smuzhiyun+ const struct weston_vnc_output_api *api = weston_vnc_output_get_api(output->compositor); 97*4882a593Smuzhiyun+ int width = 640; 98*4882a593Smuzhiyun+ int height = 480; 99*4882a593Smuzhiyun+ 100*4882a593Smuzhiyun+ assert(parsed_options); 101*4882a593Smuzhiyun+ 102*4882a593Smuzhiyun+ if (!api) { 103*4882a593Smuzhiyun+ weston_log("Cannot use weston_vnc_output_api.\n"); 104*4882a593Smuzhiyun+ return -1; 105*4882a593Smuzhiyun+ } 106*4882a593Smuzhiyun+ 107*4882a593Smuzhiyun+ if (parsed_options->width) 108*4882a593Smuzhiyun+ width = parsed_options->width; 109*4882a593Smuzhiyun+ 110*4882a593Smuzhiyun+ if (parsed_options->height) 111*4882a593Smuzhiyun+ height = parsed_options->height; 112*4882a593Smuzhiyun+ 113*4882a593Smuzhiyun+ weston_output_set_scale(output, 1); 114*4882a593Smuzhiyun+ weston_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); 115*4882a593Smuzhiyun+ 116*4882a593Smuzhiyun+ if (api->output_set_size(output, width, height) < 0) { 117*4882a593Smuzhiyun+ weston_log("Cannot configure output \"%s\" using weston_vnc_output_api.\n", 118*4882a593Smuzhiyun+ output->name); 119*4882a593Smuzhiyun+ return -1; 120*4882a593Smuzhiyun+ } 121*4882a593Smuzhiyun+ weston_log("vnc_backend_output_configure.. Done\n"); 122*4882a593Smuzhiyun+ 123*4882a593Smuzhiyun+ return 0; 124*4882a593Smuzhiyun+} 125*4882a593Smuzhiyun+ 126*4882a593Smuzhiyun+ 127*4882a593Smuzhiyun+static void 128*4882a593Smuzhiyun+weston_vnc_backend_config_init(struct weston_vnc_backend_config *config) 129*4882a593Smuzhiyun+{ 130*4882a593Smuzhiyun+ config->base.struct_version = WESTON_VNC_BACKEND_CONFIG_VERSION; 131*4882a593Smuzhiyun+ config->base.struct_size = sizeof(struct weston_vnc_backend_config); 132*4882a593Smuzhiyun+ 133*4882a593Smuzhiyun+ config->bind_address = NULL; 134*4882a593Smuzhiyun+ config->port = 5900; 135*4882a593Smuzhiyun+ config->refresh_rate = VNC_DEFAULT_FREQ; 136*4882a593Smuzhiyun+} 137*4882a593Smuzhiyun+ 138*4882a593Smuzhiyun+static int 139*4882a593Smuzhiyun+load_vnc_backend(struct weston_compositor *c, 140*4882a593Smuzhiyun+ int *argc, char *argv[], struct weston_config *wc) 141*4882a593Smuzhiyun+{ 142*4882a593Smuzhiyun+ struct weston_vnc_backend_config config = {{ 0, }}; 143*4882a593Smuzhiyun+ struct weston_config_section *section; 144*4882a593Smuzhiyun+ int ret = 0; 145*4882a593Smuzhiyun+ 146*4882a593Smuzhiyun+ struct wet_output_config *parsed_options = wet_init_parsed_options(c); 147*4882a593Smuzhiyun+ if (!parsed_options) 148*4882a593Smuzhiyun+ return -1; 149*4882a593Smuzhiyun+ 150*4882a593Smuzhiyun+ weston_vnc_backend_config_init(&config); 151*4882a593Smuzhiyun+ 152*4882a593Smuzhiyun+ const struct weston_option vnc_options[] = { 153*4882a593Smuzhiyun+ { WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width }, 154*4882a593Smuzhiyun+ { WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height }, 155*4882a593Smuzhiyun+ { WESTON_OPTION_STRING, "address", 0, &config.bind_address }, 156*4882a593Smuzhiyun+ { WESTON_OPTION_INTEGER, "port", 0, &config.port }, 157*4882a593Smuzhiyun+ }; 158*4882a593Smuzhiyun+ 159*4882a593Smuzhiyun+ parse_options(vnc_options, ARRAY_LENGTH(vnc_options), argc, argv); 160*4882a593Smuzhiyun+ 161*4882a593Smuzhiyun+ wet_set_simple_head_configurator(c, vnc_backend_output_configure); 162*4882a593Smuzhiyun+ section = weston_config_get_section(wc, "vnc", NULL, NULL); 163*4882a593Smuzhiyun+ weston_config_section_get_int(section, "refresh-rate", 164*4882a593Smuzhiyun+ &config.refresh_rate, 165*4882a593Smuzhiyun+ VNC_DEFAULT_FREQ); 166*4882a593Smuzhiyun+ 167*4882a593Smuzhiyun+ ret = weston_compositor_load_backend(c, WESTON_BACKEND_VNC, 168*4882a593Smuzhiyun+ &config.base); 169*4882a593Smuzhiyun+ 170*4882a593Smuzhiyun+ free(config.bind_address); 171*4882a593Smuzhiyun+ 172*4882a593Smuzhiyun+ return ret; 173*4882a593Smuzhiyun+} 174*4882a593Smuzhiyun+ 175*4882a593Smuzhiyun static int 176*4882a593Smuzhiyun x11_backend_output_configure(struct weston_output *output) 177*4882a593Smuzhiyun { 178*4882a593Smuzhiyun@@ -3422,6 +3519,8 @@ load_backend(struct weston_compositor *compositor, const char *backend, 179*4882a593Smuzhiyun return load_headless_backend(compositor, argc, argv, config); 180*4882a593Smuzhiyun else if (strstr(backend, "rdp-backend.so")) 181*4882a593Smuzhiyun return load_rdp_backend(compositor, argc, argv, config); 182*4882a593Smuzhiyun+ else if (strstr(backend, "vnc-backend.so")) 183*4882a593Smuzhiyun+ return load_vnc_backend(compositor, argc, argv, config); 184*4882a593Smuzhiyun else if (strstr(backend, "drm-backend.so")) 185*4882a593Smuzhiyun return load_drm_backend(compositor, argc, argv, config); 186*4882a593Smuzhiyun else if (strstr(backend, "x11-backend.so")) 187*4882a593Smuzhiyundiff --git a/include/libweston/backend-vnc.h b/include/libweston/backend-vnc.h 188*4882a593Smuzhiyunnew file mode 100644 189*4882a593Smuzhiyunindex 0000000..0085df5 190*4882a593Smuzhiyun--- /dev/null 191*4882a593Smuzhiyun+++ b/include/libweston/backend-vnc.h 192*4882a593Smuzhiyun@@ -0,0 +1,71 @@ 193*4882a593Smuzhiyun+/* 194*4882a593Smuzhiyun+ * Copyright © 2019 Stefan Agner <stefan@agner.ch> 195*4882a593Smuzhiyun+ * 196*4882a593Smuzhiyun+ * Permission is hereby granted, free of charge, to any person obtaining 197*4882a593Smuzhiyun+ * a copy of this software and associated documentation files (the 198*4882a593Smuzhiyun+ * "Software"), to deal in the Software without restriction, including 199*4882a593Smuzhiyun+ * without limitation the rights to use, copy, modify, merge, publish, 200*4882a593Smuzhiyun+ * distribute, sublicense, and/or sell copies of the Software, and to 201*4882a593Smuzhiyun+ * permit persons to whom the Software is furnished to do so, subject to 202*4882a593Smuzhiyun+ * the following conditions: 203*4882a593Smuzhiyun+ * 204*4882a593Smuzhiyun+ * The above copyright notice and this permission notice (including the 205*4882a593Smuzhiyun+ * next paragraph) shall be included in all copies or substantial 206*4882a593Smuzhiyun+ * portions of the Software. 207*4882a593Smuzhiyun+ * 208*4882a593Smuzhiyun+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 209*4882a593Smuzhiyun+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 210*4882a593Smuzhiyun+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 211*4882a593Smuzhiyun+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 212*4882a593Smuzhiyun+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 213*4882a593Smuzhiyun+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 214*4882a593Smuzhiyun+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 215*4882a593Smuzhiyun+ * SOFTWARE. 216*4882a593Smuzhiyun+ */ 217*4882a593Smuzhiyun+ 218*4882a593Smuzhiyun+#ifndef WESTON_COMPOSITOR_VNC_H 219*4882a593Smuzhiyun+#define WESTON_COMPOSITOR_VNC_H 220*4882a593Smuzhiyun+ 221*4882a593Smuzhiyun+#ifdef __cplusplus 222*4882a593Smuzhiyun+extern "C" { 223*4882a593Smuzhiyun+#endif 224*4882a593Smuzhiyun+ 225*4882a593Smuzhiyun+#include <libweston/libweston.h> 226*4882a593Smuzhiyun+#include <libweston/plugin-registry.h> 227*4882a593Smuzhiyun+ 228*4882a593Smuzhiyun+#define WESTON_VNC_OUTPUT_API_NAME "weston_vnc_output_api_v1" 229*4882a593Smuzhiyun+#define VNC_DEFAULT_FREQ 60 230*4882a593Smuzhiyun+ 231*4882a593Smuzhiyun+struct weston_vnc_output_api { 232*4882a593Smuzhiyun+ /** Initialize a VNC output with specified width and height. 233*4882a593Smuzhiyun+ * 234*4882a593Smuzhiyun+ * Returns 0 on success, -1 on failure. 235*4882a593Smuzhiyun+ */ 236*4882a593Smuzhiyun+ int (*output_set_size)(struct weston_output *output, 237*4882a593Smuzhiyun+ int width, int height); 238*4882a593Smuzhiyun+}; 239*4882a593Smuzhiyun+ 240*4882a593Smuzhiyun+static inline const struct weston_vnc_output_api * 241*4882a593Smuzhiyun+weston_vnc_output_get_api(struct weston_compositor *compositor) 242*4882a593Smuzhiyun+{ 243*4882a593Smuzhiyun+ const void *api; 244*4882a593Smuzhiyun+ api = weston_plugin_api_get(compositor, WESTON_VNC_OUTPUT_API_NAME, 245*4882a593Smuzhiyun+ sizeof(struct weston_vnc_output_api)); 246*4882a593Smuzhiyun+ 247*4882a593Smuzhiyun+ return (const struct weston_vnc_output_api *)api; 248*4882a593Smuzhiyun+} 249*4882a593Smuzhiyun+ 250*4882a593Smuzhiyun+#define WESTON_VNC_BACKEND_CONFIG_VERSION 1 251*4882a593Smuzhiyun+ 252*4882a593Smuzhiyun+struct weston_vnc_backend_config { 253*4882a593Smuzhiyun+ struct weston_backend_config base; 254*4882a593Smuzhiyun+ char *bind_address; 255*4882a593Smuzhiyun+ int port; 256*4882a593Smuzhiyun+ int refresh_rate; 257*4882a593Smuzhiyun+}; 258*4882a593Smuzhiyun+ 259*4882a593Smuzhiyun+#ifdef __cplusplus 260*4882a593Smuzhiyun+} 261*4882a593Smuzhiyun+#endif 262*4882a593Smuzhiyun+ 263*4882a593Smuzhiyun+#endif /* WESTON_COMPOSITOR_VNC_H */ 264*4882a593Smuzhiyundiff --git a/include/libweston/libweston.h b/include/libweston/libweston.h 265*4882a593Smuzhiyunindex f6f4ecc..06a9ab9 100644 266*4882a593Smuzhiyun--- a/include/libweston/libweston.h 267*4882a593Smuzhiyun+++ b/include/libweston/libweston.h 268*4882a593Smuzhiyun@@ -2090,6 +2090,7 @@ enum weston_compositor_backend { 269*4882a593Smuzhiyun WESTON_BACKEND_DRM, 270*4882a593Smuzhiyun WESTON_BACKEND_HEADLESS, 271*4882a593Smuzhiyun WESTON_BACKEND_RDP, 272*4882a593Smuzhiyun+ WESTON_BACKEND_VNC, 273*4882a593Smuzhiyun WESTON_BACKEND_WAYLAND, 274*4882a593Smuzhiyun WESTON_BACKEND_X11, 275*4882a593Smuzhiyun }; 276*4882a593Smuzhiyundiff --git a/include/libweston/meson.build b/include/libweston/meson.build 277*4882a593Smuzhiyunindex 8ae1001..f248dc5 100644 278*4882a593Smuzhiyun--- a/include/libweston/meson.build 279*4882a593Smuzhiyun+++ b/include/libweston/meson.build 280*4882a593Smuzhiyun@@ -14,6 +14,7 @@ install_headers( 281*4882a593Smuzhiyun backend_drm_h = files('backend-drm.h') 282*4882a593Smuzhiyun backend_headless_h = files('backend-headless.h') 283*4882a593Smuzhiyun backend_rdp_h = files('backend-rdp.h') 284*4882a593Smuzhiyun+backend_vnc_h = files('backend-vnc.h') 285*4882a593Smuzhiyun backend_wayland_h = files('backend-wayland.h') 286*4882a593Smuzhiyun backend_x11_h = files('backend-x11.h') 287*4882a593Smuzhiyun 288*4882a593Smuzhiyundiff --git a/libweston/backend-vnc/meson.build b/libweston/backend-vnc/meson.build 289*4882a593Smuzhiyunnew file mode 100644 290*4882a593Smuzhiyunindex 0000000..4dfe022 291*4882a593Smuzhiyun--- /dev/null 292*4882a593Smuzhiyun+++ b/libweston/backend-vnc/meson.build 293*4882a593Smuzhiyun@@ -0,0 +1,32 @@ 294*4882a593Smuzhiyun+if not get_option('backend-vnc') 295*4882a593Smuzhiyun+ subdir_done() 296*4882a593Smuzhiyun+endif 297*4882a593Smuzhiyun+ 298*4882a593Smuzhiyun+config_h.set('BUILD_VNC_COMPOSITOR', '1') 299*4882a593Smuzhiyun+dep_neatvnc = dependency('neatvnc', version: ['>= 0.5.0', '< 0.6.0'], required: false) 300*4882a593Smuzhiyun+if not dep_neatvnc.found() 301*4882a593Smuzhiyun+ error('VNC backend requires neatvnc which was not found. Or, you can use \'-Dbackend-vnc=false\'.') 302*4882a593Smuzhiyun+endif 303*4882a593Smuzhiyun+ 304*4882a593Smuzhiyun+dep_aml = dependency('aml', version: ['>= 0.1.0', '< 0.3.0'], required: false) 305*4882a593Smuzhiyun+if not dep_aml.found() 306*4882a593Smuzhiyun+ error('VNC backend requires libaml which was not found. Or, you can use \'-Dbackend-vnc=false\'.') 307*4882a593Smuzhiyun+endif 308*4882a593Smuzhiyun+ 309*4882a593Smuzhiyun+deps_vnc = [ 310*4882a593Smuzhiyun+ dep_libweston_private, 311*4882a593Smuzhiyun+ dep_neatvnc, 312*4882a593Smuzhiyun+ dep_aml, 313*4882a593Smuzhiyun+ dep_libdrm_headers, 314*4882a593Smuzhiyun+] 315*4882a593Smuzhiyun+plugin_vnc = shared_library( 316*4882a593Smuzhiyun+ 'vnc-backend', 317*4882a593Smuzhiyun+ [ 'vnc.c' ], 318*4882a593Smuzhiyun+ include_directories: common_inc, 319*4882a593Smuzhiyun+ dependencies: deps_vnc, 320*4882a593Smuzhiyun+ name_prefix: '', 321*4882a593Smuzhiyun+ install: true, 322*4882a593Smuzhiyun+ install_dir: dir_module_libweston 323*4882a593Smuzhiyun+) 324*4882a593Smuzhiyun+env_modmap += 'vnc-backend.so=@0@;'.format(plugin_vnc.full_path()) 325*4882a593Smuzhiyun+install_headers(backend_vnc_h, subdir: dir_include_libweston_install) 326*4882a593Smuzhiyundiff --git a/libweston/backend-vnc/vnc.c b/libweston/backend-vnc/vnc.c 327*4882a593Smuzhiyunnew file mode 100644 328*4882a593Smuzhiyunindex 0000000..8cfad2a 329*4882a593Smuzhiyun--- /dev/null 330*4882a593Smuzhiyun+++ b/libweston/backend-vnc/vnc.c 331*4882a593Smuzhiyun@@ -0,0 +1,1032 @@ 332*4882a593Smuzhiyun+/* 333*4882a593Smuzhiyun+ * Copyright © 2019-2020 Stefan Agner <stefan@agner.ch> 334*4882a593Smuzhiyun+ * Copyright © 2021-2022 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> 335*4882a593Smuzhiyun+ * Copyright © 2022 Pengutronix, Rouven Czerwinski <r.czerwinski@pengutronix.de> 336*4882a593Smuzhiyun+ * based on backend-rdp: 337*4882a593Smuzhiyun+ * Copyright © 2013 Hardening <rdp.effort@gmail.com> 338*4882a593Smuzhiyun+ * 339*4882a593Smuzhiyun+ * Permission is hereby granted, free of charge, to any person obtaining 340*4882a593Smuzhiyun+ * a copy of this software and associated documentation files (the 341*4882a593Smuzhiyun+ * "Software"), to deal in the Software without restriction, including 342*4882a593Smuzhiyun+ * without limitation the rights to use, copy, modify, merge, publish, 343*4882a593Smuzhiyun+ * distribute, sublicense, and/or sell copies of the Software, and to 344*4882a593Smuzhiyun+ * permit persons to whom the Software is furnished to do so, subject to 345*4882a593Smuzhiyun+ * the following conditions: 346*4882a593Smuzhiyun+ * 347*4882a593Smuzhiyun+ * The above copyright notice and this permission notice (including the 348*4882a593Smuzhiyun+ * next paragraph) shall be included in all copies or substantial 349*4882a593Smuzhiyun+ * portions of the Software. 350*4882a593Smuzhiyun+ * 351*4882a593Smuzhiyun+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 352*4882a593Smuzhiyun+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 353*4882a593Smuzhiyun+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 354*4882a593Smuzhiyun+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 355*4882a593Smuzhiyun+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 356*4882a593Smuzhiyun+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 357*4882a593Smuzhiyun+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 358*4882a593Smuzhiyun+ * SOFTWARE. 359*4882a593Smuzhiyun+ */ 360*4882a593Smuzhiyun+ 361*4882a593Smuzhiyun+#include "config.h" 362*4882a593Smuzhiyun+ 363*4882a593Smuzhiyun+#include <assert.h> 364*4882a593Smuzhiyun+#include <stdint.h> 365*4882a593Smuzhiyun+#include <stdlib.h> 366*4882a593Smuzhiyun+#include <string.h> 367*4882a593Smuzhiyun+#include <errno.h> 368*4882a593Smuzhiyun+#include <linux/input.h> 369*4882a593Smuzhiyun+#include <netinet/in.h> 370*4882a593Smuzhiyun+#include <sys/types.h> 371*4882a593Smuzhiyun+#include <sys/socket.h> 372*4882a593Smuzhiyun+#include <unistd.h> 373*4882a593Smuzhiyun+#include <xkbcommon/xkbcommon-keysyms.h> 374*4882a593Smuzhiyun+#include <xkbcommon/xkbcommon.h> 375*4882a593Smuzhiyun+#include <aml.h> 376*4882a593Smuzhiyun+#include <neatvnc.h> 377*4882a593Smuzhiyun+#include <drm_fourcc.h> 378*4882a593Smuzhiyun+ 379*4882a593Smuzhiyun+#include "shared/helpers.h" 380*4882a593Smuzhiyun+#include "shared/xalloc.h" 381*4882a593Smuzhiyun+#include "shared/timespec-util.h" 382*4882a593Smuzhiyun+#include <libweston/libweston.h> 383*4882a593Smuzhiyun+#include <libweston/backend-vnc.h> 384*4882a593Smuzhiyun+#include "pixel-formats.h" 385*4882a593Smuzhiyun+#include "pixman-renderer.h" 386*4882a593Smuzhiyun+ 387*4882a593Smuzhiyun+#define DEFAULT_AXIS_STEP_DISTANCE 10 388*4882a593Smuzhiyun+ 389*4882a593Smuzhiyun+struct vnc_output; 390*4882a593Smuzhiyun+ 391*4882a593Smuzhiyun+struct vnc_backend { 392*4882a593Smuzhiyun+ struct weston_backend base; 393*4882a593Smuzhiyun+ struct weston_compositor *compositor; 394*4882a593Smuzhiyun+ struct vnc_output *output; 395*4882a593Smuzhiyun+ 396*4882a593Smuzhiyun+ struct xkb_rule_names xkb_rule_name; 397*4882a593Smuzhiyun+ struct xkb_keymap *xkb_keymap; 398*4882a593Smuzhiyun+ 399*4882a593Smuzhiyun+ struct aml *aml; 400*4882a593Smuzhiyun+ struct wl_event_source *aml_event; 401*4882a593Smuzhiyun+ struct nvnc *server; 402*4882a593Smuzhiyun+ int vnc_monitor_refresh_rate; 403*4882a593Smuzhiyun+}; 404*4882a593Smuzhiyun+ 405*4882a593Smuzhiyun+struct vnc_output { 406*4882a593Smuzhiyun+ struct weston_output base; 407*4882a593Smuzhiyun+ struct wl_event_source *finish_frame_timer; 408*4882a593Smuzhiyun+ struct nvnc_display *display; 409*4882a593Smuzhiyun+ 410*4882a593Smuzhiyun+ struct nvnc_fb_pool *fb_pool; 411*4882a593Smuzhiyun+ 412*4882a593Smuzhiyun+ struct wl_list peers; 413*4882a593Smuzhiyun+ struct wl_list fb_side_data_list; 414*4882a593Smuzhiyun+}; 415*4882a593Smuzhiyun+ 416*4882a593Smuzhiyun+struct vnc_peer { 417*4882a593Smuzhiyun+ struct vnc_backend *backend; 418*4882a593Smuzhiyun+ struct weston_seat *seat; 419*4882a593Smuzhiyun+ struct nvnc_client *client; 420*4882a593Smuzhiyun+ 421*4882a593Smuzhiyun+ enum nvnc_button_mask last_button_mask; 422*4882a593Smuzhiyun+ struct wl_list link; 423*4882a593Smuzhiyun+}; 424*4882a593Smuzhiyun+ 425*4882a593Smuzhiyun+struct vnc_head { 426*4882a593Smuzhiyun+ struct weston_head base; 427*4882a593Smuzhiyun+}; 428*4882a593Smuzhiyun+ 429*4882a593Smuzhiyun+struct fb_side_data { 430*4882a593Smuzhiyun+ pixman_image_t *pixman_image; 431*4882a593Smuzhiyun+ pixman_region32_t damage; 432*4882a593Smuzhiyun+ struct wl_list link; 433*4882a593Smuzhiyun+}; 434*4882a593Smuzhiyun+ 435*4882a593Smuzhiyun+static inline struct vnc_backend * 436*4882a593Smuzhiyun+to_vnc_backend(struct weston_compositor *base) 437*4882a593Smuzhiyun+{ 438*4882a593Smuzhiyun+ return container_of(base->backend, struct vnc_backend, base); 439*4882a593Smuzhiyun+} 440*4882a593Smuzhiyun+ 441*4882a593Smuzhiyun+static void 442*4882a593Smuzhiyun+vnc_output_destroy(struct weston_output *base); 443*4882a593Smuzhiyun+ 444*4882a593Smuzhiyun+static inline struct vnc_output * 445*4882a593Smuzhiyun+to_vnc_output(struct weston_output *base) 446*4882a593Smuzhiyun+{ 447*4882a593Smuzhiyun+ if (base->destroy != vnc_output_destroy) 448*4882a593Smuzhiyun+ return NULL; 449*4882a593Smuzhiyun+ return container_of(base, struct vnc_output, base); 450*4882a593Smuzhiyun+} 451*4882a593Smuzhiyun+ 452*4882a593Smuzhiyun+static void 453*4882a593Smuzhiyun+vnc_head_destroy(struct weston_head *base); 454*4882a593Smuzhiyun+ 455*4882a593Smuzhiyun+static inline struct vnc_head * 456*4882a593Smuzhiyun+to_vnc_head(struct weston_head *base) 457*4882a593Smuzhiyun+{ 458*4882a593Smuzhiyun+ if (base->backend_id != vnc_head_destroy) 459*4882a593Smuzhiyun+ return NULL; 460*4882a593Smuzhiyun+ return container_of(base, struct vnc_head, base); 461*4882a593Smuzhiyun+} 462*4882a593Smuzhiyun+ 463*4882a593Smuzhiyun+struct vnc_keysym_to_keycode { 464*4882a593Smuzhiyun+ const uint32_t keysym; 465*4882a593Smuzhiyun+ const uint32_t code; 466*4882a593Smuzhiyun+ const bool shift; 467*4882a593Smuzhiyun+}; 468*4882a593Smuzhiyun+ 469*4882a593Smuzhiyun+static const 470*4882a593Smuzhiyun+struct vnc_keysym_to_keycode key_translation[] = { 471*4882a593Smuzhiyun+ {XKB_KEY_KP_Enter, 0x60, false }, 472*4882a593Smuzhiyun+ {XKB_KEY_Return, 0x1c, false }, 473*4882a593Smuzhiyun+ {XKB_KEY_space, 0x39, false }, 474*4882a593Smuzhiyun+ {XKB_KEY_BackSpace, 0xe, false }, 475*4882a593Smuzhiyun+ {XKB_KEY_Tab, 0xf, false }, 476*4882a593Smuzhiyun+ {XKB_KEY_Escape, 0x1, false }, 477*4882a593Smuzhiyun+ {XKB_KEY_Shift_L, 0x2a, false }, 478*4882a593Smuzhiyun+ {XKB_KEY_Shift_R, 0x36, false }, 479*4882a593Smuzhiyun+ {XKB_KEY_Control_L, 0x1d, false }, 480*4882a593Smuzhiyun+ {XKB_KEY_Control_R, 0x9d, false }, 481*4882a593Smuzhiyun+ {XKB_KEY_Alt_L, 0x38, false }, 482*4882a593Smuzhiyun+ {XKB_KEY_Alt_R, 0x64, false }, 483*4882a593Smuzhiyun+ {XKB_KEY_Meta_L, 0x38, false }, 484*4882a593Smuzhiyun+ {XKB_KEY_Meta_R, 0x64, false }, 485*4882a593Smuzhiyun+ {XKB_KEY_Super_L, 0x7d, false }, 486*4882a593Smuzhiyun+ {XKB_KEY_Print, 0x63, false }, 487*4882a593Smuzhiyun+ {XKB_KEY_Pause, 0x77, false }, 488*4882a593Smuzhiyun+ {XKB_KEY_Caps_Lock, 0x3a, false }, 489*4882a593Smuzhiyun+ {XKB_KEY_Scroll_Lock, 0x46, false }, 490*4882a593Smuzhiyun+ {XKB_KEY_A, 0x1e, true }, 491*4882a593Smuzhiyun+ {XKB_KEY_a, 0x1e, false }, 492*4882a593Smuzhiyun+ {XKB_KEY_B, 0x30, true }, 493*4882a593Smuzhiyun+ {XKB_KEY_b, 0x30, false }, 494*4882a593Smuzhiyun+ {XKB_KEY_C, 0x2e, true }, 495*4882a593Smuzhiyun+ {XKB_KEY_c, 0x2e, false }, 496*4882a593Smuzhiyun+ {XKB_KEY_D, 0x20, true }, 497*4882a593Smuzhiyun+ {XKB_KEY_d, 0x20, false }, 498*4882a593Smuzhiyun+ {XKB_KEY_E, 0x12, true }, 499*4882a593Smuzhiyun+ {XKB_KEY_e, 0x12, false }, 500*4882a593Smuzhiyun+ {XKB_KEY_F, 0x21, true }, 501*4882a593Smuzhiyun+ {XKB_KEY_f, 0x21, false }, 502*4882a593Smuzhiyun+ {XKB_KEY_G, 0x22, true }, 503*4882a593Smuzhiyun+ {XKB_KEY_g, 0x22, false }, 504*4882a593Smuzhiyun+ {XKB_KEY_H, 0x23, true }, 505*4882a593Smuzhiyun+ {XKB_KEY_h, 0x23, false }, 506*4882a593Smuzhiyun+ {XKB_KEY_I, 0x17, true }, 507*4882a593Smuzhiyun+ {XKB_KEY_i, 0x17, false }, 508*4882a593Smuzhiyun+ {XKB_KEY_J, 0x24, true }, 509*4882a593Smuzhiyun+ {XKB_KEY_j, 0x24, false }, 510*4882a593Smuzhiyun+ {XKB_KEY_K, 0x25, true }, 511*4882a593Smuzhiyun+ {XKB_KEY_k, 0x25, false }, 512*4882a593Smuzhiyun+ {XKB_KEY_L, 0x26, true }, 513*4882a593Smuzhiyun+ {XKB_KEY_l, 0x26, false }, 514*4882a593Smuzhiyun+ {XKB_KEY_M, 0x32, true }, 515*4882a593Smuzhiyun+ {XKB_KEY_m, 0x32, false }, 516*4882a593Smuzhiyun+ {XKB_KEY_N, 0x31, true }, 517*4882a593Smuzhiyun+ {XKB_KEY_n, 0x31, false }, 518*4882a593Smuzhiyun+ {XKB_KEY_O, 0x18, true }, 519*4882a593Smuzhiyun+ {XKB_KEY_o, 0x18, false }, 520*4882a593Smuzhiyun+ {XKB_KEY_P, 0x19, true }, 521*4882a593Smuzhiyun+ {XKB_KEY_p, 0x19, false }, 522*4882a593Smuzhiyun+ {XKB_KEY_Q, 0x10, true }, 523*4882a593Smuzhiyun+ {XKB_KEY_q, 0x10, false }, 524*4882a593Smuzhiyun+ {XKB_KEY_R, 0x13, true }, 525*4882a593Smuzhiyun+ {XKB_KEY_r, 0x13, false }, 526*4882a593Smuzhiyun+ {XKB_KEY_S, 0x1f, true }, 527*4882a593Smuzhiyun+ {XKB_KEY_s, 0x1f, false }, 528*4882a593Smuzhiyun+ {XKB_KEY_T, 0x14, true }, 529*4882a593Smuzhiyun+ {XKB_KEY_t, 0x14, false }, 530*4882a593Smuzhiyun+ {XKB_KEY_U, 0x16, true }, 531*4882a593Smuzhiyun+ {XKB_KEY_u, 0x16, false }, 532*4882a593Smuzhiyun+ {XKB_KEY_V, 0x2f, true }, 533*4882a593Smuzhiyun+ {XKB_KEY_v, 0x2f, false }, 534*4882a593Smuzhiyun+ {XKB_KEY_W, 0x11, true }, 535*4882a593Smuzhiyun+ {XKB_KEY_w, 0x11, false }, 536*4882a593Smuzhiyun+ {XKB_KEY_X, 0x2d, true }, 537*4882a593Smuzhiyun+ {XKB_KEY_x, 0x2d, false }, 538*4882a593Smuzhiyun+ {XKB_KEY_Y, 0x15, true }, 539*4882a593Smuzhiyun+ {XKB_KEY_y, 0x15, false }, 540*4882a593Smuzhiyun+ {XKB_KEY_Z, 0x2c, true }, 541*4882a593Smuzhiyun+ {XKB_KEY_z, 0x2c, false }, 542*4882a593Smuzhiyun+ {XKB_KEY_grave, 0x29, false }, 543*4882a593Smuzhiyun+ {XKB_KEY_asciitilde, 0x29, true }, 544*4882a593Smuzhiyun+ {XKB_KEY_1, 0x02, false }, 545*4882a593Smuzhiyun+ {XKB_KEY_exclam, 0x02, true }, 546*4882a593Smuzhiyun+ {XKB_KEY_2, 0x03, false }, 547*4882a593Smuzhiyun+ {XKB_KEY_at, 0x03, true }, 548*4882a593Smuzhiyun+ {XKB_KEY_3, 0x04, false }, 549*4882a593Smuzhiyun+ {XKB_KEY_numbersign, 0x04, true }, 550*4882a593Smuzhiyun+ {XKB_KEY_4, 0x05, false }, 551*4882a593Smuzhiyun+ {XKB_KEY_dollar, 0x05, true }, 552*4882a593Smuzhiyun+ {XKB_KEY_5, 0x06, false }, 553*4882a593Smuzhiyun+ {XKB_KEY_percent, 0x06, true }, 554*4882a593Smuzhiyun+ {XKB_KEY_6, 0x07, false }, 555*4882a593Smuzhiyun+ {XKB_KEY_asciicircum, 0x07, true }, 556*4882a593Smuzhiyun+ {XKB_KEY_7, 0x08, false }, 557*4882a593Smuzhiyun+ {XKB_KEY_ampersand, 0x08, true }, 558*4882a593Smuzhiyun+ {XKB_KEY_8, 0x09, false }, 559*4882a593Smuzhiyun+ {XKB_KEY_asterisk, 0x09, true }, 560*4882a593Smuzhiyun+ {XKB_KEY_9, 0x0a, false }, 561*4882a593Smuzhiyun+ {XKB_KEY_parenleft, 0x0a, true }, 562*4882a593Smuzhiyun+ {XKB_KEY_0, 0x0b, false }, 563*4882a593Smuzhiyun+ {XKB_KEY_parenright, 0x0b, true }, 564*4882a593Smuzhiyun+ {XKB_KEY_minus, 0x0c, false, }, 565*4882a593Smuzhiyun+ {XKB_KEY_underscore, 0x0c, true }, 566*4882a593Smuzhiyun+ {XKB_KEY_equal, 0x0d, false }, 567*4882a593Smuzhiyun+ {XKB_KEY_plus, 0x0d, true }, 568*4882a593Smuzhiyun+ {XKB_KEY_bracketleft, 0x1a, false }, 569*4882a593Smuzhiyun+ {XKB_KEY_braceleft, 0x1a, true }, 570*4882a593Smuzhiyun+ {XKB_KEY_bracketright, 0x1b, false }, 571*4882a593Smuzhiyun+ {XKB_KEY_braceright, 0x1b, true }, 572*4882a593Smuzhiyun+ {XKB_KEY_semicolon, 0x27, false }, 573*4882a593Smuzhiyun+ {XKB_KEY_colon, 0x27, true }, 574*4882a593Smuzhiyun+ {XKB_KEY_apostrophe, 0x28, false }, 575*4882a593Smuzhiyun+ {XKB_KEY_quotedbl, 0x28, true }, 576*4882a593Smuzhiyun+ {XKB_KEY_backslash, 0x2b, false }, 577*4882a593Smuzhiyun+ {XKB_KEY_bar, 0x2b, true }, 578*4882a593Smuzhiyun+ {XKB_KEY_comma, 0x33, false }, 579*4882a593Smuzhiyun+ {XKB_KEY_less, 0x33, true }, 580*4882a593Smuzhiyun+ {XKB_KEY_period, 0x34, false }, 581*4882a593Smuzhiyun+ {XKB_KEY_greater, 0x34, true }, 582*4882a593Smuzhiyun+ {XKB_KEY_slash, 0x35, false }, 583*4882a593Smuzhiyun+ {XKB_KEY_question, 0x35, true }, 584*4882a593Smuzhiyun+ {XKB_KEY_F1, 0x3b, false }, 585*4882a593Smuzhiyun+ {XKB_KEY_F2, 0x3c, false }, 586*4882a593Smuzhiyun+ {XKB_KEY_F3, 0x3d, false }, 587*4882a593Smuzhiyun+ {XKB_KEY_F4, 0x3e, false }, 588*4882a593Smuzhiyun+ {XKB_KEY_F5, 0x3f, false }, 589*4882a593Smuzhiyun+ {XKB_KEY_F6, 0x40, false }, 590*4882a593Smuzhiyun+ {XKB_KEY_F7, 0x41, false }, 591*4882a593Smuzhiyun+ {XKB_KEY_F8, 0x42, false }, 592*4882a593Smuzhiyun+ {XKB_KEY_F9, 0x43, false }, 593*4882a593Smuzhiyun+ {XKB_KEY_F10, 0x44, false }, 594*4882a593Smuzhiyun+ {XKB_KEY_F11, 0x57, false }, 595*4882a593Smuzhiyun+ {XKB_KEY_F12, 0x58, false }, 596*4882a593Smuzhiyun+ {XKB_KEY_Home, 0x66, false }, 597*4882a593Smuzhiyun+ {XKB_KEY_Up, 0x67, false }, 598*4882a593Smuzhiyun+ {XKB_KEY_Prior, 0x68, false }, 599*4882a593Smuzhiyun+ {XKB_KEY_Left, 0x69, false }, 600*4882a593Smuzhiyun+ {XKB_KEY_Right, 0x6a, false }, 601*4882a593Smuzhiyun+ {XKB_KEY_End, 0x6b, false }, 602*4882a593Smuzhiyun+ {XKB_KEY_Down, 0x6c, false }, 603*4882a593Smuzhiyun+ {XKB_KEY_Next, 0x6d, false }, 604*4882a593Smuzhiyun+ { }, 605*4882a593Smuzhiyun+}; 606*4882a593Smuzhiyun+ 607*4882a593Smuzhiyun+static void 608*4882a593Smuzhiyun+vnc_handle_key_event(struct nvnc_client *client, uint32_t keysym, 609*4882a593Smuzhiyun+ bool is_pressed) 610*4882a593Smuzhiyun+{ 611*4882a593Smuzhiyun+ struct vnc_peer *peer = nvnc_get_userdata(client); 612*4882a593Smuzhiyun+ uint32_t key = 0; 613*4882a593Smuzhiyun+ bool needs_shift = false; 614*4882a593Smuzhiyun+ enum weston_key_state_update state_update; 615*4882a593Smuzhiyun+ enum wl_keyboard_key_state state; 616*4882a593Smuzhiyun+ struct timespec time; 617*4882a593Smuzhiyun+ int i; 618*4882a593Smuzhiyun+ 619*4882a593Smuzhiyun+ weston_compositor_get_time(&time); 620*4882a593Smuzhiyun+ 621*4882a593Smuzhiyun+ if (is_pressed) 622*4882a593Smuzhiyun+ state = WL_KEYBOARD_KEY_STATE_PRESSED; 623*4882a593Smuzhiyun+ else 624*4882a593Smuzhiyun+ state = WL_KEYBOARD_KEY_STATE_RELEASED; 625*4882a593Smuzhiyun+ 626*4882a593Smuzhiyun+ /* Generally ignore shift state as per RFC6143 Section 7.5.4 */ 627*4882a593Smuzhiyun+ if (keysym == XKB_KEY_Shift_L || keysym == XKB_KEY_Shift_R) 628*4882a593Smuzhiyun+ return; 629*4882a593Smuzhiyun+ 630*4882a593Smuzhiyun+ /* Allow selected modifiers */ 631*4882a593Smuzhiyun+ if (keysym == XKB_KEY_Control_L || keysym == XKB_KEY_Control_R || 632*4882a593Smuzhiyun+ keysym == XKB_KEY_Alt_L || keysym == XKB_KEY_Alt_R) 633*4882a593Smuzhiyun+ state_update = STATE_UPDATE_AUTOMATIC; 634*4882a593Smuzhiyun+ else 635*4882a593Smuzhiyun+ state_update = STATE_UPDATE_NONE; 636*4882a593Smuzhiyun+ 637*4882a593Smuzhiyun+ for (i = 0; key_translation[i].keysym; i++) { 638*4882a593Smuzhiyun+ if (key_translation[i].keysym == keysym) { 639*4882a593Smuzhiyun+ key = key_translation[i].code; 640*4882a593Smuzhiyun+ needs_shift = key_translation[i].shift; 641*4882a593Smuzhiyun+ break; 642*4882a593Smuzhiyun+ } 643*4882a593Smuzhiyun+ } 644*4882a593Smuzhiyun+ 645*4882a593Smuzhiyun+ if (!key) { 646*4882a593Smuzhiyun+ weston_log("Key not found: keysym %08x, translated %08x\n", 647*4882a593Smuzhiyun+ keysym, key); 648*4882a593Smuzhiyun+ return; 649*4882a593Smuzhiyun+ } 650*4882a593Smuzhiyun+ 651*4882a593Smuzhiyun+ /* emulate lshift press */ 652*4882a593Smuzhiyun+ if (needs_shift) 653*4882a593Smuzhiyun+ notify_key(peer->seat, &time, KEY_LEFTSHIFT, 654*4882a593Smuzhiyun+ WL_KEYBOARD_KEY_STATE_PRESSED, 655*4882a593Smuzhiyun+ STATE_UPDATE_AUTOMATIC); 656*4882a593Smuzhiyun+ 657*4882a593Smuzhiyun+ /* send detected key code */ 658*4882a593Smuzhiyun+ notify_key(peer->seat, &time, key, state, state_update); 659*4882a593Smuzhiyun+ 660*4882a593Smuzhiyun+ /* emulate lshift release */ 661*4882a593Smuzhiyun+ if (needs_shift) 662*4882a593Smuzhiyun+ notify_key(peer->seat, &time, KEY_LEFTSHIFT, 663*4882a593Smuzhiyun+ WL_KEYBOARD_KEY_STATE_RELEASED, 664*4882a593Smuzhiyun+ STATE_UPDATE_AUTOMATIC); 665*4882a593Smuzhiyun+} 666*4882a593Smuzhiyun+ 667*4882a593Smuzhiyun+static void 668*4882a593Smuzhiyun+vnc_pointer_event(struct nvnc_client *client, uint16_t x, uint16_t y, 669*4882a593Smuzhiyun+ enum nvnc_button_mask button_mask) 670*4882a593Smuzhiyun+{ 671*4882a593Smuzhiyun+ struct vnc_peer *peer = nvnc_get_userdata(client); 672*4882a593Smuzhiyun+ struct vnc_output *output = peer->backend->output; 673*4882a593Smuzhiyun+ struct timespec time; 674*4882a593Smuzhiyun+ enum nvnc_button_mask changed_button_mask; 675*4882a593Smuzhiyun+ 676*4882a593Smuzhiyun+ weston_compositor_get_time(&time); 677*4882a593Smuzhiyun+ 678*4882a593Smuzhiyun+ if (x < output->base.width && y < output->base.height) { 679*4882a593Smuzhiyun+ double global_x, global_y; 680*4882a593Smuzhiyun+ 681*4882a593Smuzhiyun+ weston_output_transform_coordinate(&output->base, x, y, 682*4882a593Smuzhiyun+ &global_x, &global_y); 683*4882a593Smuzhiyun+ notify_motion_absolute(peer->seat, &time, global_x, global_y); 684*4882a593Smuzhiyun+ } 685*4882a593Smuzhiyun+ 686*4882a593Smuzhiyun+ changed_button_mask = peer->last_button_mask ^ button_mask; 687*4882a593Smuzhiyun+ 688*4882a593Smuzhiyun+ if (changed_button_mask & NVNC_BUTTON_LEFT) 689*4882a593Smuzhiyun+ notify_button(peer->seat, &time, BTN_LEFT, 690*4882a593Smuzhiyun+ (button_mask & NVNC_BUTTON_LEFT) ? 691*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_PRESSED : 692*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_RELEASED); 693*4882a593Smuzhiyun+ 694*4882a593Smuzhiyun+ if (changed_button_mask & NVNC_BUTTON_MIDDLE) 695*4882a593Smuzhiyun+ notify_button(peer->seat, &time, BTN_MIDDLE, 696*4882a593Smuzhiyun+ (button_mask & NVNC_BUTTON_MIDDLE) ? 697*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_PRESSED : 698*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_RELEASED); 699*4882a593Smuzhiyun+ 700*4882a593Smuzhiyun+ if (changed_button_mask & NVNC_BUTTON_RIGHT) 701*4882a593Smuzhiyun+ notify_button(peer->seat, &time, BTN_RIGHT, 702*4882a593Smuzhiyun+ (button_mask & NVNC_BUTTON_RIGHT) ? 703*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_PRESSED : 704*4882a593Smuzhiyun+ WL_POINTER_BUTTON_STATE_RELEASED); 705*4882a593Smuzhiyun+ 706*4882a593Smuzhiyun+ if ((button_mask & NVNC_SCROLL_UP) || 707*4882a593Smuzhiyun+ (button_mask & NVNC_SCROLL_DOWN)) { 708*4882a593Smuzhiyun+ struct weston_pointer_axis_event weston_event; 709*4882a593Smuzhiyun+ 710*4882a593Smuzhiyun+ weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL; 711*4882a593Smuzhiyun+ 712*4882a593Smuzhiyun+ /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c */ 713*4882a593Smuzhiyun+ if (button_mask & NVNC_SCROLL_UP) 714*4882a593Smuzhiyun+ weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE; 715*4882a593Smuzhiyun+ if (button_mask & NVNC_SCROLL_DOWN) 716*4882a593Smuzhiyun+ weston_event.value = DEFAULT_AXIS_STEP_DISTANCE; 717*4882a593Smuzhiyun+ weston_event.has_discrete = false; 718*4882a593Smuzhiyun+ 719*4882a593Smuzhiyun+ notify_axis(peer->seat, &time, &weston_event); 720*4882a593Smuzhiyun+ } 721*4882a593Smuzhiyun+ 722*4882a593Smuzhiyun+ peer->last_button_mask = button_mask; 723*4882a593Smuzhiyun+ 724*4882a593Smuzhiyun+ notify_pointer_frame(peer->seat); 725*4882a593Smuzhiyun+} 726*4882a593Smuzhiyun+ 727*4882a593Smuzhiyun+static void 728*4882a593Smuzhiyun+vnc_client_cleanup(struct nvnc_client *client) 729*4882a593Smuzhiyun+{ 730*4882a593Smuzhiyun+ struct vnc_peer *peer = nvnc_get_userdata(client); 731*4882a593Smuzhiyun+ 732*4882a593Smuzhiyun+ wl_list_remove(&peer->link); 733*4882a593Smuzhiyun+ weston_seat_release_keyboard(peer->seat); 734*4882a593Smuzhiyun+ weston_seat_release_pointer(peer->seat); 735*4882a593Smuzhiyun+ weston_seat_release(peer->seat); 736*4882a593Smuzhiyun+ free(peer); 737*4882a593Smuzhiyun+ weston_log("VNC Client disconnected\n"); 738*4882a593Smuzhiyun+} 739*4882a593Smuzhiyun+ 740*4882a593Smuzhiyun+static void 741*4882a593Smuzhiyun+fb_side_data_destroy(void *userdata) 742*4882a593Smuzhiyun+{ 743*4882a593Smuzhiyun+ struct fb_side_data *fb_side_data = userdata; 744*4882a593Smuzhiyun+ 745*4882a593Smuzhiyun+ wl_list_remove(&fb_side_data->link); 746*4882a593Smuzhiyun+ pixman_region32_fini(&fb_side_data->damage); 747*4882a593Smuzhiyun+ pixman_image_unref(fb_side_data->pixman_image); 748*4882a593Smuzhiyun+ free(fb_side_data); 749*4882a593Smuzhiyun+} 750*4882a593Smuzhiyun+ 751*4882a593Smuzhiyun+ 752*4882a593Smuzhiyun+/* 753*4882a593Smuzhiyun+ * Convert damage rectangles from 32-bit global coordinates to 16-bit local 754*4882a593Smuzhiyun+ * coordinates. The output transformation has to be a pure translation. 755*4882a593Smuzhiyun+ */ 756*4882a593Smuzhiyun+static void 757*4882a593Smuzhiyun+vnc_convert_damage(struct pixman_region16 *dst, struct pixman_region32 *src, 758*4882a593Smuzhiyun+ int x, int y) 759*4882a593Smuzhiyun+{ 760*4882a593Smuzhiyun+ struct pixman_box32 *src_rects; 761*4882a593Smuzhiyun+ struct pixman_box16 *dest_rects; 762*4882a593Smuzhiyun+ int n_rects = 0; 763*4882a593Smuzhiyun+ int i; 764*4882a593Smuzhiyun+ 765*4882a593Smuzhiyun+ src_rects = pixman_region32_rectangles(src, &n_rects); 766*4882a593Smuzhiyun+ if (!n_rects) 767*4882a593Smuzhiyun+ return; 768*4882a593Smuzhiyun+ 769*4882a593Smuzhiyun+ dest_rects = xcalloc(n_rects, sizeof(*dest_rects)); 770*4882a593Smuzhiyun+ 771*4882a593Smuzhiyun+ for (i = 0; i < n_rects; i++) { 772*4882a593Smuzhiyun+ dest_rects[i].x1 = src_rects[i].x1 - x; 773*4882a593Smuzhiyun+ dest_rects[i].y1 = src_rects[i].y1 - y; 774*4882a593Smuzhiyun+ dest_rects[i].x2 = src_rects[i].x2 - x; 775*4882a593Smuzhiyun+ dest_rects[i].y2 = src_rects[i].y2 - y; 776*4882a593Smuzhiyun+ } 777*4882a593Smuzhiyun+ 778*4882a593Smuzhiyun+ pixman_region_init_rects(dst, dest_rects, n_rects); 779*4882a593Smuzhiyun+ free(dest_rects); 780*4882a593Smuzhiyun+} 781*4882a593Smuzhiyun+ 782*4882a593Smuzhiyun+static void 783*4882a593Smuzhiyun+vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage) 784*4882a593Smuzhiyun+{ 785*4882a593Smuzhiyun+ struct nvnc *server = nvnc_display_get_server(display); 786*4882a593Smuzhiyun+ struct vnc_backend *backend = nvnc_get_userdata(server); 787*4882a593Smuzhiyun+ struct vnc_output *output = backend->output; 788*4882a593Smuzhiyun+ struct weston_compositor *ec = output->base.compositor; 789*4882a593Smuzhiyun+ struct fb_side_data *fb_side_data; 790*4882a593Smuzhiyun+ pixman_region16_t local_damage; 791*4882a593Smuzhiyun+ struct nvnc_fb *fb; 792*4882a593Smuzhiyun+ 793*4882a593Smuzhiyun+ fb = nvnc_fb_pool_acquire(output->fb_pool); 794*4882a593Smuzhiyun+ assert(fb); 795*4882a593Smuzhiyun+ 796*4882a593Smuzhiyun+ fb_side_data = nvnc_get_userdata(fb); 797*4882a593Smuzhiyun+ if (!fb_side_data) { 798*4882a593Smuzhiyun+ const struct pixel_format_info *pfmt; 799*4882a593Smuzhiyun+ 800*4882a593Smuzhiyun+ fb_side_data = xzalloc(sizeof(*fb_side_data)); 801*4882a593Smuzhiyun+ 802*4882a593Smuzhiyun+ pfmt = pixel_format_get_info(DRM_FORMAT_XRGB8888); 803*4882a593Smuzhiyun+ fb_side_data->pixman_image = 804*4882a593Smuzhiyun+ pixman_image_create_bits(pfmt->pixman_format, 805*4882a593Smuzhiyun+ output->base.width, 806*4882a593Smuzhiyun+ output->base.height, 807*4882a593Smuzhiyun+ nvnc_fb_get_addr(fb), 808*4882a593Smuzhiyun+ output->base.width * 4); 809*4882a593Smuzhiyun+ 810*4882a593Smuzhiyun+ /* This is a new buffer, so the whole surface is damaged. */ 811*4882a593Smuzhiyun+ pixman_region32_copy(&fb_side_data->damage, 812*4882a593Smuzhiyun+ &output->base.region); 813*4882a593Smuzhiyun+ 814*4882a593Smuzhiyun+ nvnc_set_userdata(fb, fb_side_data, fb_side_data_destroy); 815*4882a593Smuzhiyun+ wl_list_insert(&output->fb_side_data_list, &fb_side_data->link); 816*4882a593Smuzhiyun+ } 817*4882a593Smuzhiyun+ 818*4882a593Smuzhiyun+ pixman_renderer_output_set_buffer(&output->base, 819*4882a593Smuzhiyun+ fb_side_data->pixman_image); 820*4882a593Smuzhiyun+ 821*4882a593Smuzhiyun+ ec->renderer->repaint_output(&output->base, &fb_side_data->damage); 822*4882a593Smuzhiyun+ 823*4882a593Smuzhiyun+ /* Convert to local coordinates before clearing accumulated damage */ 824*4882a593Smuzhiyun+ pixman_region_init(&local_damage); 825*4882a593Smuzhiyun+ vnc_convert_damage(&local_damage, &fb_side_data->damage, 826*4882a593Smuzhiyun+ output->base.x, output->base.y); 827*4882a593Smuzhiyun+ 828*4882a593Smuzhiyun+ /* Clear accumulated damage after repaint */ 829*4882a593Smuzhiyun+ pixman_region32_clear(&fb_side_data->damage); 830*4882a593Smuzhiyun+ 831*4882a593Smuzhiyun+ nvnc_display_feed_buffer(output->display, fb, &local_damage); 832*4882a593Smuzhiyun+ nvnc_fb_unref(fb); 833*4882a593Smuzhiyun+ pixman_region_fini(&local_damage); 834*4882a593Smuzhiyun+} 835*4882a593Smuzhiyun+ 836*4882a593Smuzhiyun+static void 837*4882a593Smuzhiyun+vnc_new_client(struct nvnc_client *client) 838*4882a593Smuzhiyun+{ 839*4882a593Smuzhiyun+ struct nvnc *server = nvnc_client_get_server(client); 840*4882a593Smuzhiyun+ struct vnc_backend *backend = nvnc_get_userdata(server); 841*4882a593Smuzhiyun+ struct vnc_output *output = backend->output; 842*4882a593Smuzhiyun+ struct vnc_peer *peer; 843*4882a593Smuzhiyun+ const char *seat_name = "VNC Client"; 844*4882a593Smuzhiyun+ 845*4882a593Smuzhiyun+ weston_log("New VNC client connected\n"); 846*4882a593Smuzhiyun+ 847*4882a593Smuzhiyun+ peer = xzalloc(sizeof(*peer)); 848*4882a593Smuzhiyun+ peer->client = client; 849*4882a593Smuzhiyun+ peer->backend = backend; 850*4882a593Smuzhiyun+ peer->seat = zalloc(sizeof(*peer->seat)); 851*4882a593Smuzhiyun+ 852*4882a593Smuzhiyun+ if (!peer->seat) { 853*4882a593Smuzhiyun+ weston_log("unable to create a weston_seat\n"); 854*4882a593Smuzhiyun+ return; 855*4882a593Smuzhiyun+ } 856*4882a593Smuzhiyun+ weston_seat_init(peer->seat, backend->compositor, seat_name); 857*4882a593Smuzhiyun+ weston_seat_init_pointer(peer->seat); 858*4882a593Smuzhiyun+ weston_seat_init_keyboard(peer->seat, backend->xkb_keymap); 859*4882a593Smuzhiyun+ 860*4882a593Smuzhiyun+ wl_list_insert(&output->peers, &peer->link); 861*4882a593Smuzhiyun+ 862*4882a593Smuzhiyun+ nvnc_set_userdata(client, peer, NULL); 863*4882a593Smuzhiyun+ nvnc_set_client_cleanup_fn(client, vnc_client_cleanup); 864*4882a593Smuzhiyun+ 865*4882a593Smuzhiyun+ /* 866*4882a593Smuzhiyun+ * Make up for repaints that were skipped when no clients were 867*4882a593Smuzhiyun+ * connected. 868*4882a593Smuzhiyun+ */ 869*4882a593Smuzhiyun+ weston_output_schedule_repaint(&output->base); 870*4882a593Smuzhiyun+} 871*4882a593Smuzhiyun+ 872*4882a593Smuzhiyun+ 873*4882a593Smuzhiyun+static int 874*4882a593Smuzhiyun+finish_frame_handler(void *data) 875*4882a593Smuzhiyun+{ 876*4882a593Smuzhiyun+ struct vnc_output *output = data; 877*4882a593Smuzhiyun+ int refresh_nsec = millihz_to_nsec(output->base.current_mode->refresh); 878*4882a593Smuzhiyun+ struct timespec now, ts; 879*4882a593Smuzhiyun+ int delta; 880*4882a593Smuzhiyun+ 881*4882a593Smuzhiyun+ /* The timer only has msec precision, but if we approximately hit our 882*4882a593Smuzhiyun+ * target, report an exact time stamp by adding to the previous frame 883*4882a593Smuzhiyun+ * time. 884*4882a593Smuzhiyun+ */ 885*4882a593Smuzhiyun+ timespec_add_nsec(&ts, &output->base.frame_time, refresh_nsec); 886*4882a593Smuzhiyun+ 887*4882a593Smuzhiyun+ /* If we are more than 1.5 ms late, report the current time instead. */ 888*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(output->base.compositor, &now); 889*4882a593Smuzhiyun+ delta = (int)timespec_sub_to_nsec(&now, &ts); 890*4882a593Smuzhiyun+ if (delta > 1500000) 891*4882a593Smuzhiyun+ ts = now; 892*4882a593Smuzhiyun+ 893*4882a593Smuzhiyun+ weston_output_finish_frame(&output->base, &ts, 0); 894*4882a593Smuzhiyun+ 895*4882a593Smuzhiyun+ return 1; 896*4882a593Smuzhiyun+} 897*4882a593Smuzhiyun+ 898*4882a593Smuzhiyun+static int 899*4882a593Smuzhiyun+vnc_output_enable(struct weston_output *base) 900*4882a593Smuzhiyun+{ 901*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 902*4882a593Smuzhiyun+ struct vnc_backend *backend; 903*4882a593Smuzhiyun+ struct wl_event_loop *loop; 904*4882a593Smuzhiyun+ const struct pixman_renderer_output_options options = { 905*4882a593Smuzhiyun+ .use_shadow = true, 906*4882a593Smuzhiyun+ .fb_size = { 907*4882a593Smuzhiyun+ .width = output->base.width, 908*4882a593Smuzhiyun+ .height = output->base.height, 909*4882a593Smuzhiyun+ }, 910*4882a593Smuzhiyun+ }; 911*4882a593Smuzhiyun+ 912*4882a593Smuzhiyun+ assert(output); 913*4882a593Smuzhiyun+ 914*4882a593Smuzhiyun+ backend = to_vnc_backend(base->compositor); 915*4882a593Smuzhiyun+ backend->output = output; 916*4882a593Smuzhiyun+ 917*4882a593Smuzhiyun+ if (pixman_renderer_output_create(&output->base, &options) < 0) 918*4882a593Smuzhiyun+ return -1; 919*4882a593Smuzhiyun+ 920*4882a593Smuzhiyun+ loop = wl_display_get_event_loop(backend->compositor->wl_display); 921*4882a593Smuzhiyun+ output->finish_frame_timer = wl_event_loop_add_timer(loop, 922*4882a593Smuzhiyun+ finish_frame_handler, 923*4882a593Smuzhiyun+ output); 924*4882a593Smuzhiyun+ 925*4882a593Smuzhiyun+ output->fb_pool = nvnc_fb_pool_new(output->base.width, 926*4882a593Smuzhiyun+ output->base.height, 927*4882a593Smuzhiyun+ DRM_FORMAT_XRGB8888, 928*4882a593Smuzhiyun+ output->base.width); 929*4882a593Smuzhiyun+ 930*4882a593Smuzhiyun+ output->display = nvnc_display_new(0, 0); 931*4882a593Smuzhiyun+ 932*4882a593Smuzhiyun+ wl_list_init(&output->fb_side_data_list); 933*4882a593Smuzhiyun+ 934*4882a593Smuzhiyun+ nvnc_add_display(backend->server, output->display); 935*4882a593Smuzhiyun+ 936*4882a593Smuzhiyun+ /* 937*4882a593Smuzhiyun+ * Neat VNC warns when a client connects before a display buffer has 938*4882a593Smuzhiyun+ * been set. Repaint once to create an initial buffer. 939*4882a593Smuzhiyun+ */ 940*4882a593Smuzhiyun+ vnc_update_buffer(output->display, &output->base.region); 941*4882a593Smuzhiyun+ 942*4882a593Smuzhiyun+ return 0; 943*4882a593Smuzhiyun+} 944*4882a593Smuzhiyun+ 945*4882a593Smuzhiyun+static int 946*4882a593Smuzhiyun+vnc_output_disable(struct weston_output *base) 947*4882a593Smuzhiyun+{ 948*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 949*4882a593Smuzhiyun+ struct vnc_backend *backend; 950*4882a593Smuzhiyun+ 951*4882a593Smuzhiyun+ assert(output); 952*4882a593Smuzhiyun+ 953*4882a593Smuzhiyun+ backend = to_vnc_backend(base->compositor); 954*4882a593Smuzhiyun+ 955*4882a593Smuzhiyun+ if (!output->base.enabled) 956*4882a593Smuzhiyun+ return 0; 957*4882a593Smuzhiyun+ 958*4882a593Smuzhiyun+ pixman_renderer_output_destroy(&output->base); 959*4882a593Smuzhiyun+ 960*4882a593Smuzhiyun+ nvnc_display_unref(output->display); 961*4882a593Smuzhiyun+ nvnc_fb_pool_unref(output->fb_pool); 962*4882a593Smuzhiyun+ 963*4882a593Smuzhiyun+ wl_event_source_remove(output->finish_frame_timer); 964*4882a593Smuzhiyun+ backend->output = NULL; 965*4882a593Smuzhiyun+ 966*4882a593Smuzhiyun+ return 0; 967*4882a593Smuzhiyun+} 968*4882a593Smuzhiyun+ 969*4882a593Smuzhiyun+static void 970*4882a593Smuzhiyun+vnc_output_destroy(struct weston_output *base) 971*4882a593Smuzhiyun+{ 972*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 973*4882a593Smuzhiyun+ 974*4882a593Smuzhiyun+ /* Can only be called on outputs created by vnc_create_output() */ 975*4882a593Smuzhiyun+ assert(output); 976*4882a593Smuzhiyun+ 977*4882a593Smuzhiyun+ vnc_output_disable(&output->base); 978*4882a593Smuzhiyun+ weston_output_release(&output->base); 979*4882a593Smuzhiyun+ 980*4882a593Smuzhiyun+ free(output); 981*4882a593Smuzhiyun+} 982*4882a593Smuzhiyun+ 983*4882a593Smuzhiyun+static struct weston_output * 984*4882a593Smuzhiyun+vnc_create_output(struct weston_compositor *compositor, const char *name) 985*4882a593Smuzhiyun+{ 986*4882a593Smuzhiyun+ struct vnc_output *output; 987*4882a593Smuzhiyun+ 988*4882a593Smuzhiyun+ output = zalloc(sizeof *output); 989*4882a593Smuzhiyun+ if (output == NULL) 990*4882a593Smuzhiyun+ return NULL; 991*4882a593Smuzhiyun+ 992*4882a593Smuzhiyun+ weston_output_init(&output->base, compositor, name); 993*4882a593Smuzhiyun+ 994*4882a593Smuzhiyun+ output->base.destroy = vnc_output_destroy; 995*4882a593Smuzhiyun+ output->base.disable = vnc_output_disable; 996*4882a593Smuzhiyun+ output->base.enable = vnc_output_enable; 997*4882a593Smuzhiyun+ output->base.attach_head = NULL; 998*4882a593Smuzhiyun+ 999*4882a593Smuzhiyun+ weston_compositor_add_pending_output(&output->base, compositor); 1000*4882a593Smuzhiyun+ 1001*4882a593Smuzhiyun+ return &output->base; 1002*4882a593Smuzhiyun+} 1003*4882a593Smuzhiyun+ 1004*4882a593Smuzhiyun+static void 1005*4882a593Smuzhiyun+vnc_destroy(struct weston_compositor *ec) 1006*4882a593Smuzhiyun+{ 1007*4882a593Smuzhiyun+ struct weston_head *base, *next; 1008*4882a593Smuzhiyun+ struct vnc_backend *backend = to_vnc_backend(ec); 1009*4882a593Smuzhiyun+ 1010*4882a593Smuzhiyun+ nvnc_close(backend->server); 1011*4882a593Smuzhiyun+ 1012*4882a593Smuzhiyun+ weston_compositor_shutdown(ec); 1013*4882a593Smuzhiyun+ 1014*4882a593Smuzhiyun+ wl_event_source_remove(backend->aml_event); 1015*4882a593Smuzhiyun+ 1016*4882a593Smuzhiyun+ aml_unref(backend->aml); 1017*4882a593Smuzhiyun+ 1018*4882a593Smuzhiyun+ wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) 1019*4882a593Smuzhiyun+ vnc_head_destroy(base); 1020*4882a593Smuzhiyun+ 1021*4882a593Smuzhiyun+ xkb_keymap_unref(backend->xkb_keymap); 1022*4882a593Smuzhiyun+ 1023*4882a593Smuzhiyun+ free(backend); 1024*4882a593Smuzhiyun+} 1025*4882a593Smuzhiyun+ 1026*4882a593Smuzhiyun+static int 1027*4882a593Smuzhiyun+vnc_head_create(struct weston_compositor *compositor, const char *name) 1028*4882a593Smuzhiyun+{ 1029*4882a593Smuzhiyun+ struct vnc_head *head; 1030*4882a593Smuzhiyun+ 1031*4882a593Smuzhiyun+ head = zalloc(sizeof *head); 1032*4882a593Smuzhiyun+ if (!head) 1033*4882a593Smuzhiyun+ return -1; 1034*4882a593Smuzhiyun+ 1035*4882a593Smuzhiyun+ weston_head_init(&head->base, name); 1036*4882a593Smuzhiyun+ 1037*4882a593Smuzhiyun+ head->base.backend_id = vnc_head_destroy; 1038*4882a593Smuzhiyun+ 1039*4882a593Smuzhiyun+ weston_head_set_connection_status(&head->base, true); 1040*4882a593Smuzhiyun+ weston_compositor_add_head(compositor, &head->base); 1041*4882a593Smuzhiyun+ 1042*4882a593Smuzhiyun+ return 0; 1043*4882a593Smuzhiyun+} 1044*4882a593Smuzhiyun+ 1045*4882a593Smuzhiyun+static void 1046*4882a593Smuzhiyun+vnc_head_destroy(struct weston_head *base) 1047*4882a593Smuzhiyun+{ 1048*4882a593Smuzhiyun+ struct vnc_head *head = to_vnc_head(base); 1049*4882a593Smuzhiyun+ 1050*4882a593Smuzhiyun+ if (!head) 1051*4882a593Smuzhiyun+ return; 1052*4882a593Smuzhiyun+ 1053*4882a593Smuzhiyun+ weston_head_release(&head->base); 1054*4882a593Smuzhiyun+ free(head); 1055*4882a593Smuzhiyun+} 1056*4882a593Smuzhiyun+ 1057*4882a593Smuzhiyun+static int 1058*4882a593Smuzhiyun+vnc_output_start_repaint_loop(struct weston_output *output) 1059*4882a593Smuzhiyun+{ 1060*4882a593Smuzhiyun+ struct timespec ts; 1061*4882a593Smuzhiyun+ 1062*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(output->compositor, &ts); 1063*4882a593Smuzhiyun+ weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID); 1064*4882a593Smuzhiyun+ 1065*4882a593Smuzhiyun+ return 0; 1066*4882a593Smuzhiyun+} 1067*4882a593Smuzhiyun+ 1068*4882a593Smuzhiyun+static int 1069*4882a593Smuzhiyun+vnc_output_repaint(struct weston_output *base, pixman_region32_t *damage) 1070*4882a593Smuzhiyun+{ 1071*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 1072*4882a593Smuzhiyun+ struct weston_compositor *ec = output->base.compositor; 1073*4882a593Smuzhiyun+ struct vnc_backend *backend = to_vnc_backend(ec); 1074*4882a593Smuzhiyun+ struct timespec now, target; 1075*4882a593Smuzhiyun+ int refresh_nsec = millihz_to_nsec(output->base.current_mode->refresh); 1076*4882a593Smuzhiyun+ int refresh_msec = refresh_nsec / 1000000; 1077*4882a593Smuzhiyun+ int next_frame_delta; 1078*4882a593Smuzhiyun+ 1079*4882a593Smuzhiyun+ assert(output); 1080*4882a593Smuzhiyun+ 1081*4882a593Smuzhiyun+ if (pixman_region32_not_empty(damage)) { 1082*4882a593Smuzhiyun+ struct fb_side_data *fb_side_data; 1083*4882a593Smuzhiyun+ 1084*4882a593Smuzhiyun+ /* Accumulate damage in all buffers */ 1085*4882a593Smuzhiyun+ wl_list_for_each(fb_side_data, &output->fb_side_data_list, link) 1086*4882a593Smuzhiyun+ pixman_region32_union(&fb_side_data->damage, 1087*4882a593Smuzhiyun+ &fb_side_data->damage, damage); 1088*4882a593Smuzhiyun+ 1089*4882a593Smuzhiyun+ /* Only repaint when a client is connected */ 1090*4882a593Smuzhiyun+ if (!wl_list_empty(&output->peers)) 1091*4882a593Smuzhiyun+ vnc_update_buffer(output->display, damage); 1092*4882a593Smuzhiyun+ 1093*4882a593Smuzhiyun+ pixman_region32_subtract(&ec->primary_plane.damage, 1094*4882a593Smuzhiyun+ &ec->primary_plane.damage, damage); 1095*4882a593Smuzhiyun+ } 1096*4882a593Smuzhiyun+ 1097*4882a593Smuzhiyun+ /* 1098*4882a593Smuzhiyun+ * Make sure damage of this (or previous) damage is handled 1099*4882a593Smuzhiyun+ * 1100*4882a593Smuzhiyun+ * This will usually invoke the render callback where the (pixman) 1101*4882a593Smuzhiyun+ * renderer gets invoked 1102*4882a593Smuzhiyun+ */ 1103*4882a593Smuzhiyun+ aml_dispatch(backend->aml); 1104*4882a593Smuzhiyun+ 1105*4882a593Smuzhiyun+ weston_compositor_read_presentation_clock(ec, &now); 1106*4882a593Smuzhiyun+ timespec_add_nsec(&target, &output->base.frame_time, refresh_nsec); 1107*4882a593Smuzhiyun+ 1108*4882a593Smuzhiyun+ next_frame_delta = (int)timespec_sub_to_msec(&target, &now); 1109*4882a593Smuzhiyun+ if (next_frame_delta < 1) 1110*4882a593Smuzhiyun+ next_frame_delta = 1; 1111*4882a593Smuzhiyun+ if (next_frame_delta > refresh_msec) 1112*4882a593Smuzhiyun+ next_frame_delta = refresh_msec; 1113*4882a593Smuzhiyun+ 1114*4882a593Smuzhiyun+ wl_event_source_timer_update(output->finish_frame_timer, 1115*4882a593Smuzhiyun+ next_frame_delta); 1116*4882a593Smuzhiyun+ 1117*4882a593Smuzhiyun+ return 0; 1118*4882a593Smuzhiyun+} 1119*4882a593Smuzhiyun+ 1120*4882a593Smuzhiyun+static struct weston_mode * 1121*4882a593Smuzhiyun+vnc_insert_new_mode(struct weston_output *output, int width, int height, 1122*4882a593Smuzhiyun+ int rate) 1123*4882a593Smuzhiyun+{ 1124*4882a593Smuzhiyun+ struct weston_mode *mode; 1125*4882a593Smuzhiyun+ 1126*4882a593Smuzhiyun+ mode = zalloc(sizeof *mode); 1127*4882a593Smuzhiyun+ if (!mode) 1128*4882a593Smuzhiyun+ return NULL; 1129*4882a593Smuzhiyun+ mode->width = width; 1130*4882a593Smuzhiyun+ mode->height = height; 1131*4882a593Smuzhiyun+ mode->refresh = rate; 1132*4882a593Smuzhiyun+ wl_list_insert(&output->mode_list, &mode->link); 1133*4882a593Smuzhiyun+ 1134*4882a593Smuzhiyun+ return mode; 1135*4882a593Smuzhiyun+} 1136*4882a593Smuzhiyun+ 1137*4882a593Smuzhiyun+static struct weston_mode * 1138*4882a593Smuzhiyun+vnc_ensure_matching_mode(struct weston_output *output, 1139*4882a593Smuzhiyun+ struct weston_mode *target) 1140*4882a593Smuzhiyun+{ 1141*4882a593Smuzhiyun+ struct vnc_backend *backend = to_vnc_backend(output->compositor); 1142*4882a593Smuzhiyun+ struct weston_mode *local; 1143*4882a593Smuzhiyun+ 1144*4882a593Smuzhiyun+ wl_list_for_each(local, &output->mode_list, link) { 1145*4882a593Smuzhiyun+ if ((local->width == target->width) && 1146*4882a593Smuzhiyun+ (local->height == target->height)) 1147*4882a593Smuzhiyun+ return local; 1148*4882a593Smuzhiyun+ } 1149*4882a593Smuzhiyun+ 1150*4882a593Smuzhiyun+ return vnc_insert_new_mode(output, target->width, target->height, 1151*4882a593Smuzhiyun+ backend->vnc_monitor_refresh_rate); 1152*4882a593Smuzhiyun+} 1153*4882a593Smuzhiyun+ 1154*4882a593Smuzhiyun+static int 1155*4882a593Smuzhiyun+vnc_switch_mode(struct weston_output *base, struct weston_mode *target_mode) 1156*4882a593Smuzhiyun+{ 1157*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 1158*4882a593Smuzhiyun+ struct weston_mode *local_mode; 1159*4882a593Smuzhiyun+ struct weston_size fb_size; 1160*4882a593Smuzhiyun+ 1161*4882a593Smuzhiyun+ assert(output); 1162*4882a593Smuzhiyun+ 1163*4882a593Smuzhiyun+ local_mode = vnc_ensure_matching_mode(base, target_mode); 1164*4882a593Smuzhiyun+ if (!local_mode) { 1165*4882a593Smuzhiyun+ weston_log("mode %dx%d not available\n", 1166*4882a593Smuzhiyun+ target_mode->width, target_mode->height); 1167*4882a593Smuzhiyun+ return -ENOENT; 1168*4882a593Smuzhiyun+ } 1169*4882a593Smuzhiyun+ 1170*4882a593Smuzhiyun+ if (local_mode == base->current_mode) 1171*4882a593Smuzhiyun+ return 0; 1172*4882a593Smuzhiyun+ 1173*4882a593Smuzhiyun+ base->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT; 1174*4882a593Smuzhiyun+ 1175*4882a593Smuzhiyun+ base->current_mode = base->native_mode = local_mode; 1176*4882a593Smuzhiyun+ base->current_mode->flags |= WL_OUTPUT_MODE_CURRENT; 1177*4882a593Smuzhiyun+ 1178*4882a593Smuzhiyun+ fb_size.width = target_mode->width; 1179*4882a593Smuzhiyun+ fb_size.height = target_mode->height; 1180*4882a593Smuzhiyun+ 1181*4882a593Smuzhiyun+ weston_renderer_resize_output(base, &fb_size, NULL); 1182*4882a593Smuzhiyun+ 1183*4882a593Smuzhiyun+ nvnc_fb_pool_unref(output->fb_pool); 1184*4882a593Smuzhiyun+ 1185*4882a593Smuzhiyun+ output->fb_pool = nvnc_fb_pool_new(target_mode->width, 1186*4882a593Smuzhiyun+ target_mode->height, 1187*4882a593Smuzhiyun+ DRM_FORMAT_XRGB8888, 1188*4882a593Smuzhiyun+ target_mode->width * 4); 1189*4882a593Smuzhiyun+ 1190*4882a593Smuzhiyun+ return 0; 1191*4882a593Smuzhiyun+} 1192*4882a593Smuzhiyun+ 1193*4882a593Smuzhiyun+static int 1194*4882a593Smuzhiyun+vnc_output_set_size(struct weston_output *base, int width, int height) 1195*4882a593Smuzhiyun+{ 1196*4882a593Smuzhiyun+ struct vnc_output *output = to_vnc_output(base); 1197*4882a593Smuzhiyun+ struct vnc_backend *backend = to_vnc_backend(base->compositor); 1198*4882a593Smuzhiyun+ struct weston_head *head; 1199*4882a593Smuzhiyun+ struct weston_mode *current_mode; 1200*4882a593Smuzhiyun+ struct weston_mode init_mode; 1201*4882a593Smuzhiyun+ 1202*4882a593Smuzhiyun+ /* We can only be called once. */ 1203*4882a593Smuzhiyun+ assert(!output->base.current_mode); 1204*4882a593Smuzhiyun+ 1205*4882a593Smuzhiyun+ wl_list_for_each(head, &output->base.head_list, output_link) { 1206*4882a593Smuzhiyun+ weston_head_set_monitor_strings(head, "weston", "vnc", NULL); 1207*4882a593Smuzhiyun+ 1208*4882a593Smuzhiyun+ weston_head_set_physical_size(head, 0, 0); 1209*4882a593Smuzhiyun+ } 1210*4882a593Smuzhiyun+ 1211*4882a593Smuzhiyun+ wl_list_init(&output->peers); 1212*4882a593Smuzhiyun+ 1213*4882a593Smuzhiyun+ init_mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED; 1214*4882a593Smuzhiyun+ init_mode.width = width; 1215*4882a593Smuzhiyun+ init_mode.height = height; 1216*4882a593Smuzhiyun+ init_mode.refresh = backend->vnc_monitor_refresh_rate; 1217*4882a593Smuzhiyun+ 1218*4882a593Smuzhiyun+ current_mode = vnc_ensure_matching_mode(&output->base, &init_mode); 1219*4882a593Smuzhiyun+ if (!current_mode) 1220*4882a593Smuzhiyun+ return -1; 1221*4882a593Smuzhiyun+ 1222*4882a593Smuzhiyun+ output->base.current_mode = output->base.native_mode = current_mode; 1223*4882a593Smuzhiyun+ 1224*4882a593Smuzhiyun+ output->base.start_repaint_loop = vnc_output_start_repaint_loop; 1225*4882a593Smuzhiyun+ output->base.repaint = vnc_output_repaint; 1226*4882a593Smuzhiyun+ output->base.assign_planes = NULL; 1227*4882a593Smuzhiyun+ output->base.set_backlight = NULL; 1228*4882a593Smuzhiyun+ output->base.set_dpms = NULL; 1229*4882a593Smuzhiyun+ output->base.switch_mode = vnc_switch_mode; 1230*4882a593Smuzhiyun+ 1231*4882a593Smuzhiyun+ return 0; 1232*4882a593Smuzhiyun+} 1233*4882a593Smuzhiyun+ 1234*4882a593Smuzhiyun+static const struct weston_vnc_output_api api = { 1235*4882a593Smuzhiyun+ vnc_output_set_size, 1236*4882a593Smuzhiyun+}; 1237*4882a593Smuzhiyun+ 1238*4882a593Smuzhiyun+static int 1239*4882a593Smuzhiyun+vnc_aml_dispatch(int fd, uint32_t mask, void *data) 1240*4882a593Smuzhiyun+{ 1241*4882a593Smuzhiyun+ struct aml *aml = data; 1242*4882a593Smuzhiyun+ 1243*4882a593Smuzhiyun+ aml_poll(aml, 0); 1244*4882a593Smuzhiyun+ aml_dispatch(aml); 1245*4882a593Smuzhiyun+ 1246*4882a593Smuzhiyun+ return 0; 1247*4882a593Smuzhiyun+} 1248*4882a593Smuzhiyun+ 1249*4882a593Smuzhiyun+static struct vnc_backend * 1250*4882a593Smuzhiyun+vnc_backend_create(struct weston_compositor *compositor, 1251*4882a593Smuzhiyun+ struct weston_vnc_backend_config *config) 1252*4882a593Smuzhiyun+{ 1253*4882a593Smuzhiyun+ struct vnc_backend *backend; 1254*4882a593Smuzhiyun+ struct wl_event_loop *loop; 1255*4882a593Smuzhiyun+ struct weston_head *base, *next; 1256*4882a593Smuzhiyun+ int ret; 1257*4882a593Smuzhiyun+ int fd; 1258*4882a593Smuzhiyun+ 1259*4882a593Smuzhiyun+ backend = zalloc(sizeof *backend); 1260*4882a593Smuzhiyun+ if (backend == NULL) 1261*4882a593Smuzhiyun+ return NULL; 1262*4882a593Smuzhiyun+ 1263*4882a593Smuzhiyun+ backend->compositor = compositor; 1264*4882a593Smuzhiyun+ backend->base.destroy = vnc_destroy; 1265*4882a593Smuzhiyun+ backend->base.create_output = vnc_create_output; 1266*4882a593Smuzhiyun+ backend->vnc_monitor_refresh_rate = config->refresh_rate * 1000; 1267*4882a593Smuzhiyun+ 1268*4882a593Smuzhiyun+ compositor->backend = &backend->base; 1269*4882a593Smuzhiyun+ 1270*4882a593Smuzhiyun+ if (weston_compositor_set_presentation_clock_software(compositor) < 0) 1271*4882a593Smuzhiyun+ goto err_compositor; 1272*4882a593Smuzhiyun+ 1273*4882a593Smuzhiyun+ if (pixman_renderer_init(compositor) < 0) 1274*4882a593Smuzhiyun+ goto err_compositor; 1275*4882a593Smuzhiyun+ 1276*4882a593Smuzhiyun+ if (vnc_head_create(compositor, "vnc") < 0) 1277*4882a593Smuzhiyun+ goto err_compositor; 1278*4882a593Smuzhiyun+ 1279*4882a593Smuzhiyun+ compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES; 1280*4882a593Smuzhiyun+ 1281*4882a593Smuzhiyun+ backend->xkb_rule_name.rules = strdup("evdev"); 1282*4882a593Smuzhiyun+ backend->xkb_rule_name.model = strdup("pc105"); 1283*4882a593Smuzhiyun+ backend->xkb_rule_name.layout = strdup("us"); 1284*4882a593Smuzhiyun+ 1285*4882a593Smuzhiyun+ backend->xkb_keymap = xkb_keymap_new_from_names( 1286*4882a593Smuzhiyun+ backend->compositor->xkb_context, 1287*4882a593Smuzhiyun+ &backend->xkb_rule_name, 0); 1288*4882a593Smuzhiyun+ 1289*4882a593Smuzhiyun+ loop = wl_display_get_event_loop(backend->compositor->wl_display); 1290*4882a593Smuzhiyun+ 1291*4882a593Smuzhiyun+ backend->aml = aml_new(); 1292*4882a593Smuzhiyun+ if (!backend->aml) 1293*4882a593Smuzhiyun+ goto err_output; 1294*4882a593Smuzhiyun+ aml_set_default(backend->aml); 1295*4882a593Smuzhiyun+ 1296*4882a593Smuzhiyun+ fd = aml_get_fd(backend->aml); 1297*4882a593Smuzhiyun+ 1298*4882a593Smuzhiyun+ backend->aml_event = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, 1299*4882a593Smuzhiyun+ vnc_aml_dispatch, 1300*4882a593Smuzhiyun+ backend->aml); 1301*4882a593Smuzhiyun+ 1302*4882a593Smuzhiyun+ backend->server = nvnc_open(config->bind_address, config->port); 1303*4882a593Smuzhiyun+ if (!backend->server) 1304*4882a593Smuzhiyun+ goto err_output; 1305*4882a593Smuzhiyun+ 1306*4882a593Smuzhiyun+ nvnc_set_new_client_fn(backend->server, vnc_new_client); 1307*4882a593Smuzhiyun+ nvnc_set_pointer_fn(backend->server, vnc_pointer_event); 1308*4882a593Smuzhiyun+ nvnc_set_key_fn(backend->server, vnc_handle_key_event); 1309*4882a593Smuzhiyun+ nvnc_set_userdata(backend->server, backend, NULL); 1310*4882a593Smuzhiyun+ nvnc_set_name(backend->server, "Weston VNC backend"); 1311*4882a593Smuzhiyun+ 1312*4882a593Smuzhiyun+ ret = weston_plugin_api_register(compositor, WESTON_VNC_OUTPUT_API_NAME, 1313*4882a593Smuzhiyun+ &api, sizeof(api)); 1314*4882a593Smuzhiyun+ if (ret < 0) { 1315*4882a593Smuzhiyun+ weston_log("Failed to register output API.\n"); 1316*4882a593Smuzhiyun+ goto err_output; 1317*4882a593Smuzhiyun+ } 1318*4882a593Smuzhiyun+ 1319*4882a593Smuzhiyun+ return backend; 1320*4882a593Smuzhiyun+ 1321*4882a593Smuzhiyun+err_output: 1322*4882a593Smuzhiyun+ if (backend->output) 1323*4882a593Smuzhiyun+ weston_output_release(&backend->output->base); 1324*4882a593Smuzhiyun+ wl_list_for_each_safe(base, next, &compositor->head_list, compositor_link) 1325*4882a593Smuzhiyun+ vnc_head_destroy(base); 1326*4882a593Smuzhiyun+err_compositor: 1327*4882a593Smuzhiyun+ weston_compositor_shutdown(compositor); 1328*4882a593Smuzhiyun+ free(backend); 1329*4882a593Smuzhiyun+ return NULL; 1330*4882a593Smuzhiyun+} 1331*4882a593Smuzhiyun+ 1332*4882a593Smuzhiyun+static void 1333*4882a593Smuzhiyun+config_init_to_defaults(struct weston_vnc_backend_config *config) 1334*4882a593Smuzhiyun+{ 1335*4882a593Smuzhiyun+ config->bind_address = NULL; 1336*4882a593Smuzhiyun+ config->port = 5900; 1337*4882a593Smuzhiyun+ config->refresh_rate = VNC_DEFAULT_FREQ; 1338*4882a593Smuzhiyun+} 1339*4882a593Smuzhiyun+ 1340*4882a593Smuzhiyun+WL_EXPORT int 1341*4882a593Smuzhiyun+weston_backend_init(struct weston_compositor *compositor, 1342*4882a593Smuzhiyun+ struct weston_backend_config *config_base) 1343*4882a593Smuzhiyun+{ 1344*4882a593Smuzhiyun+ struct vnc_backend *backend; 1345*4882a593Smuzhiyun+ struct weston_vnc_backend_config config = {{ 0, }}; 1346*4882a593Smuzhiyun+ 1347*4882a593Smuzhiyun+ weston_log("Initializing VNC backend\n"); 1348*4882a593Smuzhiyun+ 1349*4882a593Smuzhiyun+ if (config_base == NULL || 1350*4882a593Smuzhiyun+ config_base->struct_version != WESTON_VNC_BACKEND_CONFIG_VERSION || 1351*4882a593Smuzhiyun+ config_base->struct_size > sizeof(struct weston_vnc_backend_config)) { 1352*4882a593Smuzhiyun+ weston_log("VNC backend config structure is invalid\n"); 1353*4882a593Smuzhiyun+ return -1; 1354*4882a593Smuzhiyun+ } 1355*4882a593Smuzhiyun+ 1356*4882a593Smuzhiyun+ config_init_to_defaults(&config); 1357*4882a593Smuzhiyun+ memcpy(&config, config_base, config_base->struct_size); 1358*4882a593Smuzhiyun+ 1359*4882a593Smuzhiyun+ backend = vnc_backend_create(compositor, &config); 1360*4882a593Smuzhiyun+ if (backend == NULL) 1361*4882a593Smuzhiyun+ return -1; 1362*4882a593Smuzhiyun+ return 0; 1363*4882a593Smuzhiyun+} 1364*4882a593Smuzhiyundiff --git a/libweston/compositor.c b/libweston/compositor.c 1365*4882a593Smuzhiyunindex cd5c48d..24f4f36 100644 1366*4882a593Smuzhiyun--- a/libweston/compositor.c 1367*4882a593Smuzhiyun+++ b/libweston/compositor.c 1368*4882a593Smuzhiyun@@ -9101,6 +9101,7 @@ static const char * const backend_map[] = { 1369*4882a593Smuzhiyun [WESTON_BACKEND_DRM] = "drm-backend.so", 1370*4882a593Smuzhiyun [WESTON_BACKEND_HEADLESS] = "headless-backend.so", 1371*4882a593Smuzhiyun [WESTON_BACKEND_RDP] = "rdp-backend.so", 1372*4882a593Smuzhiyun+ [WESTON_BACKEND_VNC] = "vnc-backend.so", 1373*4882a593Smuzhiyun [WESTON_BACKEND_WAYLAND] = "wayland-backend.so", 1374*4882a593Smuzhiyun [WESTON_BACKEND_X11] = "x11-backend.so", 1375*4882a593Smuzhiyun }; 1376*4882a593Smuzhiyundiff --git a/libweston/meson.build b/libweston/meson.build 1377*4882a593Smuzhiyunindex 6a845cc..6906244 100644 1378*4882a593Smuzhiyun--- a/libweston/meson.build 1379*4882a593Smuzhiyun+++ b/libweston/meson.build 1380*4882a593Smuzhiyun@@ -241,5 +241,6 @@ subdir('renderer-gl') 1381*4882a593Smuzhiyun subdir('backend-drm') 1382*4882a593Smuzhiyun subdir('backend-headless') 1383*4882a593Smuzhiyun subdir('backend-rdp') 1384*4882a593Smuzhiyun+subdir('backend-vnc') 1385*4882a593Smuzhiyun subdir('backend-wayland') 1386*4882a593Smuzhiyun subdir('backend-x11') 1387*4882a593Smuzhiyundiff --git a/meson_options.txt b/meson_options.txt 1388*4882a593Smuzhiyunindex 055457d..df5ba60 100644 1389*4882a593Smuzhiyun--- a/meson_options.txt 1390*4882a593Smuzhiyun+++ b/meson_options.txt 1391*4882a593Smuzhiyun@@ -32,6 +32,12 @@ option( 1392*4882a593Smuzhiyun value: true, 1393*4882a593Smuzhiyun description: 'Compositor: RDP screen-sharing support' 1394*4882a593Smuzhiyun ) 1395*4882a593Smuzhiyun+option( 1396*4882a593Smuzhiyun+ 'backend-vnc', 1397*4882a593Smuzhiyun+ type: 'boolean', 1398*4882a593Smuzhiyun+ value: true, 1399*4882a593Smuzhiyun+ description: 'Weston backend: VNC remote screensharing' 1400*4882a593Smuzhiyun+) 1401*4882a593Smuzhiyun option( 1402*4882a593Smuzhiyun 'backend-wayland', 1403*4882a593Smuzhiyun type: 'boolean', 1404*4882a593Smuzhiyun-- 1405*4882a593Smuzhiyun2.20.1 1406*4882a593Smuzhiyun 1407