diff options
Diffstat (limited to 'Xserver/hw/rdp/rdpup.c')
-rw-r--r-- | Xserver/hw/rdp/rdpup.c | 806 |
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); + } +} |