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
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.
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.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 /* #define WITH_DEBUG_SEAMLESS */
27 #ifdef WITH_DEBUG_SEAMLESS
28 #define DEBUG_SEAMLESS(args) printf args;
30 #define DEBUG_SEAMLESS(args)
34 seamless_get_token(char **s
)
42 comma
= strchr(head
, ',');
58 seamless_process_line(RDPCLIENT
* This
, const char *line
, void *data
)
61 char *tok1
, *tok2
, *tok3
, *tok4
, *tok5
, *tok6
, *tok7
, *tok8
;
62 unsigned long id
, flags
;
68 DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p
));
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
);
79 if (!strcmp("CREATE", tok1
))
81 unsigned long group
, parent
;
85 id
= strtoul(tok3
, &endptr
, 0);
89 group
= strtoul(tok4
, &endptr
, 0);
93 parent
= strtoul(tok5
, &endptr
, 0);
97 flags
= strtoul(tok6
, &endptr
, 0);
101 ui_seamless_create_window(This
, id
, group
, parent
, flags
);
103 else if (!strcmp("DESTROY", tok1
))
108 id
= strtoul(tok3
, &endptr
, 0);
112 flags
= strtoul(tok4
, &endptr
, 0);
116 ui_seamless_destroy_window(This
, id
, flags
);
119 else if (!strcmp("DESTROYGRP", tok1
))
124 id
= strtoul(tok3
, &endptr
, 0);
128 flags
= strtoul(tok4
, &endptr
, 0);
132 ui_seamless_destroy_group(This
, id
, flags
);
134 else if (!strcmp("SETICON", tok1
))
136 unimpl("SeamlessRDP SETICON1\n");
138 else if (!strcmp("POSITION", tok1
))
140 int x
, y
, width
, height
;
145 id
= strtoul(tok3
, &endptr
, 0);
149 x
= strtol(tok4
, &endptr
, 0);
152 y
= strtol(tok5
, &endptr
, 0);
156 width
= strtol(tok6
, &endptr
, 0);
159 height
= strtol(tok7
, &endptr
, 0);
163 flags
= strtoul(tok8
, &endptr
, 0);
167 ui_seamless_move_window(This
, id
, x
, y
, width
, height
, flags
);
169 else if (!strcmp("ZCHANGE", tok1
))
171 unsigned long behind
;
173 id
= strtoul(tok3
, &endptr
, 0);
177 behind
= strtoul(tok4
, &endptr
, 0);
181 flags
= strtoul(tok5
, &endptr
, 0);
185 ui_seamless_restack_window(This
, id
, behind
, flags
);
187 else if (!strcmp("TITLE", tok1
))
192 id
= strtoul(tok3
, &endptr
, 0);
196 flags
= strtoul(tok5
, &endptr
, 0);
200 ui_seamless_settitle(This
, id
, tok4
, flags
);
202 else if (!strcmp("STATE", tok1
))
209 id
= strtoul(tok3
, &endptr
, 0);
213 state
= strtoul(tok4
, &endptr
, 0);
217 flags
= strtoul(tok5
, &endptr
, 0);
221 ui_seamless_setstate(This
, id
, state
, flags
);
223 else if (!strcmp("DEBUG", tok1
))
225 DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line
));
227 else if (!strcmp("SYNCBEGIN", tok1
))
232 flags
= strtoul(tok3
, &endptr
, 0);
236 ui_seamless_syncbegin(This
, flags
);
238 else if (!strcmp("SYNCEND", tok1
))
243 flags
= strtoul(tok3
, &endptr
, 0);
247 /* do nothing, currently */
249 else if (!strcmp("HELLO", tok1
))
254 flags
= strtoul(tok3
, &endptr
, 0);
258 ui_seamless_begin(This
, !!(flags
& SEAMLESSRDP_HELLO_HIDDEN
));
260 else if (!strcmp("ACK", tok1
))
264 serial
= strtoul(tok3
, &endptr
, 0);
268 ui_seamless_ack(This
, serial
);
270 else if (!strcmp("HIDE", tok1
))
275 flags
= strtoul(tok3
, &endptr
, 0);
279 ui_seamless_hide_desktop(This
);
281 else if (!strcmp("UNHIDE", tok1
))
286 flags
= strtoul(tok3
, &endptr
, 0);
290 ui_seamless_unhide_desktop(This
);
300 seamless_line_handler(RDPCLIENT
* This
, const char *line
, void *data
)
302 if (!seamless_process_line(This
, line
, data
))
304 warning("SeamlessRDP: Invalid request:%s\n", line
);
311 seamless_process(RDPCLIENT
* This
, STREAM s
)
314 static char *rest
= NULL
;
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);
322 printf("seamless recv:\n");
323 hexdump(s
->p
, pkglen
);
326 str_handle_lines(This
, buf
, &rest
, seamless_line_handler
, NULL
);
333 seamless_init(RDPCLIENT
* This
)
335 if (!This
->seamless_rdp
)
338 This
->seamless
.serial
= 0;
340 This
->seamless
.channel
=
341 channel_register(This
, "seamrdp", CHANNEL_OPTION_INITIALIZED
| CHANNEL_OPTION_ENCRYPT_RDP
,
343 return (This
->seamless
.channel
!= NULL
);
348 seamless_send(RDPCLIENT
* This
, const char *command
, const char *format
, ...)
355 len
= snprintf(buf
, sizeof(buf
) - 1, "%s,%u,", command
, This
->seamless
.serial
);
357 assert(len
< (sizeof(buf
) - 1));
359 va_start(argp
, format
);
360 len
+= vsnprintf(buf
+ len
, sizeof(buf
) - len
- 1, format
, argp
);
363 assert(len
< (sizeof(buf
) - 1));
370 s
= channel_init(This
, This
->seamless
.channel
, len
);
371 out_uint8p(s
, buf
, len
) s_mark_end(s
);
373 DEBUG_SEAMLESS(("SeamlessRDP sending:%s", buf
));
376 printf("seamless send:\n");
377 hexdump(s
->channel_hdr
+ 8, s
->end
- s
->channel_hdr
- 8);
380 channel_send(This
, s
, This
->seamless
.channel
);
382 return This
->seamless
.serial
++;
387 seamless_send_sync(RDPCLIENT
* This
)
389 if (!This
->seamless_rdp
)
390 return (unsigned int) -1;
392 return seamless_send(This
, "SYNC", "");
397 seamless_send_state(RDPCLIENT
* This
, unsigned long id
, unsigned int state
, unsigned long flags
)
399 if (!This
->seamless_rdp
)
400 return (unsigned int) -1;
402 return seamless_send(This
, "STATE", "0x%08lx,0x%x,0x%lx", id
, state
, flags
);
407 seamless_send_position(RDPCLIENT
* This
, unsigned long id
, int x
, int y
, int width
, int height
, unsigned long flags
)
409 return seamless_send(This
, "POSITION", "0x%08lx,%d,%d,%d,%d,0x%lx", id
, x
, y
, width
, height
,
414 /* Update select timeout */
416 seamless_select_timeout(RDPCLIENT
* This
, struct timeval
*tv
)
418 struct timeval ourtimeout
= { 0, SEAMLESSRDP_POSITION_TIMER
};
420 if (This
->seamless_rdp
)
422 if (timercmp(&ourtimeout
, tv
, <))
424 tv
->tv_sec
= ourtimeout
.tv_sec
;
425 tv
->tv_usec
= ourtimeout
.tv_usec
;
432 seamless_send_zchange(RDPCLIENT
* This
, unsigned long id
, unsigned long below
, unsigned long flags
)
434 if (!This
->seamless_rdp
)
435 return (unsigned int) -1;
437 return seamless_send(This
, "ZCHANGE", "0x%08lx,0x%08lx,0x%lx", id
, below
, flags
);
443 seamless_send_focus(RDPCLIENT
* This
, unsigned long id
, unsigned long flags
)
445 if (!This
->seamless_rdp
)
446 return (unsigned int) -1;
448 return seamless_send(This
, "FOCUS", "0x%08lx,0x%lx", id
, flags
);