Revision bd023f95
b/Makefile.objs | ||
---|---|---|
111 | 111 |
ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o |
112 | 112 |
ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o |
113 | 113 |
ui-obj-$(CONFIG_COCOA) += cocoa.o |
114 |
ifdef CONFIG_VNC_THREAD |
|
115 |
ui-obj-y += vnc-jobs-async.o |
|
116 |
else |
|
117 |
ui-obj-y += vnc-jobs-sync.o |
|
118 |
endif |
|
114 | 119 |
common-obj-y += $(addprefix ui/, $(ui-obj-y)) |
115 | 120 |
|
116 | 121 |
common-obj-y += iov.o acl.o |
117 |
common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
|
|
122 |
common-obj-$(CONFIG_THREAD) += qemu-thread.o |
|
118 | 123 |
common-obj-y += notify.o event_notifier.o |
119 | 124 |
common-obj-y += qemu-timer.o |
120 | 125 |
|
b/configure | ||
---|---|---|
270 | 270 |
vnc_sasl="" |
271 | 271 |
vnc_jpeg="" |
272 | 272 |
vnc_png="" |
273 |
vnc_thread="" |
|
273 | 274 |
xen="" |
274 | 275 |
linux_aio="" |
275 | 276 |
attr="" |
... | ... | |
585 | 586 |
;; |
586 | 587 |
--enable-vnc-png) vnc_png="yes" |
587 | 588 |
;; |
589 |
--disable-vnc-thread) vnc_thread="no" |
|
590 |
;; |
|
591 |
--enable-vnc-thread) vnc_thread="yes" |
|
592 |
;; |
|
588 | 593 |
--disable-slirp) slirp="no" |
589 | 594 |
;; |
590 | 595 |
--disable-uuid) uuid="no" |
... | ... | |
839 | 844 |
echo " --enable-vnc-jpeg enable JPEG lossy compression for VNC server" |
840 | 845 |
echo " --disable-vnc-png disable PNG compression for VNC server" |
841 | 846 |
echo " --enable-vnc-png enable PNG compression for VNC server" |
847 |
echo " --disable-vnc-thread disable threaded VNC server" |
|
848 |
echo " --enable-vnc-thread enable threaded VNC server" |
|
842 | 849 |
echo " --disable-curses disable curses output" |
843 | 850 |
echo " --enable-curses enable curses output" |
844 | 851 |
echo " --disable-curl disable curl connectivity" |
... | ... | |
2156 | 2163 |
echo "VNC SASL support $vnc_sasl" |
2157 | 2164 |
echo "VNC JPEG support $vnc_jpeg" |
2158 | 2165 |
echo "VNC PNG support $vnc_png" |
2166 |
echo "VNC thread $vnc_thread" |
|
2159 | 2167 |
if test -n "$sparc_cpu"; then |
2160 | 2168 |
echo "Target Sparc Arch $sparc_cpu" |
2161 | 2169 |
fi |
... | ... | |
2301 | 2309 |
echo "CONFIG_VNC_PNG=y" >> $config_host_mak |
2302 | 2310 |
echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak |
2303 | 2311 |
fi |
2312 |
if test "$vnc_thread" = "yes" ; then |
|
2313 |
echo "CONFIG_VNC_THREAD=y" >> $config_host_mak |
|
2314 |
echo "CONFIG_THREAD=y" >> $config_host_mak |
|
2315 |
fi |
|
2304 | 2316 |
if test "$fnmatch" = "yes" ; then |
2305 | 2317 |
echo "CONFIG_FNMATCH=y" >> $config_host_mak |
2306 | 2318 |
fi |
... | ... | |
2377 | 2389 |
fi |
2378 | 2390 |
if test "$io_thread" = "yes" ; then |
2379 | 2391 |
echo "CONFIG_IOTHREAD=y" >> $config_host_mak |
2392 |
echo "CONFIG_THREAD=y" >> $config_host_mak |
|
2380 | 2393 |
fi |
2381 | 2394 |
if test "$linux_aio" = "yes" ; then |
2382 | 2395 |
echo "CONFIG_LINUX_AIO=y" >> $config_host_mak |
b/ui/vnc-jobs-async.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU VNC display driver |
|
3 |
* |
|
4 |
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> |
|
5 |
* Copyright (C) 2006 Fabrice Bellard |
|
6 |
* Copyright (C) 2009 Red Hat, Inc |
|
7 |
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> |
|
8 |
* |
|
9 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
10 |
* of this software and associated documentation files (the "Software"), to deal |
|
11 |
* in the Software without restriction, including without limitation the rights |
|
12 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
13 |
* copies of the Software, and to permit persons to whom the Software is |
|
14 |
* furnished to do so, subject to the following conditions: |
|
15 |
* |
|
16 |
* The above copyright notice and this permission notice shall be included in |
|
17 |
* all copies or substantial portions of the Software. |
|
18 |
* |
|
19 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
20 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
21 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
22 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
23 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
24 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
25 |
* THE SOFTWARE. |
|
26 |
*/ |
|
27 |
|
|
28 |
|
|
29 |
#include "vnc.h" |
|
30 |
#include "vnc-jobs.h" |
|
31 |
|
|
32 |
/* |
|
33 |
* Locking: |
|
34 |
* |
|
35 |
* There is three levels of locking: |
|
36 |
* - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) |
|
37 |
* - VncDisplay global lock: mainly used for framebuffer updates to avoid |
|
38 |
* screen corruption if the framebuffer is updated |
|
39 |
* while the worker is doing something. |
|
40 |
* - VncState::output lock: used to make sure the output buffer is not corrupted |
|
41 |
* if two threads try to write on it at the same time |
|
42 |
* |
|
43 |
* While the VNC worker thread is working, the VncDisplay global lock is hold |
|
44 |
* to avoid screen corruptions (this does not block vnc_refresh() because it |
|
45 |
* uses trylock()) but the output lock is not hold because the thread work on |
|
46 |
* its own output buffer. |
|
47 |
* When the encoding job is done, the worker thread will hold the output lock |
|
48 |
* and copy its output buffer in vs->output. |
|
49 |
*/ |
|
50 |
|
|
51 |
struct VncJobQueue { |
|
52 |
QemuCond cond; |
|
53 |
QemuMutex mutex; |
|
54 |
QemuThread thread; |
|
55 |
Buffer buffer; |
|
56 |
bool exit; |
|
57 |
QTAILQ_HEAD(, VncJob) jobs; |
|
58 |
}; |
|
59 |
|
|
60 |
typedef struct VncJobQueue VncJobQueue; |
|
61 |
|
|
62 |
/* |
|
63 |
* We use a single global queue, but most of the functions are |
|
64 |
* already reetrant, so we can easilly add more than one encoding thread |
|
65 |
*/ |
|
66 |
static VncJobQueue *queue; |
|
67 |
|
|
68 |
static void vnc_lock_queue(VncJobQueue *queue) |
|
69 |
{ |
|
70 |
qemu_mutex_lock(&queue->mutex); |
|
71 |
} |
|
72 |
|
|
73 |
static void vnc_unlock_queue(VncJobQueue *queue) |
|
74 |
{ |
|
75 |
qemu_mutex_unlock(&queue->mutex); |
|
76 |
} |
|
77 |
|
|
78 |
VncJob *vnc_job_new(VncState *vs) |
|
79 |
{ |
|
80 |
VncJob *job = qemu_mallocz(sizeof(VncJob)); |
|
81 |
|
|
82 |
job->vs = vs; |
|
83 |
vnc_lock_queue(queue); |
|
84 |
QLIST_INIT(&job->rectangles); |
|
85 |
vnc_unlock_queue(queue); |
|
86 |
return job; |
|
87 |
} |
|
88 |
|
|
89 |
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) |
|
90 |
{ |
|
91 |
VncRectEntry *entry = qemu_mallocz(sizeof(VncRectEntry)); |
|
92 |
|
|
93 |
entry->rect.x = x; |
|
94 |
entry->rect.y = y; |
|
95 |
entry->rect.w = w; |
|
96 |
entry->rect.h = h; |
|
97 |
|
|
98 |
vnc_lock_queue(queue); |
|
99 |
QLIST_INSERT_HEAD(&job->rectangles, entry, next); |
|
100 |
vnc_unlock_queue(queue); |
|
101 |
return 1; |
|
102 |
} |
|
103 |
|
|
104 |
void vnc_job_push(VncJob *job) |
|
105 |
{ |
|
106 |
vnc_lock_queue(queue); |
|
107 |
if (queue->exit || QLIST_EMPTY(&job->rectangles)) { |
|
108 |
qemu_free(job); |
|
109 |
} else { |
|
110 |
QTAILQ_INSERT_TAIL(&queue->jobs, job, next); |
|
111 |
qemu_cond_broadcast(&queue->cond); |
|
112 |
} |
|
113 |
vnc_unlock_queue(queue); |
|
114 |
} |
|
115 |
|
|
116 |
static bool vnc_has_job_locked(VncState *vs) |
|
117 |
{ |
|
118 |
VncJob *job; |
|
119 |
|
|
120 |
QTAILQ_FOREACH(job, &queue->jobs, next) { |
|
121 |
if (job->vs == vs || !vs) { |
|
122 |
return true; |
|
123 |
} |
|
124 |
} |
|
125 |
return false; |
|
126 |
} |
|
127 |
|
|
128 |
bool vnc_has_job(VncState *vs) |
|
129 |
{ |
|
130 |
bool ret; |
|
131 |
|
|
132 |
vnc_lock_queue(queue); |
|
133 |
ret = vnc_has_job_locked(vs); |
|
134 |
vnc_unlock_queue(queue); |
|
135 |
return ret; |
|
136 |
} |
|
137 |
|
|
138 |
void vnc_jobs_clear(VncState *vs) |
|
139 |
{ |
|
140 |
VncJob *job, *tmp; |
|
141 |
|
|
142 |
vnc_lock_queue(queue); |
|
143 |
QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) { |
|
144 |
if (job->vs == vs || !vs) { |
|
145 |
QTAILQ_REMOVE(&queue->jobs, job, next); |
|
146 |
} |
|
147 |
} |
|
148 |
vnc_unlock_queue(queue); |
|
149 |
} |
|
150 |
|
|
151 |
void vnc_jobs_join(VncState *vs) |
|
152 |
{ |
|
153 |
vnc_lock_queue(queue); |
|
154 |
while (vnc_has_job_locked(vs)) { |
|
155 |
qemu_cond_wait(&queue->cond, &queue->mutex); |
|
156 |
} |
|
157 |
vnc_unlock_queue(queue); |
|
158 |
} |
|
159 |
|
|
160 |
/* |
|
161 |
* Copy data for local use |
|
162 |
*/ |
|
163 |
static void vnc_async_encoding_start(VncState *orig, VncState *local) |
|
164 |
{ |
|
165 |
local->vnc_encoding = orig->vnc_encoding; |
|
166 |
local->features = orig->features; |
|
167 |
local->ds = orig->ds; |
|
168 |
local->vd = orig->vd; |
|
169 |
local->write_pixels = orig->write_pixels; |
|
170 |
local->clientds = orig->clientds; |
|
171 |
local->tight = orig->tight; |
|
172 |
local->zlib = orig->zlib; |
|
173 |
local->hextile = orig->hextile; |
|
174 |
local->output = queue->buffer; |
|
175 |
local->csock = -1; /* Don't do any network work on this thread */ |
|
176 |
|
|
177 |
buffer_reset(&local->output); |
|
178 |
} |
|
179 |
|
|
180 |
static void vnc_async_encoding_end(VncState *orig, VncState *local) |
|
181 |
{ |
|
182 |
orig->tight = local->tight; |
|
183 |
orig->zlib = local->zlib; |
|
184 |
orig->hextile = local->hextile; |
|
185 |
} |
|
186 |
|
|
187 |
static int vnc_worker_thread_loop(VncJobQueue *queue) |
|
188 |
{ |
|
189 |
VncJob *job; |
|
190 |
VncRectEntry *entry, *tmp; |
|
191 |
VncState vs; |
|
192 |
int n_rectangles; |
|
193 |
int saved_offset; |
|
194 |
bool flush; |
|
195 |
|
|
196 |
vnc_lock_queue(queue); |
|
197 |
while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) { |
|
198 |
qemu_cond_wait(&queue->cond, &queue->mutex); |
|
199 |
} |
|
200 |
/* Here job can only be NULL if queue->exit is true */ |
|
201 |
job = QTAILQ_FIRST(&queue->jobs); |
|
202 |
vnc_unlock_queue(queue); |
|
203 |
|
|
204 |
if (queue->exit) { |
|
205 |
return -1; |
|
206 |
} |
|
207 |
|
|
208 |
vnc_lock_output(job->vs); |
|
209 |
if (job->vs->csock == -1 || job->vs->abort == true) { |
|
210 |
goto disconnected; |
|
211 |
} |
|
212 |
vnc_unlock_output(job->vs); |
|
213 |
|
|
214 |
/* Make a local copy of vs and switch output buffers */ |
|
215 |
vnc_async_encoding_start(job->vs, &vs); |
|
216 |
|
|
217 |
/* Start sending rectangles */ |
|
218 |
n_rectangles = 0; |
|
219 |
vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
|
220 |
vnc_write_u8(&vs, 0); |
|
221 |
saved_offset = vs.output.offset; |
|
222 |
vnc_write_u16(&vs, 0); |
|
223 |
|
|
224 |
vnc_lock_display(job->vs->vd); |
|
225 |
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { |
|
226 |
int n; |
|
227 |
|
|
228 |
if (job->vs->csock == -1) { |
|
229 |
vnc_unlock_display(job->vs->vd); |
|
230 |
goto disconnected; |
|
231 |
} |
|
232 |
|
|
233 |
n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y, |
|
234 |
entry->rect.w, entry->rect.h); |
|
235 |
|
|
236 |
if (n >= 0) { |
|
237 |
n_rectangles += n; |
|
238 |
} |
|
239 |
qemu_free(entry); |
|
240 |
} |
|
241 |
vnc_unlock_display(job->vs->vd); |
|
242 |
|
|
243 |
/* Put n_rectangles at the beginning of the message */ |
|
244 |
vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; |
|
245 |
vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF; |
|
246 |
|
|
247 |
/* Switch back buffers */ |
|
248 |
vnc_lock_output(job->vs); |
|
249 |
if (job->vs->csock == -1) { |
|
250 |
goto disconnected; |
|
251 |
} |
|
252 |
|
|
253 |
vnc_write(job->vs, vs.output.buffer, vs.output.offset); |
|
254 |
|
|
255 |
disconnected: |
|
256 |
/* Copy persistent encoding data */ |
|
257 |
vnc_async_encoding_end(job->vs, &vs); |
|
258 |
flush = (job->vs->csock != -1 && job->vs->abort != true); |
|
259 |
vnc_unlock_output(job->vs); |
|
260 |
|
|
261 |
if (flush) { |
|
262 |
vnc_flush(job->vs); |
|
263 |
} |
|
264 |
|
|
265 |
vnc_lock_queue(queue); |
|
266 |
QTAILQ_REMOVE(&queue->jobs, job, next); |
|
267 |
vnc_unlock_queue(queue); |
|
268 |
qemu_cond_broadcast(&queue->cond); |
|
269 |
qemu_free(job); |
|
270 |
return 0; |
|
271 |
} |
|
272 |
|
|
273 |
static VncJobQueue *vnc_queue_init(void) |
|
274 |
{ |
|
275 |
VncJobQueue *queue = qemu_mallocz(sizeof(VncJobQueue)); |
|
276 |
|
|
277 |
qemu_cond_init(&queue->cond); |
|
278 |
qemu_mutex_init(&queue->mutex); |
|
279 |
QTAILQ_INIT(&queue->jobs); |
|
280 |
return queue; |
|
281 |
} |
|
282 |
|
|
283 |
static void vnc_queue_clear(VncJobQueue *q) |
|
284 |
{ |
|
285 |
qemu_cond_destroy(&queue->cond); |
|
286 |
qemu_mutex_destroy(&queue->mutex); |
|
287 |
buffer_free(&queue->buffer); |
|
288 |
qemu_free(q); |
|
289 |
queue = NULL; /* Unset global queue */ |
|
290 |
} |
|
291 |
|
|
292 |
static void *vnc_worker_thread(void *arg) |
|
293 |
{ |
|
294 |
VncJobQueue *queue = arg; |
|
295 |
|
|
296 |
qemu_thread_self(&queue->thread); |
|
297 |
|
|
298 |
while (!vnc_worker_thread_loop(queue)) ; |
|
299 |
vnc_queue_clear(queue); |
|
300 |
return NULL; |
|
301 |
} |
|
302 |
|
|
303 |
void vnc_start_worker_thread(void) |
|
304 |
{ |
|
305 |
VncJobQueue *q; |
|
306 |
|
|
307 |
if (vnc_worker_thread_running()) |
|
308 |
return ; |
|
309 |
|
|
310 |
q = vnc_queue_init(); |
|
311 |
qemu_thread_create(&q->thread, vnc_worker_thread, q); |
|
312 |
queue = q; /* Set global queue */ |
|
313 |
} |
|
314 |
|
|
315 |
bool vnc_worker_thread_running(void) |
|
316 |
{ |
|
317 |
return queue; /* Check global queue */ |
|
318 |
} |
|
319 |
|
|
320 |
void vnc_stop_worker_thread(void) |
|
321 |
{ |
|
322 |
if (!vnc_worker_thread_running()) |
|
323 |
return ; |
|
324 |
|
|
325 |
/* Remove all jobs and wake up the thread */ |
|
326 |
vnc_lock_queue(queue); |
|
327 |
queue->exit = true; |
|
328 |
vnc_unlock_queue(queue); |
|
329 |
vnc_jobs_clear(NULL); |
|
330 |
qemu_cond_broadcast(&queue->cond); |
|
331 |
} |
b/ui/vnc-jobs-sync.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU VNC display driver |
|
3 |
* |
|
4 |
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws> |
|
5 |
* Copyright (C) 2006 Fabrice Bellard |
|
6 |
* Copyright (C) 2009 Red Hat, Inc |
|
7 |
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> |
|
8 |
* |
|
9 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
10 |
* of this software and associated documentation files (the "Software"), to deal |
|
11 |
* in the Software without restriction, including without limitation the rights |
|
12 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
13 |
* copies of the Software, and to permit persons to whom the Software is |
|
14 |
* furnished to do so, subject to the following conditions: |
|
15 |
* |
|
16 |
* The above copyright notice and this permission notice shall be included in |
|
17 |
* all copies or substantial portions of the Software. |
|
18 |
* |
|
19 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
20 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
21 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
22 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
23 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
24 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
25 |
* THE SOFTWARE. |
|
26 |
*/ |
|
27 |
|
|
28 |
#include "vnc.h" |
|
29 |
#include "vnc-jobs.h" |
|
30 |
|
|
31 |
void vnc_jobs_clear(VncState *vs) |
|
32 |
{ |
|
33 |
} |
|
34 |
|
|
35 |
void vnc_jobs_join(VncState *vs) |
|
36 |
{ |
|
37 |
} |
|
38 |
|
|
39 |
VncJob *vnc_job_new(VncState *vs) |
|
40 |
{ |
|
41 |
vs->job.vs = vs; |
|
42 |
vs->job.rectangles = 0; |
|
43 |
|
|
44 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
|
45 |
vnc_write_u8(vs, 0); |
|
46 |
vs->job.saved_offset = vs->output.offset; |
|
47 |
vnc_write_u16(vs, 0); |
|
48 |
return &vs->job; |
|
49 |
} |
|
50 |
|
|
51 |
void vnc_job_push(VncJob *job) |
|
52 |
{ |
|
53 |
VncState *vs = job->vs; |
|
54 |
|
|
55 |
vs->output.buffer[job->saved_offset] = (job->rectangles >> 8) & 0xFF; |
|
56 |
vs->output.buffer[job->saved_offset + 1] = job->rectangles & 0xFF; |
|
57 |
vnc_flush(job->vs); |
|
58 |
} |
|
59 |
|
|
60 |
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h) |
|
61 |
{ |
|
62 |
int n; |
|
63 |
|
|
64 |
n = vnc_send_framebuffer_update(job->vs, x, y, w, h); |
|
65 |
if (n >= 0) |
|
66 |
job->rectangles += n; |
|
67 |
return n; |
|
68 |
} |
|
69 |
|
|
70 |
bool vnc_has_job(VncState *vs) |
|
71 |
{ |
|
72 |
return false; |
|
73 |
} |
b/ui/vnc-jobs.h | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU VNC display driver |
|
3 |
* |
|
4 |
* From libvncserver/rfb/rfbproto.h |
|
5 |
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin |
|
6 |
* Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved. |
|
7 |
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved. |
|
8 |
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. |
|
9 |
* |
|
10 |
* |
|
11 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
12 |
* of this software and associated documentation files (the "Software"), to deal |
|
13 |
* in the Software without restriction, including without limitation the rights |
|
14 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
15 |
* copies of the Software, and to permit persons to whom the Software is |
|
16 |
* furnished to do so, subject to the following conditions: |
|
17 |
* |
|
18 |
* The above copyright notice and this permission notice shall be included in |
|
19 |
* all copies or substantial portions of the Software. |
|
20 |
* |
|
21 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
22 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
23 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
24 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
25 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
26 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
27 |
* THE SOFTWARE. |
|
28 |
*/ |
|
29 |
|
|
30 |
#ifndef VNC_JOBS_H |
|
31 |
#define VNC_JOBS_H |
|
32 |
|
|
33 |
/* Jobs */ |
|
34 |
VncJob *vnc_job_new(VncState *vs); |
|
35 |
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h); |
|
36 |
void vnc_job_push(VncJob *job); |
|
37 |
bool vnc_has_job(VncState *vs); |
|
38 |
void vnc_jobs_clear(VncState *vs); |
|
39 |
void vnc_jobs_join(VncState *vs); |
|
40 |
|
|
41 |
#ifdef CONFIG_VNC_THREAD |
|
42 |
|
|
43 |
void vnc_start_worker_thread(void); |
|
44 |
bool vnc_worker_thread_running(void); |
|
45 |
void vnc_stop_worker_thread(void); |
|
46 |
|
|
47 |
#endif /* CONFIG_VNC_THREAD */ |
|
48 |
|
|
49 |
/* Locks */ |
|
50 |
static inline int vnc_trylock_display(VncDisplay *vd) |
|
51 |
{ |
|
52 |
#ifdef CONFIG_VNC_THREAD |
|
53 |
return qemu_mutex_trylock(&vd->mutex); |
|
54 |
#else |
|
55 |
return 0; |
|
56 |
#endif |
|
57 |
} |
|
58 |
|
|
59 |
static inline void vnc_lock_display(VncDisplay *vd) |
|
60 |
{ |
|
61 |
#ifdef CONFIG_VNC_THREAD |
|
62 |
qemu_mutex_lock(&vd->mutex); |
|
63 |
#endif |
|
64 |
} |
|
65 |
|
|
66 |
static inline void vnc_unlock_display(VncDisplay *vd) |
|
67 |
{ |
|
68 |
#ifdef CONFIG_VNC_THREAD |
|
69 |
qemu_mutex_unlock(&vd->mutex); |
|
70 |
#endif |
|
71 |
} |
|
72 |
|
|
73 |
static inline void vnc_lock_output(VncState *vs) |
|
74 |
{ |
|
75 |
#ifdef CONFIG_VNC_THREAD |
|
76 |
qemu_mutex_lock(&vs->output_mutex); |
|
77 |
#endif |
|
78 |
} |
|
79 |
|
|
80 |
static inline void vnc_unlock_output(VncState *vs) |
|
81 |
{ |
|
82 |
#ifdef CONFIG_VNC_THREAD |
|
83 |
qemu_mutex_unlock(&vs->output_mutex); |
|
84 |
#endif |
|
85 |
} |
|
86 |
|
|
87 |
#endif /* VNC_JOBS_H */ |
b/ui/vnc.c | ||
---|---|---|
25 | 25 |
*/ |
26 | 26 |
|
27 | 27 |
#include "vnc.h" |
28 |
#include "vnc-jobs.h" |
|
28 | 29 |
#include "sysemu.h" |
29 | 30 |
#include "qemu_socket.h" |
30 | 31 |
#include "qemu-timer.h" |
... | ... | |
45 | 46 |
} \ |
46 | 47 |
} |
47 | 48 |
|
48 |
|
|
49 | 49 |
static VncDisplay *vnc_display; /* needed for info vnc */ |
50 | 50 |
static DisplayChangeListener *dcl; |
51 | 51 |
|
... | ... | |
359 | 359 |
*/ |
360 | 360 |
|
361 | 361 |
static int vnc_update_client(VncState *vs, int has_dirty); |
362 |
static int vnc_update_client_sync(VncState *vs, int has_dirty); |
|
362 | 363 |
static void vnc_disconnect_start(VncState *vs); |
363 | 364 |
static void vnc_disconnect_finish(VncState *vs); |
364 | 365 |
static void vnc_init_timer(VncDisplay *vd); |
... | ... | |
502 | 503 |
} |
503 | 504 |
vs->client_width = ds_get_width(ds); |
504 | 505 |
vs->client_height = ds_get_height(ds); |
506 |
vnc_lock_output(vs); |
|
505 | 507 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
506 | 508 |
vnc_write_u8(vs, 0); |
507 | 509 |
vnc_write_u16(vs, 1); /* number of rects */ |
508 | 510 |
vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height, |
509 | 511 |
VNC_ENCODING_DESKTOPRESIZE); |
512 |
vnc_unlock_output(vs); |
|
510 | 513 |
vnc_flush(vs); |
511 | 514 |
} |
512 | 515 |
|
516 |
#ifdef CONFIG_VNC_THREAD |
|
517 |
static void vnc_abort_display_jobs(VncDisplay *vd) |
|
518 |
{ |
|
519 |
VncState *vs; |
|
520 |
|
|
521 |
QTAILQ_FOREACH(vs, &vd->clients, next) { |
|
522 |
vnc_lock_output(vs); |
|
523 |
vs->abort = true; |
|
524 |
vnc_unlock_output(vs); |
|
525 |
} |
|
526 |
QTAILQ_FOREACH(vs, &vd->clients, next) { |
|
527 |
vnc_jobs_join(vs); |
|
528 |
} |
|
529 |
QTAILQ_FOREACH(vs, &vd->clients, next) { |
|
530 |
vnc_lock_output(vs); |
|
531 |
vs->abort = false; |
|
532 |
vnc_unlock_output(vs); |
|
533 |
} |
|
534 |
} |
|
535 |
#else |
|
536 |
static void vnc_abort_display_jobs(VncDisplay *vd) |
|
537 |
{ |
|
538 |
} |
|
539 |
#endif |
|
540 |
|
|
513 | 541 |
static void vnc_dpy_resize(DisplayState *ds) |
514 | 542 |
{ |
515 | 543 |
VncDisplay *vd = ds->opaque; |
516 | 544 |
VncState *vs; |
517 | 545 |
|
546 |
vnc_abort_display_jobs(vd); |
|
547 |
|
|
518 | 548 |
/* server surface */ |
519 | 549 |
if (!vd->server) |
520 | 550 |
vd->server = qemu_mallocz(sizeof(*vd->server)); |
... | ... | |
642 | 672 |
return 1; |
643 | 673 |
} |
644 | 674 |
|
645 |
static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
|
675 |
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
|
646 | 676 |
{ |
647 | 677 |
int n = 0; |
648 | 678 |
|
... | ... | |
671 | 701 |
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) |
672 | 702 |
{ |
673 | 703 |
/* send bitblit op to the vnc client */ |
704 |
vnc_lock_output(vs); |
|
674 | 705 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
675 | 706 |
vnc_write_u8(vs, 0); |
676 | 707 |
vnc_write_u16(vs, 1); /* number of rects */ |
677 | 708 |
vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT); |
678 | 709 |
vnc_write_u16(vs, src_x); |
679 | 710 |
vnc_write_u16(vs, src_y); |
711 |
vnc_unlock_output(vs); |
|
680 | 712 |
vnc_flush(vs); |
681 | 713 |
} |
682 | 714 |
|
... | ... | |
693 | 725 |
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { |
694 | 726 |
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { |
695 | 727 |
vs->force_update = 1; |
696 |
vnc_update_client(vs, 1); |
|
728 |
vnc_update_client_sync(vs, 1);
|
|
697 | 729 |
/* vs might be free()ed here */ |
698 | 730 |
} |
699 | 731 |
} |
... | ... | |
813 | 845 |
return h; |
814 | 846 |
} |
815 | 847 |
|
848 |
#ifdef CONFIG_VNC_THREAD |
|
849 |
static int vnc_update_client_sync(VncState *vs, int has_dirty) |
|
850 |
{ |
|
851 |
int ret = vnc_update_client(vs, has_dirty); |
|
852 |
vnc_jobs_join(vs); |
|
853 |
return ret; |
|
854 |
} |
|
855 |
#else |
|
856 |
static int vnc_update_client_sync(VncState *vs, int has_dirty) |
|
857 |
{ |
|
858 |
return vnc_update_client(vs, has_dirty); |
|
859 |
} |
|
860 |
#endif |
|
861 |
|
|
816 | 862 |
static int vnc_update_client(VncState *vs, int has_dirty) |
817 | 863 |
{ |
818 | 864 |
if (vs->need_update && vs->csock != -1) { |
819 | 865 |
VncDisplay *vd = vs->vd; |
866 |
VncJob *job; |
|
820 | 867 |
int y; |
821 |
int n_rectangles; |
|
822 |
int saved_offset; |
|
823 | 868 |
int width, height; |
824 |
int n; |
|
869 |
int n = 0; |
|
870 |
|
|
825 | 871 |
|
826 | 872 |
if (vs->output.offset && !vs->audio_cap && !vs->force_update) |
827 | 873 |
/* kernel send buffers are full -> drop frames to throttle */ |
... | ... | |
836 | 882 |
* happening in parallel don't disturb us, the next pass will |
837 | 883 |
* send them to the client. |
838 | 884 |
*/ |
839 |
n_rectangles = 0; |
|
840 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
|
841 |
vnc_write_u8(vs, 0); |
|
842 |
saved_offset = vs->output.offset; |
|
843 |
vnc_write_u16(vs, 0); |
|
885 |
job = vnc_job_new(vs); |
|
844 | 886 |
|
845 | 887 |
width = MIN(vd->server->width, vs->client_width); |
846 | 888 |
height = MIN(vd->server->height, vs->client_height); |
... | ... | |
857 | 899 |
} else { |
858 | 900 |
if (last_x != -1) { |
859 | 901 |
int h = find_and_clear_dirty_height(vs, y, last_x, x); |
860 |
n = send_framebuffer_update(vs, last_x * 16, y, |
|
861 |
(x - last_x) * 16, h);
|
|
862 |
n_rectangles += n;
|
|
902 |
|
|
903 |
n += vnc_job_add_rect(job, last_x * 16, y,
|
|
904 |
(x - last_x) * 16, h);
|
|
863 | 905 |
} |
864 | 906 |
last_x = -1; |
865 | 907 |
} |
866 | 908 |
} |
867 | 909 |
if (last_x != -1) { |
868 | 910 |
int h = find_and_clear_dirty_height(vs, y, last_x, x); |
869 |
n = send_framebuffer_update(vs, last_x * 16, y, |
|
870 |
(x - last_x) * 16, h); |
|
871 |
n_rectangles += n; |
|
911 |
n += vnc_job_add_rect(job, last_x * 16, y, |
|
912 |
(x - last_x) * 16, h); |
|
872 | 913 |
} |
873 | 914 |
} |
874 |
vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; |
|
875 |
vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; |
|
876 |
vnc_flush(vs); |
|
915 |
|
|
916 |
vnc_job_push(job); |
|
877 | 917 |
vs->force_update = 0; |
878 |
return n_rectangles;
|
|
918 |
return n; |
|
879 | 919 |
} |
880 | 920 |
|
881 | 921 |
if (vs->csock == -1) |
... | ... | |
891 | 931 |
|
892 | 932 |
switch (cmd) { |
893 | 933 |
case AUD_CNOTIFY_DISABLE: |
934 |
vnc_lock_output(vs); |
|
894 | 935 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); |
895 | 936 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); |
896 | 937 |
vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END); |
938 |
vnc_unlock_output(vs); |
|
897 | 939 |
vnc_flush(vs); |
898 | 940 |
break; |
899 | 941 |
|
900 | 942 |
case AUD_CNOTIFY_ENABLE: |
943 |
vnc_lock_output(vs); |
|
901 | 944 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); |
902 | 945 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); |
903 | 946 |
vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN); |
947 |
vnc_unlock_output(vs); |
|
904 | 948 |
vnc_flush(vs); |
905 | 949 |
break; |
906 | 950 |
} |
... | ... | |
914 | 958 |
{ |
915 | 959 |
VncState *vs = opaque; |
916 | 960 |
|
961 |
vnc_lock_output(vs); |
|
917 | 962 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); |
918 | 963 |
vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); |
919 | 964 |
vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); |
920 | 965 |
vnc_write_u32(vs, size); |
921 | 966 |
vnc_write(vs, buf, size); |
967 |
vnc_unlock_output(vs); |
|
922 | 968 |
vnc_flush(vs); |
923 | 969 |
} |
924 | 970 |
|
... | ... | |
960 | 1006 |
|
961 | 1007 |
static void vnc_disconnect_finish(VncState *vs) |
962 | 1008 |
{ |
1009 |
vnc_jobs_join(vs); /* Wait encoding jobs */ |
|
1010 |
|
|
1011 |
vnc_lock_output(vs); |
|
963 | 1012 |
vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED); |
964 | 1013 |
|
965 | 1014 |
buffer_free(&vs->input); |
... | ... | |
988 | 1037 |
vnc_remove_timer(vs->vd); |
989 | 1038 |
if (vs->vd->lock_key_sync) |
990 | 1039 |
qemu_remove_led_event_handler(vs->led); |
1040 |
vnc_unlock_output(vs); |
|
1041 |
|
|
1042 |
#ifdef CONFIG_VNC_THREAD |
|
1043 |
qemu_mutex_destroy(&vs->output_mutex); |
|
1044 |
#endif |
|
991 | 1045 |
qemu_free(vs); |
992 | 1046 |
} |
993 | 1047 |
|
... | ... | |
1107 | 1161 |
* the client socket. Will delegate actual work according to whether |
1108 | 1162 |
* SASL SSF layers are enabled (thus requiring encryption calls) |
1109 | 1163 |
*/ |
1110 |
void vnc_client_write(void *opaque)
|
|
1164 |
static void vnc_client_write_locked(void *opaque)
|
|
1111 | 1165 |
{ |
1112 | 1166 |
VncState *vs = opaque; |
1113 | 1167 |
|
... | ... | |
1121 | 1175 |
vnc_client_write_plain(vs); |
1122 | 1176 |
} |
1123 | 1177 |
|
1178 |
void vnc_client_write(void *opaque) |
|
1179 |
{ |
|
1180 |
VncState *vs = opaque; |
|
1181 |
|
|
1182 |
vnc_lock_output(vs); |
|
1183 |
if (vs->output.offset) { |
|
1184 |
vnc_client_write_locked(opaque); |
|
1185 |
} else { |
|
1186 |
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); |
|
1187 |
} |
|
1188 |
vnc_unlock_output(vs); |
|
1189 |
} |
|
1190 |
|
|
1124 | 1191 |
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) |
1125 | 1192 |
{ |
1126 | 1193 |
vs->read_handler = func; |
... | ... | |
1272 | 1339 |
|
1273 | 1340 |
void vnc_flush(VncState *vs) |
1274 | 1341 |
{ |
1275 |
if (vs->csock != -1 && vs->output.offset) |
|
1276 |
vnc_client_write(vs); |
|
1342 |
vnc_lock_output(vs); |
|
1343 |
if (vs->csock != -1 && vs->output.offset) { |
|
1344 |
vnc_client_write_locked(vs); |
|
1345 |
} |
|
1346 |
vnc_unlock_output(vs); |
|
1277 | 1347 |
} |
1278 | 1348 |
|
1279 | 1349 |
uint8_t read_u8(uint8_t *data, size_t offset) |
... | ... | |
1308 | 1378 |
int absolute = kbd_mouse_is_absolute(); |
1309 | 1379 |
|
1310 | 1380 |
if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { |
1381 |
vnc_lock_output(vs); |
|
1311 | 1382 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
1312 | 1383 |
vnc_write_u8(vs, 0); |
1313 | 1384 |
vnc_write_u16(vs, 1); |
1314 | 1385 |
vnc_framebuffer_update(vs, absolute, 0, |
1315 | 1386 |
ds_get_width(vs->ds), ds_get_height(vs->ds), |
1316 | 1387 |
VNC_ENCODING_POINTER_TYPE_CHANGE); |
1388 |
vnc_unlock_output(vs); |
|
1317 | 1389 |
vnc_flush(vs); |
1318 | 1390 |
} |
1319 | 1391 |
vs->absolute = absolute; |
... | ... | |
1617 | 1689 |
|
1618 | 1690 |
static void send_ext_key_event_ack(VncState *vs) |
1619 | 1691 |
{ |
1692 |
vnc_lock_output(vs); |
|
1620 | 1693 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
1621 | 1694 |
vnc_write_u8(vs, 0); |
1622 | 1695 |
vnc_write_u16(vs, 1); |
1623 | 1696 |
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), |
1624 | 1697 |
VNC_ENCODING_EXT_KEY_EVENT); |
1698 |
vnc_unlock_output(vs); |
|
1625 | 1699 |
vnc_flush(vs); |
1626 | 1700 |
} |
1627 | 1701 |
|
1628 | 1702 |
static void send_ext_audio_ack(VncState *vs) |
1629 | 1703 |
{ |
1704 |
vnc_lock_output(vs); |
|
1630 | 1705 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
1631 | 1706 |
vnc_write_u8(vs, 0); |
1632 | 1707 |
vnc_write_u16(vs, 1); |
1633 | 1708 |
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), |
1634 | 1709 |
VNC_ENCODING_AUDIO); |
1710 |
vnc_unlock_output(vs); |
|
1635 | 1711 |
vnc_flush(vs); |
1636 | 1712 |
} |
1637 | 1713 |
|
... | ... | |
1794 | 1870 |
{ |
1795 | 1871 |
if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { |
1796 | 1872 |
/* Sending a WMVi message to notify the client*/ |
1873 |
vnc_lock_output(vs); |
|
1797 | 1874 |
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); |
1798 | 1875 |
vnc_write_u8(vs, 0); |
1799 | 1876 |
vnc_write_u16(vs, 1); /* number of rects */ |
1800 | 1877 |
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), |
1801 | 1878 |
ds_get_height(vs->ds), VNC_ENCODING_WMVi); |
1802 | 1879 |
pixel_format_message(vs); |
1880 |
vnc_unlock_output(vs); |
|
1803 | 1881 |
vnc_flush(vs); |
1804 | 1882 |
} else { |
1805 | 1883 |
set_pixel_conversion(vs); |
... | ... | |
2227 | 2305 |
|
2228 | 2306 |
vga_hw_update(); |
2229 | 2307 |
|
2308 |
if (vnc_trylock_display(vd)) { |
|
2309 |
vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; |
|
2310 |
qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + |
|
2311 |
vd->timer_interval); |
|
2312 |
return; |
|
2313 |
} |
|
2314 |
|
|
2230 | 2315 |
has_dirty = vnc_refresh_server_surface(vd); |
2316 |
vnc_unlock_display(vd); |
|
2231 | 2317 |
|
2232 | 2318 |
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { |
2233 | 2319 |
rects += vnc_update_client(vs, has_dirty); |
2234 | 2320 |
/* vs might be free()ed here */ |
2235 | 2321 |
} |
2322 |
|
|
2236 | 2323 |
/* vd->timer could be NULL now if the last client disconnected, |
2237 | 2324 |
* in this case don't update the timer */ |
2238 | 2325 |
if (vd->timer == NULL) |
... | ... | |
2291 | 2378 |
vs->as.fmt = AUD_FMT_S16; |
2292 | 2379 |
vs->as.endianness = 0; |
2293 | 2380 |
|
2381 |
#ifdef CONFIG_VNC_THREAD |
|
2382 |
qemu_mutex_init(&vs->output_mutex); |
|
2383 |
#endif |
|
2384 |
|
|
2294 | 2385 |
QTAILQ_INSERT_HEAD(&vd->clients, vs, next); |
2295 | 2386 |
|
2296 | 2387 |
vga_hw_update(); |
... | ... | |
2348 | 2439 |
if (!vs->kbd_layout) |
2349 | 2440 |
exit(1); |
2350 | 2441 |
|
2442 |
#ifdef CONFIG_VNC_THREAD |
|
2443 |
qemu_mutex_init(&vs->mutex); |
|
2444 |
vnc_start_worker_thread(); |
|
2445 |
#endif |
|
2446 |
|
|
2351 | 2447 |
dcl->dpy_copy = vnc_dpy_copy; |
2352 | 2448 |
dcl->dpy_update = vnc_dpy_update; |
2353 | 2449 |
dcl->dpy_resize = vnc_dpy_resize; |
b/ui/vnc.h | ||
---|---|---|
29 | 29 |
|
30 | 30 |
#include "qemu-common.h" |
31 | 31 |
#include "qemu-queue.h" |
32 |
#ifdef CONFIG_VNC_THREAD |
|
33 |
#include "qemu-thread.h" |
|
34 |
#endif |
|
32 | 35 |
#include "console.h" |
33 | 36 |
#include "monitor.h" |
34 | 37 |
#include "audio/audio.h" |
... | ... | |
59 | 62 |
} Buffer; |
60 | 63 |
|
61 | 64 |
typedef struct VncState VncState; |
65 |
typedef struct VncJob VncJob; |
|
66 |
typedef struct VncRect VncRect; |
|
67 |
typedef struct VncRectEntry VncRectEntry; |
|
62 | 68 |
|
63 | 69 |
typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); |
64 | 70 |
|
... | ... | |
101 | 107 |
DisplayState *ds; |
102 | 108 |
kbd_layout_t *kbd_layout; |
103 | 109 |
int lock_key_sync; |
110 |
#ifdef CONFIG_VNC_THREAD |
|
111 |
QemuMutex mutex; |
|
112 |
#endif |
|
104 | 113 |
|
105 | 114 |
QEMUCursor *cursor; |
106 | 115 |
int cursor_msize; |
... | ... | |
152 | 161 |
int level; |
153 | 162 |
} VncZlib; |
154 | 163 |
|
164 |
#ifdef CONFIG_VNC_THREAD |
|
165 |
struct VncRect |
|
166 |
{ |
|
167 |
int x; |
|
168 |
int y; |
|
169 |
int w; |
|
170 |
int h; |
|
171 |
}; |
|
172 |
|
|
173 |
struct VncRectEntry |
|
174 |
{ |
|
175 |
struct VncRect rect; |
|
176 |
QLIST_ENTRY(VncRectEntry) next; |
|
177 |
}; |
|
178 |
|
|
179 |
struct VncJob |
|
180 |
{ |
|
181 |
VncState *vs; |
|
182 |
|
|
183 |
QLIST_HEAD(, VncRectEntry) rectangles; |
|
184 |
QTAILQ_ENTRY(VncJob) next; |
|
185 |
}; |
|
186 |
#else |
|
187 |
struct VncJob |
|
188 |
{ |
|
189 |
VncState *vs; |
|
190 |
int rectangles; |
|
191 |
size_t saved_offset; |
|
192 |
}; |
|
193 |
#endif |
|
194 |
|
|
155 | 195 |
struct VncState |
156 | 196 |
{ |
157 | 197 |
int csock; |
... | ... | |
199 | 239 |
uint8_t modifiers_state[256]; |
200 | 240 |
QEMUPutLEDEntry *led; |
201 | 241 |
|
202 |
/* Encoding specific */ |
|
242 |
bool abort; |
|
243 |
#ifndef CONFIG_VNC_THREAD |
|
244 |
VncJob job; |
|
245 |
#else |
|
246 |
QemuMutex output_mutex; |
|
247 |
#endif |
|
248 |
|
|
249 |
/* Encoding specific, if you add something here, don't forget to |
|
250 |
* update vnc_async_encoding_start() |
|
251 |
*/ |
|
203 | 252 |
VncTight tight; |
204 | 253 |
VncZlib zlib; |
205 | 254 |
VncHextile hextile; |
... | ... | |
431 | 480 |
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v); |
432 | 481 |
|
433 | 482 |
/* Encodings */ |
483 |
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); |
|
484 |
|
|
434 | 485 |
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); |
435 | 486 |
|
436 | 487 |
int vnc_hextile_send_framebuffer_update(VncState *vs, int x, |
Also available in: Unified diff