summaryrefslogtreecommitdiffstats
path: root/Xserver/hw/rdp/rdpup.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xserver/hw/rdp/rdpup.c')
-rw-r--r--Xserver/hw/rdp/rdpup.c806
1 files changed, 806 insertions, 0 deletions
diff --git a/Xserver/hw/rdp/rdpup.c b/Xserver/hw/rdp/rdpup.c
new file mode 100644
index 00000000..01e8a05d
--- /dev/null
+++ b/Xserver/hw/rdp/rdpup.c
@@ -0,0 +1,806 @@
+/*
+Copyright 2005-2006 Jay Sorg
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include "rdp.h"
+/*#include "arch.h"*/
+/*#include "parse.h"*/
+/*#include "os_calls.h"*/
+
+#define DEBUG_OUT_UP(arg)
+/*#define DEBUG_OUT_UP(arg) ErrorF arg*/
+
+static int g_listen_sck = 0;
+static int g_sck = 0;
+static int g_sck_closed = 0;
+static int g_connected = 0;
+static int g_begin = 0;
+static struct stream* g_out_s = 0;
+static struct stream* g_in_s = 0;
+static int g_button_mask = 0;
+static int g_cursor_x = 0;
+static int g_cursor_y = 0;
+static OsTimerPtr g_timer = 0;
+static int g_scheduled = 0;
+static int g_count = 0;
+
+extern ScreenPtr g_pScreen; /* from rdpmain.c */
+extern int g_Bpp; /* from rdpmain.c */
+extern int g_Bpp_mask; /* from rdpmain.c */
+extern rdpScreenInfo g_rdpScreen; /* from rdpmain.c */
+
+extern char* display;
+
+static void
+rdpScheduleDeferredUpdate(void);
+
+/*
+0 GXclear, 0
+1 GXnor, DPon
+2 GXandInverted, DPna
+3 GXcopyInverted, Pn
+4 GXandReverse, PDna
+5 GXinvert, Dn
+6 GXxor, DPx
+7 GXnand, DPan
+8 GXand, DPa
+9 GXequiv, DPxn
+a GXnoop, D
+b GXorInverted, DPno
+c GXcopy, P
+d GXorReverse, PDno
+e GXor, DPo
+f GXset 1
+*/
+
+static int rdp_opcodes[16] =
+{
+ 0x00, /* GXclear 0x0 0 */
+ 0x88, /* GXand 0x1 src AND dst */
+ 0x44, /* GXandReverse 0x2 src AND NOT dst */
+ 0xcc, /* GXcopy 0x3 src */
+ 0x22, /* GXandInverted 0x4 NOT src AND dst */
+ 0xaa, /* GXnoop 0x5 dst */
+ 0x66, /* GXxor 0x6 src XOR dst */
+ 0xee, /* GXor 0x7 src OR dst */
+ 0x11, /* GXnor 0x8 NOT src AND NOT dst */
+ 0x99, /* GXequiv 0x9 NOT src XOR dst */
+ 0x55, /* GXinvert 0xa NOT dst */
+ 0xdd, /* GXorReverse 0xb src OR NOT dst */
+ 0x33, /* GXcopyInverted 0xc NOT src */
+ 0xbb, /* GXorInverted 0xd NOT src OR dst */
+ 0x77, /* GXnand 0xe NOT src OR NOT dst */
+ 0xff /* GXset 0xf 1 */
+};
+
+/******************************************************************************/
+/* returns error */
+static int
+rdpup_recv(char* data, int len)
+{
+ int rcvd;
+
+ if (g_sck_closed)
+ {
+ return 1;
+ }
+ while (len > 0)
+ {
+ rcvd = g_tcp_recv(g_sck, data, len, 0);
+ if (rcvd == -1)
+ {
+ if (g_tcp_last_error_would_block(g_sck))
+ {
+ g_sleep(1);
+ }
+ else
+ {
+ RemoveEnabledDevice(g_sck);
+ g_connected = 0;
+ g_tcp_close(g_sck);
+ g_sck = 0;
+ g_sck_closed = 1;
+ return 1;
+ }
+ }
+ else if (rcvd == 0)
+ {
+ RemoveEnabledDevice(g_sck);
+ g_connected = 0;
+ g_tcp_close(g_sck);
+ g_sck = 0;
+ g_sck_closed = 1;
+ return 1;
+ }
+ else
+ {
+ data += rcvd;
+ len -= rcvd;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* returns error */
+static int
+rdpup_send(char* data, int len)
+{
+ int sent;
+
+ DEBUG_OUT_UP(("rdpup_send - sending %d bytes\n", len));
+ if (g_sck_closed)
+ {
+ return 1;
+ }
+ while (len > 0)
+ {
+ sent = g_tcp_send(g_sck, data, len, 0);
+ if (sent == -1)
+ {
+ if (g_tcp_last_error_would_block(g_sck))
+ {
+ g_sleep(1);
+ }
+ else
+ {
+ RemoveEnabledDevice(g_sck);
+ g_connected = 0;
+ g_tcp_close(g_sck);
+ g_sck = 0;
+ g_sck_closed = 1;
+ return 1;
+ }
+ }
+ else if (sent == 0)
+ {
+ RemoveEnabledDevice(g_sck);
+ g_connected = 0;
+ g_tcp_close(g_sck);
+ g_sck = 0;
+ g_sck_closed = 1;
+ return 1;
+ }
+ else
+ {
+ data += sent;
+ len -= sent;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+static int
+rdpup_send_msg(struct stream* s)
+{
+ int len;
+ int rv;
+
+ rv = 1;
+ if (s != 0)
+ {
+ len = s->end - s->data;
+ if (len > s->size)
+ {
+ ErrorF("overrun error len %d count %d\n", len, g_count);
+ }
+ s_pop_layer(s, iso_hdr);
+ out_uint16_le(s, 1);
+ out_uint16_le(s, g_count);
+ out_uint32_le(s, len - 8);
+ rv = rdpup_send(s->data, len);
+ }
+ if (rv != 0)
+ {
+ ErrorF("error in rdpup_send_msg\n");
+ }
+ return rv;
+}
+
+/******************************************************************************/
+static int
+rdpup_recv_msg(struct stream* s)
+{
+ int len;
+ int rv;
+
+ rv = 1;
+ if (s != 0)
+ {
+ init_stream(s, 4);
+ rv = rdpup_recv(s->data, 4);
+ if (rv == 0)
+ {
+ in_uint32_le(s, len);
+ if (len > 3)
+ {
+ init_stream(s, len);
+ rv = rdpup_recv(s->data, len - 4);
+ }
+ }
+ }
+ if (rv != 0)
+ {
+ ErrorF("error in rdpup_recv_msg\n");
+ }
+ return rv;
+}
+
+/******************************************************************************/
+static int
+rdpup_process_msg(struct stream* s)
+{
+ int msg_type;
+ int msg;
+ int param1;
+ int param2;
+ int param3;
+ int param4;
+
+ in_uint16_le(s, msg_type);
+ if (msg_type == 103)
+ {
+ in_uint32_le(s, msg);
+ in_uint32_le(s, param1);
+ in_uint32_le(s, param2);
+ in_uint32_le(s, param3);
+ in_uint32_le(s, param4);
+ DEBUG_OUT_UP(("rdpup_process_msg - msg %d param1 %d param2 %d param3 %d \
+param4 %d\n", msg, param1, param2, param3, param4));
+ switch (msg)
+ {
+ case 15: /* key down */
+ case 16: /* key up */
+ KbdAddEvent(msg == 15, param1, param2, param3, param4);
+ break;
+ case 100:
+ g_cursor_x = param1;
+ g_cursor_y = param2;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 101:
+ g_button_mask = g_button_mask & (~1);
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 102:
+ g_button_mask = g_button_mask | 1;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 103:
+ g_button_mask = g_button_mask & (~4);
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 104:
+ g_button_mask = g_button_mask | 4;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 105:
+ g_button_mask = g_button_mask & (~2);
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 106:
+ g_button_mask = g_button_mask | 2;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 107:
+ g_button_mask = g_button_mask & (~8);
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 108:
+ g_button_mask = g_button_mask | 8;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 109:
+ g_button_mask = g_button_mask & (~16);
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 110:
+ g_button_mask = g_button_mask | 16;
+ PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y);
+ break;
+ case 200:
+ rdpup_begin_update();
+ rdpup_send_area(param1, param2, param3, param4);
+ rdpup_end_update();
+ break;
+ }
+ }
+ else
+ {
+ ErrorF("unknown message type in rdpup_process_msg\n");
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_init(void)
+{
+ char text[256];
+ int i;
+
+ i = atoi(display);
+ if (i < 1)
+ {
+ return 0;
+ }
+ g_sprintf(text, "62%2.2d", i);
+ if (g_in_s == 0)
+ {
+ make_stream(g_in_s);
+ init_stream(g_in_s, 8192);
+ }
+ if (g_out_s == 0)
+ {
+ make_stream(g_out_s);
+ init_stream(g_out_s, 8192 * g_Bpp + 100);
+ }
+ if (g_listen_sck == 0)
+ {
+ g_listen_sck = g_tcp_socket();
+ if (g_tcp_bind(g_listen_sck, text) != 0)
+ {
+ return 0;
+ }
+ g_tcp_listen(g_listen_sck);
+ AddEnabledDevice(g_listen_sck);
+ }
+ return 1;
+}
+
+/******************************************************************************/
+int
+rdpup_check(void)
+{
+ int sel;
+
+ sel = g_tcp_select(g_listen_sck, g_sck);
+ if (sel & 1)
+ {
+ if (g_sck == 0)
+ {
+ g_sck = g_tcp_accept(g_listen_sck);
+ if (g_sck == -1)
+ {
+ g_sck = 0;
+ }
+ else
+ {
+ g_tcp_set_non_blocking(g_sck);
+ g_tcp_set_no_delay(g_sck);
+ g_connected = 1;
+ g_sck_closed = 0;
+ AddEnabledDevice(g_sck);
+ }
+ }
+ else
+ {
+ ErrorF("rejecting connection - maybe\n");
+ /* g_tcp_close(g_tcp_accept(g_listen_sck));*/
+ }
+ }
+ if (sel & 2)
+ {
+ if (rdpup_recv_msg(g_in_s) == 0)
+ {
+ rdpup_process_msg(g_in_s);
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_begin_update(void)
+{
+ if (g_connected)
+ {
+ if (g_begin)
+ {
+ return 0;
+ }
+ init_stream(g_out_s, 0);
+ s_push_layer(g_out_s, iso_hdr, 8);
+ out_uint16_le(g_out_s, 1);
+ DEBUG_OUT_UP(("begin %d\n", g_count));
+ g_begin = 1;
+ g_count = 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_end_update(void)
+{
+ if (g_connected && g_begin)
+ {
+ rdpScheduleDeferredUpdate();
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_pre_check(int in_size)
+{
+ if (!g_begin)
+ {
+ rdpup_begin_update();
+ }
+ if ((g_out_s->p - g_out_s->data) > (g_out_s->size - (in_size + 20)))
+ {
+ /*ErrorF("%d %d\n", in_size, g_out_s->size);*/
+ s_mark_end(g_out_s);
+ rdpup_send_msg(g_out_s);
+ g_count = 0;
+ init_stream(g_out_s, 0);
+ s_push_layer(g_out_s, iso_hdr, 8);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_fill_rect(short x, short y, int cx, int cy)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_fill_rect\n"));
+ rdpup_pre_check(10);
+ out_uint16_le(g_out_s, 3);
+ g_count++;
+ out_uint16_le(g_out_s, x);
+ out_uint16_le(g_out_s, y);
+ out_uint16_le(g_out_s, cx);
+ out_uint16_le(g_out_s, cy);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_screen_blt(short x, short y, int cx, int cy, short srcx, short srcy)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_screen_blt\n"));
+ rdpup_pre_check(14);
+ out_uint16_le(g_out_s, 4);
+ g_count++;
+ out_uint16_le(g_out_s, x);
+ out_uint16_le(g_out_s, y);
+ out_uint16_le(g_out_s, cx);
+ out_uint16_le(g_out_s, cy);
+ out_uint16_le(g_out_s, srcx);
+ out_uint16_le(g_out_s, srcy);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_clip(short x, short y, int cx, int cy)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_clip\n"));
+ rdpup_pre_check(10);
+ out_uint16_le(g_out_s, 10);
+ g_count++;
+ out_uint16_le(g_out_s, x);
+ out_uint16_le(g_out_s, y);
+ out_uint16_le(g_out_s, cx);
+ out_uint16_le(g_out_s, cy);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_reset_clip(void)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_reset_clip\n"));
+ rdpup_pre_check(2);
+ out_uint16_le(g_out_s, 11);
+ g_count++;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_fgcolor(int fgcolor)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_fgcolor\n"));
+ rdpup_pre_check(6);
+ out_uint16_le(g_out_s, 12);
+ g_count++;
+ fgcolor = fgcolor & g_Bpp_mask;
+ out_uint32_le(g_out_s, fgcolor);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_bgcolor(int bgcolor)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_bgcolor\n"));
+ rdpup_pre_check(6);
+ out_uint16_le(g_out_s, 13);
+ g_count++;
+ bgcolor = bgcolor & g_Bpp_mask;
+ out_uint32_le(g_out_s, bgcolor);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_opcode(int opcode)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_opcode\n"));
+ rdpup_pre_check(4);
+ out_uint16_le(g_out_s, 14);
+ g_count++;
+ out_uint16_le(g_out_s, rdp_opcodes[opcode & 0xf]);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_pen(int style, int width)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_pen\n"));
+ rdpup_pre_check(6);
+ out_uint16_le(g_out_s, 17);
+ g_count++;
+ out_uint16_le(g_out_s, style);
+ out_uint16_le(g_out_s, width);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_draw_line(short x1, short y1, short x2, short y2)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_draw_line\n"));
+ rdpup_pre_check(10);
+ out_uint16_le(g_out_s, 18);
+ g_count++;
+ out_uint16_le(g_out_s, x1);
+ out_uint16_le(g_out_s, y1);
+ out_uint16_le(g_out_s, x2);
+ out_uint16_le(g_out_s, y2);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int
+rdpup_set_cursor(short x, short y, char* cur_data, char* cur_mask)
+{
+ if (g_connected)
+ {
+ DEBUG_OUT_UP((" rdpup_set_cursor\n"));
+ rdpup_pre_check(6 + 32 * (32 * 3) + 32 * (32 / 8));
+ out_uint16_le(g_out_s, 19);
+ g_count++;
+ out_uint16_le(g_out_s, x);
+ out_uint16_le(g_out_s, y);
+ out_uint8a(g_out_s, cur_data, 32 * (32 * 3));
+ out_uint8a(g_out_s, cur_mask, 32 * (32 / 8));
+ }
+ return 0;
+}
+
+/******************************************************************************/
+static int
+get_single_color(int x, int y, int w, int h)
+{
+ int rv;
+ int i;
+ int j;
+ int p;
+ unsigned char* i8;
+ unsigned short* i16;
+
+ rv = -1;
+ if (g_Bpp == 1)
+ {
+ for (i = 0; i < h; i++)
+ {
+ i8 = (unsigned char*)(g_rdpScreen.pfbMemory +
+ ((y + i) * g_rdpScreen.paddedWidthInBytes) + (x * g_Bpp));
+ if (i == 0)
+ {
+ p = *i8;
+ }
+ for (j = 0; j < w; j++)
+ {
+ if (i8[j] != p)
+ {
+ return -1;
+ }
+ }
+ }
+ rv = p;
+ }
+ else if (g_Bpp == 2)
+ {
+ for (i = 0; i < h; i++)
+ {
+ i16 = (unsigned short*)(g_rdpScreen.pfbMemory +
+ ((y + i) * g_rdpScreen.paddedWidthInBytes) + (x * g_Bpp));
+ if (i == 0)
+ {
+ p = *i16;
+ }
+ for (j = 0; j < w; j++)
+ {
+ if (i16[j] != p)
+ {
+ return -1;
+ }
+ }
+ }
+ rv = p;
+ }
+ return rv;
+}
+
+/******************************************************************************/
+/* split the bitmap up into 64 x 64 pixel areas */
+void
+rdpup_send_area(int x, int y, int w, int h)
+{
+ char* s;
+ int i;
+ int single_color;
+ int lx;
+ int ly;
+ int lh;
+ int lw;
+
+ if (x >= g_rdpScreen.width)
+ {
+ return;
+ }
+ if (y >= g_rdpScreen.height)
+ {
+ return;
+ }
+ if (x < 0)
+ {
+ w += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ h += y;
+ y = 0;
+ }
+ if (w <= 0)
+ {
+ return;
+ }
+ if (h <= 0)
+ {
+ return;
+ }
+ if (x + w > g_rdpScreen.width)
+ {
+ w = g_rdpScreen.width - x;
+ }
+ if (y + h > g_rdpScreen.height)
+ {
+ h = g_rdpScreen.height - y;
+ }
+ /*ErrorF("%d\n", w * h);*/
+ if (g_connected && g_begin)
+ {
+ DEBUG_OUT_UP((" rdpup_send_area\n"));
+ ly = y;
+ while (ly < y + h)
+ {
+ lx = x;
+ while (lx < x + w)
+ {
+ lw = MIN(64, (x + w) - lx);
+ lh = MIN(64, (y + h) - ly);
+ single_color = get_single_color(lx, ly, lw, lh);
+ if (single_color != -1)
+ {
+ /*ErrorF("%d sending single color\n", g_count);*/
+ rdpup_set_fgcolor(single_color);
+ rdpup_fill_rect(lx, ly, lw, lh);
+ }
+ else
+ {
+ rdpup_pre_check(lw * lh * g_Bpp + 42);
+ out_uint16_le(g_out_s, 5);
+ g_count++;
+ out_uint16_le(g_out_s, lx);
+ out_uint16_le(g_out_s, ly);
+ out_uint16_le(g_out_s, lw);
+ out_uint16_le(g_out_s, lh);
+ out_uint32_le(g_out_s, lw * lh * g_Bpp);
+ for (i = 0; i < lh; i++)
+ {
+ s = (g_rdpScreen.pfbMemory +
+ ((ly + i) * g_rdpScreen.paddedWidthInBytes) + (lx * g_Bpp));
+ out_uint8a(g_out_s, s, lw * g_Bpp);
+ }
+ out_uint16_le(g_out_s, lw);
+ out_uint16_le(g_out_s, lh);
+ out_uint16_le(g_out_s, 0);
+ out_uint16_le(g_out_s, 0);
+ }
+ lx += 64;
+ }
+ ly += 64;
+ }
+ }
+}
+
+/******************************************************************************/
+static CARD32
+rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+ if (g_connected && g_begin)
+ {
+ DEBUG_OUT_UP(("end %d\n", g_count));
+ out_uint16_le(g_out_s, 2);
+ g_count++;
+ s_mark_end(g_out_s);
+ rdpup_send_msg(g_out_s);
+ }
+ g_count = 0;
+ g_begin = 0;
+ g_scheduled = 0;
+ return 0;
+}
+
+/******************************************************************************/
+static void
+rdpScheduleDeferredUpdate(void)
+{
+ if (!g_scheduled)
+ {
+ g_scheduled = 1;
+ g_timer = TimerSet(g_timer, 0, 40, rdpDeferredUpdateCallback, 0);
+ }
+}