Implement some functions that are forwarded to HAL on x86 build, but not on x64....
[reactos.git] / reactos / base / applications / tsclient / rdesktop / seamless.c
1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Seamless Windows support
4 Copyright (C) Peter Astrand <astrand@cendio.se> 2005-2006
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "rdesktop.h"
22 #include <stdarg.h>
23 #include <assert.h>
24
25 /* #define WITH_DEBUG_SEAMLESS */
26
27 #ifdef WITH_DEBUG_SEAMLESS
28 #define DEBUG_SEAMLESS(args) printf args;
29 #else
30 #define DEBUG_SEAMLESS(args)
31 #endif
32
33 static char *
34 seamless_get_token(char **s)
35 {
36 char *comma, *head;
37 head = *s;
38
39 if (!head)
40 return NULL;
41
42 comma = strchr(head, ',');
43 if (comma)
44 {
45 *comma = '\0';
46 *s = comma + 1;
47 }
48 else
49 {
50 *s = NULL;
51 }
52
53 return head;
54 }
55
56
57 static BOOL
58 seamless_process_line(RDPCLIENT * This, const char *line, void *data)
59 {
60 char *p, *l;
61 char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
62 unsigned long id, flags;
63 char *endptr;
64
65 l = xstrdup(line);
66 p = l;
67
68 DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p));
69
70 tok1 = seamless_get_token(&p);
71 tok2 = seamless_get_token(&p);
72 tok3 = seamless_get_token(&p);
73 tok4 = seamless_get_token(&p);
74 tok5 = seamless_get_token(&p);
75 tok6 = seamless_get_token(&p);
76 tok7 = seamless_get_token(&p);
77 tok8 = seamless_get_token(&p);
78
79 if (!strcmp("CREATE", tok1))
80 {
81 unsigned long group, parent;
82 if (!tok6)
83 return False;
84
85 id = strtoul(tok3, &endptr, 0);
86 if (*endptr)
87 return False;
88
89 group = strtoul(tok4, &endptr, 0);
90 if (*endptr)
91 return False;
92
93 parent = strtoul(tok5, &endptr, 0);
94 if (*endptr)
95 return False;
96
97 flags = strtoul(tok6, &endptr, 0);
98 if (*endptr)
99 return False;
100
101 ui_seamless_create_window(This, id, group, parent, flags);
102 }
103 else if (!strcmp("DESTROY", tok1))
104 {
105 if (!tok4)
106 return False;
107
108 id = strtoul(tok3, &endptr, 0);
109 if (*endptr)
110 return False;
111
112 flags = strtoul(tok4, &endptr, 0);
113 if (*endptr)
114 return False;
115
116 ui_seamless_destroy_window(This, id, flags);
117
118 }
119 else if (!strcmp("DESTROYGRP", tok1))
120 {
121 if (!tok4)
122 return False;
123
124 id = strtoul(tok3, &endptr, 0);
125 if (*endptr)
126 return False;
127
128 flags = strtoul(tok4, &endptr, 0);
129 if (*endptr)
130 return False;
131
132 ui_seamless_destroy_group(This, id, flags);
133 }
134 else if (!strcmp("SETICON", tok1))
135 {
136 unimpl("SeamlessRDP SETICON1\n");
137 }
138 else if (!strcmp("POSITION", tok1))
139 {
140 int x, y, width, height;
141
142 if (!tok8)
143 return False;
144
145 id = strtoul(tok3, &endptr, 0);
146 if (*endptr)
147 return False;
148
149 x = strtol(tok4, &endptr, 0);
150 if (*endptr)
151 return False;
152 y = strtol(tok5, &endptr, 0);
153 if (*endptr)
154 return False;
155
156 width = strtol(tok6, &endptr, 0);
157 if (*endptr)
158 return False;
159 height = strtol(tok7, &endptr, 0);
160 if (*endptr)
161 return False;
162
163 flags = strtoul(tok8, &endptr, 0);
164 if (*endptr)
165 return False;
166
167 ui_seamless_move_window(This, id, x, y, width, height, flags);
168 }
169 else if (!strcmp("ZCHANGE", tok1))
170 {
171 unsigned long behind;
172
173 id = strtoul(tok3, &endptr, 0);
174 if (*endptr)
175 return False;
176
177 behind = strtoul(tok4, &endptr, 0);
178 if (*endptr)
179 return False;
180
181 flags = strtoul(tok5, &endptr, 0);
182 if (*endptr)
183 return False;
184
185 ui_seamless_restack_window(This, id, behind, flags);
186 }
187 else if (!strcmp("TITLE", tok1))
188 {
189 if (!tok5)
190 return False;
191
192 id = strtoul(tok3, &endptr, 0);
193 if (*endptr)
194 return False;
195
196 flags = strtoul(tok5, &endptr, 0);
197 if (*endptr)
198 return False;
199
200 ui_seamless_settitle(This, id, tok4, flags);
201 }
202 else if (!strcmp("STATE", tok1))
203 {
204 unsigned int state;
205
206 if (!tok5)
207 return False;
208
209 id = strtoul(tok3, &endptr, 0);
210 if (*endptr)
211 return False;
212
213 state = strtoul(tok4, &endptr, 0);
214 if (*endptr)
215 return False;
216
217 flags = strtoul(tok5, &endptr, 0);
218 if (*endptr)
219 return False;
220
221 ui_seamless_setstate(This, id, state, flags);
222 }
223 else if (!strcmp("DEBUG", tok1))
224 {
225 DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line));
226 }
227 else if (!strcmp("SYNCBEGIN", tok1))
228 {
229 if (!tok3)
230 return False;
231
232 flags = strtoul(tok3, &endptr, 0);
233 if (*endptr)
234 return False;
235
236 ui_seamless_syncbegin(This, flags);
237 }
238 else if (!strcmp("SYNCEND", tok1))
239 {
240 if (!tok3)
241 return False;
242
243 flags = strtoul(tok3, &endptr, 0);
244 if (*endptr)
245 return False;
246
247 /* do nothing, currently */
248 }
249 else if (!strcmp("HELLO", tok1))
250 {
251 if (!tok3)
252 return False;
253
254 flags = strtoul(tok3, &endptr, 0);
255 if (*endptr)
256 return False;
257
258 ui_seamless_begin(This, !!(flags & SEAMLESSRDP_HELLO_HIDDEN));
259 }
260 else if (!strcmp("ACK", tok1))
261 {
262 unsigned int serial;
263
264 serial = strtoul(tok3, &endptr, 0);
265 if (*endptr)
266 return False;
267
268 ui_seamless_ack(This, serial);
269 }
270 else if (!strcmp("HIDE", tok1))
271 {
272 if (!tok3)
273 return False;
274
275 flags = strtoul(tok3, &endptr, 0);
276 if (*endptr)
277 return False;
278
279 ui_seamless_hide_desktop(This);
280 }
281 else if (!strcmp("UNHIDE", tok1))
282 {
283 if (!tok3)
284 return False;
285
286 flags = strtoul(tok3, &endptr, 0);
287 if (*endptr)
288 return False;
289
290 ui_seamless_unhide_desktop(This);
291 }
292
293
294 xfree(l);
295 return True;
296 }
297
298
299 static BOOL
300 seamless_line_handler(RDPCLIENT * This, const char *line, void *data)
301 {
302 if (!seamless_process_line(This, line, data))
303 {
304 warning("SeamlessRDP: Invalid request:%s\n", line);
305 }
306 return True;
307 }
308
309
310 static void
311 seamless_process(RDPCLIENT * This, STREAM s)
312 {
313 unsigned int pkglen;
314 static char *rest = NULL;
315 char *buf;
316
317 pkglen = s->end - s->p;
318 /* str_handle_lines requires null terminated strings */
319 buf = xmalloc(pkglen + 1);
320 STRNCPY(buf, (char *) s->p, pkglen + 1);
321 #if 0
322 printf("seamless recv:\n");
323 hexdump(s->p, pkglen);
324 #endif
325
326 str_handle_lines(This, buf, &rest, seamless_line_handler, NULL);
327
328 xfree(buf);
329 }
330
331
332 BOOL
333 seamless_init(RDPCLIENT * This)
334 {
335 if (!This->seamless_rdp)
336 return False;
337
338 This->seamless.serial = 0;
339
340 This->seamless.channel =
341 channel_register(This, "seamrdp", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
342 seamless_process);
343 return (This->seamless.channel != NULL);
344 }
345
346
347 static unsigned int
348 seamless_send(RDPCLIENT * This, const char *command, const char *format, ...)
349 {
350 STREAM s;
351 size_t len;
352 va_list argp;
353 char buf[1025];
354
355 len = snprintf(buf, sizeof(buf) - 1, "%s,%u,", command, This->seamless.serial);
356
357 assert(len < (sizeof(buf) - 1));
358
359 va_start(argp, format);
360 len += vsnprintf(buf + len, sizeof(buf) - len - 1, format, argp);
361 va_end(argp);
362
363 assert(len < (sizeof(buf) - 1));
364
365 buf[len] = '\n';
366 buf[len + 1] = '\0';
367
368 len++;
369
370 s = channel_init(This, This->seamless.channel, len);
371 out_uint8p(s, buf, len) s_mark_end(s);
372
373 DEBUG_SEAMLESS(("SeamlessRDP sending:%s", buf));
374
375 #if 0
376 printf("seamless send:\n");
377 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
378 #endif
379
380 channel_send(This, s, This->seamless.channel);
381
382 return This->seamless.serial++;
383 }
384
385
386 unsigned int
387 seamless_send_sync(RDPCLIENT * This)
388 {
389 if (!This->seamless_rdp)
390 return (unsigned int) -1;
391
392 return seamless_send(This, "SYNC", "");
393 }
394
395
396 unsigned int
397 seamless_send_state(RDPCLIENT * This, unsigned long id, unsigned int state, unsigned long flags)
398 {
399 if (!This->seamless_rdp)
400 return (unsigned int) -1;
401
402 return seamless_send(This, "STATE", "0x%08lx,0x%x,0x%lx", id, state, flags);
403 }
404
405
406 unsigned int
407 seamless_send_position(RDPCLIENT * This, unsigned long id, int x, int y, int width, int height, unsigned long flags)
408 {
409 return seamless_send(This, "POSITION", "0x%08lx,%d,%d,%d,%d,0x%lx", id, x, y, width, height,
410 flags);
411 }
412
413
414 /* Update select timeout */
415 void
416 seamless_select_timeout(RDPCLIENT * This, struct timeval *tv)
417 {
418 struct timeval ourtimeout = { 0, SEAMLESSRDP_POSITION_TIMER };
419
420 if (This->seamless_rdp)
421 {
422 if (timercmp(&ourtimeout, tv, <))
423 {
424 tv->tv_sec = ourtimeout.tv_sec;
425 tv->tv_usec = ourtimeout.tv_usec;
426 }
427 }
428 }
429
430
431 unsigned int
432 seamless_send_zchange(RDPCLIENT * This, unsigned long id, unsigned long below, unsigned long flags)
433 {
434 if (!This->seamless_rdp)
435 return (unsigned int) -1;
436
437 return seamless_send(This, "ZCHANGE", "0x%08lx,0x%08lx,0x%lx", id, below, flags);
438 }
439
440
441
442 unsigned int
443 seamless_send_focus(RDPCLIENT * This, unsigned long id, unsigned long flags)
444 {
445 if (!This->seamless_rdp)
446 return (unsigned int) -1;
447
448 return seamless_send(This, "FOCUS", "0x%08lx,0x%lx", id, flags);
449 }