Move tsclient to rosapps (not included in build process and superseded by Geds mstsc...
[reactos.git] / rosapps / applications / net / tsclient / rdesktop / seamless.c
diff --git a/rosapps/applications/net/tsclient/rdesktop/seamless.c b/rosapps/applications/net/tsclient/rdesktop/seamless.c
new file mode 100644 (file)
index 0000000..20f7d2e
--- /dev/null
@@ -0,0 +1,449 @@
+/* -*- c-basic-offset: 8 -*-
+   rdesktop: A Remote Desktop Protocol client.
+   Seamless Windows support
+   Copyright (C) Peter Astrand <astrand@cendio.se> 2005-2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "rdesktop.h"
+#include <stdarg.h>
+#include <assert.h>
+
+/* #define WITH_DEBUG_SEAMLESS */
+
+#ifdef WITH_DEBUG_SEAMLESS
+#define DEBUG_SEAMLESS(args) printf args;
+#else
+#define DEBUG_SEAMLESS(args)
+#endif
+
+static char *
+seamless_get_token(char **s)
+{
+       char *comma, *head;
+       head = *s;
+
+       if (!head)
+               return NULL;
+
+       comma = strchr(head, ',');
+       if (comma)
+       {
+               *comma = '\0';
+               *s = comma + 1;
+       }
+       else
+       {
+               *s = NULL;
+       }
+
+       return head;
+}
+
+
+static BOOL
+seamless_process_line(RDPCLIENT * This, const char *line, void *data)
+{
+       char *p, *l;
+       char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
+       unsigned long id, flags;
+       char *endptr;
+
+       l = xstrdup(line);
+       p = l;
+
+       DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p));
+
+       tok1 = seamless_get_token(&p);
+       tok2 = seamless_get_token(&p);
+       tok3 = seamless_get_token(&p);
+       tok4 = seamless_get_token(&p);
+       tok5 = seamless_get_token(&p);
+       tok6 = seamless_get_token(&p);
+       tok7 = seamless_get_token(&p);
+       tok8 = seamless_get_token(&p);
+
+       if (!strcmp("CREATE", tok1))
+       {
+               unsigned long group, parent;
+               if (!tok6)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               group = strtoul(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               parent = strtoul(tok5, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok6, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_create_window(This, id, group, parent, flags);
+       }
+       else if (!strcmp("DESTROY", tok1))
+       {
+               if (!tok4)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_destroy_window(This, id, flags);
+
+       }
+       else if (!strcmp("DESTROYGRP", tok1))
+       {
+               if (!tok4)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_destroy_group(This, id, flags);
+       }
+       else if (!strcmp("SETICON", tok1))
+       {
+               unimpl("SeamlessRDP SETICON1\n");
+       }
+       else if (!strcmp("POSITION", tok1))
+       {
+               int x, y, width, height;
+
+               if (!tok8)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               x = strtol(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+               y = strtol(tok5, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               width = strtol(tok6, &endptr, 0);
+               if (*endptr)
+                       return False;
+               height = strtol(tok7, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok8, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_move_window(This, id, x, y, width, height, flags);
+       }
+       else if (!strcmp("ZCHANGE", tok1))
+       {
+               unsigned long behind;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               behind = strtoul(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok5, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_restack_window(This, id, behind, flags);
+       }
+       else if (!strcmp("TITLE", tok1))
+       {
+               if (!tok5)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok5, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_settitle(This, id, tok4, flags);
+       }
+       else if (!strcmp("STATE", tok1))
+       {
+               unsigned int state;
+
+               if (!tok5)
+                       return False;
+
+               id = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               state = strtoul(tok4, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               flags = strtoul(tok5, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_setstate(This, id, state, flags);
+       }
+       else if (!strcmp("DEBUG", tok1))
+       {
+               DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line));
+       }
+       else if (!strcmp("SYNCBEGIN", tok1))
+       {
+               if (!tok3)
+                       return False;
+
+               flags = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_syncbegin(This, flags);
+       }
+       else if (!strcmp("SYNCEND", tok1))
+       {
+               if (!tok3)
+                       return False;
+
+               flags = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               /* do nothing, currently */
+       }
+       else if (!strcmp("HELLO", tok1))
+       {
+               if (!tok3)
+                       return False;
+
+               flags = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_begin(This, !!(flags & SEAMLESSRDP_HELLO_HIDDEN));
+       }
+       else if (!strcmp("ACK", tok1))
+       {
+               unsigned int serial;
+
+               serial = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_ack(This, serial);
+       }
+       else if (!strcmp("HIDE", tok1))
+       {
+               if (!tok3)
+                       return False;
+
+               flags = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_hide_desktop(This);
+       }
+       else if (!strcmp("UNHIDE", tok1))
+       {
+               if (!tok3)
+                       return False;
+
+               flags = strtoul(tok3, &endptr, 0);
+               if (*endptr)
+                       return False;
+
+               ui_seamless_unhide_desktop(This);
+       }
+
+
+       xfree(l);
+       return True;
+}
+
+
+static BOOL
+seamless_line_handler(RDPCLIENT * This, const char *line, void *data)
+{
+       if (!seamless_process_line(This, line, data))
+       {
+               warning("SeamlessRDP: Invalid request:%s\n", line);
+       }
+       return True;
+}
+
+
+static void
+seamless_process(RDPCLIENT * This, STREAM s)
+{
+       unsigned int pkglen;
+       static char *rest = NULL;
+       char *buf;
+
+       pkglen = s->end - s->p;
+       /* str_handle_lines requires null terminated strings */
+       buf = xmalloc(pkglen + 1);
+       STRNCPY(buf, (char *) s->p, pkglen + 1);
+#if 0
+       printf("seamless recv:\n");
+       hexdump(s->p, pkglen);
+#endif
+
+       str_handle_lines(This, buf, &rest, seamless_line_handler, NULL);
+
+       xfree(buf);
+}
+
+
+BOOL
+seamless_init(RDPCLIENT * This)
+{
+       if (!This->seamless_rdp)
+               return False;
+
+       This->seamless.serial = 0;
+
+       This->seamless.channel =
+               channel_register(This, "seamrdp", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
+                                seamless_process);
+       return (This->seamless.channel != NULL);
+}
+
+
+static unsigned int
+seamless_send(RDPCLIENT * This, const char *command, const char *format, ...)
+{
+       STREAM s;
+       size_t len;
+       va_list argp;
+       char buf[1025];
+
+       len = snprintf(buf, sizeof(buf) - 1, "%s,%u,", command, This->seamless.serial);
+
+       assert(len < (sizeof(buf) - 1));
+
+       va_start(argp, format);
+       len += vsnprintf(buf + len, sizeof(buf) - len - 1, format, argp);
+       va_end(argp);
+
+       assert(len < (sizeof(buf) - 1));
+
+       buf[len] = '\n';
+       buf[len + 1] = '\0';
+
+       len++;
+
+       s = channel_init(This, This->seamless.channel, len);
+       out_uint8p(s, buf, len) s_mark_end(s);
+
+       DEBUG_SEAMLESS(("SeamlessRDP sending:%s", buf));
+
+#if 0
+       printf("seamless send:\n");
+       hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
+#endif
+
+       channel_send(This, s, This->seamless.channel);
+
+       return This->seamless.serial++;
+}
+
+
+unsigned int
+seamless_send_sync(RDPCLIENT * This)
+{
+       if (!This->seamless_rdp)
+               return (unsigned int) -1;
+
+       return seamless_send(This, "SYNC", "");
+}
+
+
+unsigned int
+seamless_send_state(RDPCLIENT * This, unsigned long id, unsigned int state, unsigned long flags)
+{
+       if (!This->seamless_rdp)
+               return (unsigned int) -1;
+
+       return seamless_send(This, "STATE", "0x%08lx,0x%x,0x%lx", id, state, flags);
+}
+
+
+unsigned int
+seamless_send_position(RDPCLIENT * This, unsigned long id, int x, int y, int width, int height, unsigned long flags)
+{
+       return seamless_send(This, "POSITION", "0x%08lx,%d,%d,%d,%d,0x%lx", id, x, y, width, height,
+                            flags);
+}
+
+
+/* Update select timeout */
+void
+seamless_select_timeout(RDPCLIENT * This, struct timeval *tv)
+{
+       struct timeval ourtimeout = { 0, SEAMLESSRDP_POSITION_TIMER };
+
+       if (This->seamless_rdp)
+       {
+               if (timercmp(&ourtimeout, tv, <))
+               {
+                       tv->tv_sec = ourtimeout.tv_sec;
+                       tv->tv_usec = ourtimeout.tv_usec;
+               }
+       }
+}
+
+
+unsigned int
+seamless_send_zchange(RDPCLIENT * This, unsigned long id, unsigned long below, unsigned long flags)
+{
+       if (!This->seamless_rdp)
+               return (unsigned int) -1;
+
+       return seamless_send(This, "ZCHANGE", "0x%08lx,0x%08lx,0x%lx", id, below, flags);
+}
+
+
+
+unsigned int
+seamless_send_focus(RDPCLIENT * This, unsigned long id, unsigned long flags)
+{
+       if (!This->seamless_rdp)
+               return (unsigned int) -1;
+
+       return seamless_send(This, "FOCUS", "0x%08lx,0x%lx", id, flags);
+}